From: Rob Sayre Date: Tue, 5 Jul 2011 17:53:57 +0000 (-0700) Subject: Add Makefile. Move some files around to make building the website easier. X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=7f5c7a3130e1f888edefe04c7f4ddffb033f75ee;p=pdf.js.git Add Makefile. Move some files around to make building the website easier. --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..da18e5b --- /dev/null +++ b/Makefile @@ -0,0 +1,154 @@ +REPO = git@github.com:andreasgal/pdf.js.git +BUILD_DIR := build +DEFAULT_BROWSERS := test/resources/browser_manifests/browser_manifest.json +DEFAULT_TESTS := test/test_manifest.json + +# JS files needed for pdf.js. +# This list doesn't account for the 'worker' directory. +PDF_JS_FILES = \ + pdf.js \ + crypto.js \ + fonts.js \ + glyphlist.js \ + $(NULL) + +# not sure what to do for all yet +all: help + +test: shell-test browser-test + +# make browser-test +# +# This target runs in-browser tests using two primary arguments: a +# test manifest file, and a browser manifest file. Both are simple +# JSON formats, and examples can be found in the test/ directory. The +# target will inspect the environment for the PDF_TESTS and +# PDF_BROWSERS variables, and use those if found. Otherwise, the +# defaults at the top of this file are used. +ifeq ($(PDF_TESTS),) +PDF_TESTS := $(DEFAULT_TESTS) +endif +ifeq ($(PDF_BROWSERS),) +PDF_BROWSERS := $(DEFAULT_BROWSERS) +endif + + +browser-test: + @if [ ! "$(PDF_BROWSERS)" ]; then \ + echo "Browser manifest file $(PDF_BROWSERS) does not exist."; \ + echo "Try copying one of the examples" \ + "in test/resources/browser_manifests/"; \ + exit 1; \ + fi; + + cd test; \ + python test.py --reftest \ + --browserManifestFile=$(abspath $(PDF_BROWSERS)) \ + --manifestFile=$(abspath $(PDF_TESTS)) + +# make shell-test +# +# This target runs all of the tests that can be run in a JS shell. +# The shell used is taken from the JS_SHELL environment variable. If +# that veriable is not defined, the script will attempt to use the copy +# of Rhino that comes with the Closure compiler used for producing the +# website. +SHELL_TARGET = $(NULL) +ifeq ($(JS_SHELL),) +JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar" +JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main" +SHELL_TARGET = compiler +endif + +shell-test: shell-msg $(SHELL_TARGET) font-test +shell-msg: +ifeq ($(SHELL_TARGET), compiler) + @echo "No JS_SHELL env variable present." + @echo "The default is to find a copy of Rhino and try that." +endif + @echo "JS shell command is: $(JS_SHELL)" + +font-test: + @echo "font test stub." + +# make lint +# +# This target runs the Closure Linter on most of our JS files. +# To install gjslint, see: +# +# +SRC_DIRS := . utils worker web +GJSLINT_FILES = $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.js)) +lint: + gjslint $(GJSLINT_FILES) + +# make web +# +# This target produces the website for the project, by checking out +# the gh-pages branch underneath the build directory, and then move +# the various viewer files into place. +# +# TODO: Use the Closure compiler to optimize the pdf.js files. +# +GH_PAGES = $(BUILD_DIR)/gh-pages +web: | compiler pages-repo \ + $(addprefix $(GH_PAGES)/, $(PDF_JS_FILES)) \ + $(addprefix $(GH_PAGES)/, $(wildcard web/*.*)) \ + $(addprefix $(GH_PAGES)/, $(wildcard web/images/*.*)) + + @cp $(GH_PAGES)/web/index.html.template $(GH_PAGES)/index.html; + @cd $(GH_PAGES); git add -A; + @echo "Website built in $(GH_PAGES)" + +# make pages-repo +# +# This target clones the gh-pages repo into the build directory. It +# deletes the current contents of the repo, since we overwrite +# everything with data from the master repo. The 'make web' target +# then uses 'git add -A' to track additions, modifications, moves, +# and deletions. +pages-repo: | $(BUILD_DIR) + @if [ ! -d "$(GH_PAGES)" ]; then \ + git clone -b gh-pages $(REPO) $(GH_PAGES); \ + rm -rf $(GH_PAGES)/*; \ + fi; + @mkdir -p $(GH_PAGES)/web; + @mkdir -p $(GH_PAGES)/web/images; + +$(GH_PAGES)/%.js: %.js + @cp $< $@ + +$(GH_PAGES)/web/%: web/% + @cp $< $@ + +$(GH_PAGES)/web/images/%: web/images/% + @cp $< $@ + +# make compiler +# +# This target downloads the Closure compiler, and places it in the +# build directory. This target is also useful when the user doesn't +# have a JS shell available--we can have them use the Rhino shell that +# comes with Closure. +COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip + +compiler: $(BUILD_DIR)/compiler.zip +$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR) + curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip; + cd $(BUILD_DIR); unzip compiler.zip compiler.jar; + +# Make sure there's a build directory. +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +clean: + rm -rf $(BUILD_DIR) + +# make help +# +# This target just prints out a message to read these comments. :) +help: + @echo "Read the comments in the Makefile for guidance."; + +.PHONY: all test browser-test font-test shell-test \ + shell-msg lint clean web compiler help \ No newline at end of file diff --git a/compressed.tracemonkey-pldi-09.pdf b/compressed.tracemonkey-pldi-09.pdf deleted file mode 100644 index 6557018..0000000 Binary files a/compressed.tracemonkey-pldi-09.pdf and /dev/null differ diff --git a/images/buttons.png b/images/buttons.png deleted file mode 100644 index 3357b47..0000000 Binary files a/images/buttons.png and /dev/null differ diff --git a/images/source/Buttons.psd.zip b/images/source/Buttons.psd.zip deleted file mode 100644 index 528e6ee..0000000 Binary files a/images/source/Buttons.psd.zip and /dev/null differ diff --git a/images/source/FileButton.psd.zip b/images/source/FileButton.psd.zip deleted file mode 100644 index 1f2b51c..0000000 Binary files a/images/source/FileButton.psd.zip and /dev/null differ diff --git a/multi_page_viewer.css b/multi_page_viewer.css deleted file mode 100644 index 17b2537..0000000 --- a/multi_page_viewer.css +++ /dev/null @@ -1,230 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; -} - -canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; -} - -span { - font-size: 0.8em; -} - -.control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; -} - -.control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; -} - -.control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; -} - -.thumbnailPageNumber { - color: #fff; - font-size: 0.55em; - text-align: right; - margin: -6px 2px 6px 0px; - width: 102px; -} - -.thumbnail { - width: 104px; - height: 134px; - margin: 0px auto 10px; -} - -.page { - width: 816px; - height: 1056px; - margin: 10px auto; -} - -#controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; -} - -#previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; -} - -#previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; -} - -#nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; -} - -#nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; -} - -#openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; -} - -#openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; -} - -#openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; -} - -#fileInput { - display: none; -} - -#pageNumber { - text-align: right; -} - -#sidebar { - position: fixed; - width: 200px; - top: 62px; - bottom: 18px; - left: -140px; - transition: left 0.25s ease-in-out 1s; - -moz-transition: left 0.25s ease-in-out 1s; - -webkit-transition: left 0.25s ease-in-out 1s; -} - -#sidebar:hover { - left: 0px; - transition: left 0.25s ease-in-out 0s; - -moz-transition: left 0.25s ease-in-out 0s; - -webkit-transition: left 0.25s ease-in-out 0s; -} - -#sidebarBox { - background-color: rgba(0, 0, 0, 0.7); - width: 150px; - height: 100%; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 10px; - bottom: 10px; - left: 10px; - width: 130px; -} - -#sidebarContentView { - height: auto; - width: 100px; -} - -#viewer { - margin: 44px 0px 0px; - padding: 8px 0px; -} diff --git a/multi_page_viewer.html b/multi_page_viewer.html deleted file mode 100644 index df71d66..0000000 --- a/multi_page_viewer.html +++ /dev/null @@ -1,55 +0,0 @@ - - - -pdf.js Multi-Page Viewer - - - - - - - - - -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- - - - -
- - diff --git a/multi_page_viewer.js b/multi_page_viewer.js deleted file mode 100644 index 01d7b4f..0000000 --- a/multi_page_viewer.js +++ /dev/null @@ -1,534 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -"use strict"; - -var pageTimeout; - -var PDFViewer = { - queryParams: {}, - - element: null, - - sidebarContentView: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function(page) { - var pdfToCssUnitsCoef = 96.0 / 72.0; - var width = (page.mediaBox[2] - page.mediaBox[0]); - return width * PDFViewer.scale * pdfToCssUnitsCoef; - }, - - pageHeight: function(page) { - var pdfToCssUnitsCoef = 96.0 / 72.0; - var height = (page.mediaBox[3] - page.mediaBox[1]); - return height * PDFViewer.scale * pdfToCssUnitsCoef; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - const pageBottomMargin = 10; - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - - var pageHeight, page; - var i, n = PDFViewer.numberOfPages, currentHeight = pageBottomMargin; - for (i = 1; i <= n; i++) { - var page = PDFViewer.pdf.getPage(i); - pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; - if (currentHeight + pageHeight > windowTop) - break; - currentHeight += pageHeight; - } - - var pages = []; - for (; i <= n && currentHeight < windowBottom; i++) { - var page = PDFViewer.pdf.getPage(i); - pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; - currentHeight += pageHeight; - pages.push(i); - } - - return pages; - }, - - createThumbnail: function(num) { - if (PDFViewer.sidebarContentView) { - var anchor = document.createElement('a'); - anchor.href = '#' + num; - - var containerDiv = document.createElement('div'); - containerDiv.id = 'thumbnailContainer' + num; - containerDiv.className = 'thumbnail'; - - var pageNumberDiv = document.createElement('div'); - pageNumberDiv.className = 'thumbnailPageNumber'; - pageNumberDiv.innerHTML = '' + num; - - anchor.appendChild(containerDiv); - PDFViewer.sidebarContentView.appendChild(anchor); - PDFViewer.sidebarContentView.appendChild(pageNumberDiv); - } - }, - - removeThumbnail: function(num) { - var div = document.getElementById('thumbnailContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawThumbnail: function(num) { - if (!PDFViewer.pdf) - return; - - var div = document.getElementById('thumbnailContainer' + num); - - if (div && !div.hasChildNodes()) { - var page = PDFViewer.pdf.getPage(num); - var canvas = document.createElement('canvas'); - - canvas.id = 'thumbnail' + num; - canvas.mozOpaque = true; - - var pageWidth = PDFViewer.pageWidth(page); - var pageHeight = PDFViewer.pageHeight(page); - var thumbScale = Math.min(104 / pageWidth, 134 / pageHeight); - canvas.width = pageWidth * thumbScale; - canvas.height = pageHeight * thumbScale; - div.appendChild(canvas); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; - page.compile(gfx, fonts); - - FontLoader.bind(fonts, function() { page.display(gfx); }); - } - }, - - createPage: function(num) { - var page = PDFViewer.pdf.getPage(num); - - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth(page) + 'px'; - div.style.height = PDFViewer.pageHeight(page) + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) - return; - - var div = document.getElementById('pageContainer' + num); - - if (div && !div.hasChildNodes()) { - var page = PDFViewer.pdf.getPage(num); - var canvas = document.createElement('canvas'); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - canvas.width = PDFViewer.pageWidth(page); - canvas.height = PDFViewer.pageHeight(page); - div.appendChild(canvas); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; - page.compile(gfx, fonts); - - FontLoader.bind(fonts, function() { page.display(gfx); }); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - - // Clear the array of the last pages drawn to force a redraw. - PDFViewer.lastPagesDrawn = []; - - // Jump the scroll position to the correct page. - PDFViewer.goToPage(PDFViewer.pageNumber); - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - if (document.location.hash.substr(1) == PDFViewer.pageNumber) - // Force a "scroll event" to redraw - setTimeout(window.onscroll, 0); - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - if (this.thumbsLoadingInterval) { - // cancel thumbs loading operations - clearInterval(this.thumbsLoadingInterval); - this.thumbsLoadingInterval = null; - } - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - thumbsLoadingInterval: null, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - while (PDFViewer.sidebarContentView.hasChildNodes()) { - PDFViewer.sidebarContentView.removeChild(PDFViewer.sidebarContentView.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - - // slowly loading the thumbs (few per second) - // first time we are loading more images than subsequent - var currentPageIndex = 1, imagesToLoad = 15; - this.thumbsLoadingInterval = setInterval((function() { - while (imagesToLoad-- > 0) { - if (currentPageIndex > PDFViewer.numberOfPages) { - clearInterval(this.thumbsLoadingInterval); - this.thumbsLoadingInterval = null; - return; - } - PDFViewer.createThumbnail(currentPageIndex); - PDFViewer.drawThumbnail(currentPageIndex); - ++currentPageIndex; - } - imagesToLoad = 3; // next time loading less images - }).bind(this), 500); - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } -}; - -window.onload = function() { - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.sidebarContentView = document.getElementById('sidebarContentView'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; diff --git a/viewer.css b/viewer.css deleted file mode 100644 index 9987492..0000000 --- a/viewer.css +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -body { - margin: 6px; - padding: 0px; - background-color: #c0bdb7; -} - -#controls { - position:fixed; - left: 0px; - top: 0px; - width: 100%; - padding: 7px; - border-bottom: 1px solid black; - background-color: rgb(242, 240, 238); -} - -span#info { - float: right; - font: 14px sans-serif; - margin-right: 10px; -} - -#viewer { -} - -#canvas { - margin: auto; - display: block; -} - -#pageNumber { - text-align: right; -} diff --git a/viewer.html b/viewer.html deleted file mode 100644 index c600547..0000000 --- a/viewer.html +++ /dev/null @@ -1,32 +0,0 @@ - - - Simple pdf.js page viewer - - - - - - - - - - - -
- - - - - - -- - -
- -
- -
- - - diff --git a/viewer.js b/viewer.js deleted file mode 100644 index 6702a67..0000000 --- a/viewer.js +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -"use strict"; - -var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages; -function load(userInput) { - canvas = document.getElementById("canvas"); - canvas.mozOpaque = true; - pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1; - pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5; - var fileName = userInput; - if (!userInput) { - fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; - } - open(fileName); -} - -function queryParams() { - var qs = window.location.search.substring(1); - var kvs = qs.split("&"); - var params = { }; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split("="); - params[unescape(kv[0])] = unescape(kv[1]); - } - return params; -} - -function open(url) { - document.title = url; - var req = new XMLHttpRequest(); - req.open("GET", url); - req.mozResponseType = req.responseType = "arraybuffer"; - req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; - req.onreadystatechange = function() { - if (req.readyState == 4 && req.status == req.expected) { - var data = req.mozResponseArrayBuffer || req.mozResponse || - req.responseArrayBuffer || req.response; - pdfDocument = new PDFDoc(new Stream(data)); - numPages = pdfDocument.numPages; - document.getElementById("numPages").innerHTML = numPages.toString(); - goToPage(pageNum); - } - }; - req.send(null); -} - -function gotoPage(num) { - if (0 <= num && num <= numPages) - pageNum = num; - displayPage(pageNum); -} - -function displayPage(num) { - document.getElementById("pageNumber").value = num; - - var t0 = Date.now(); - - var page = pdfDocument.getPage(pageNum = num); - - var pdfToCssUnitsCoef = 96.0 / 72.0; - var pageWidth = (page.mediaBox[2] - page.mediaBox[0]); - var pageHeight = (page.mediaBox[3] - page.mediaBox[1]); - canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef; - canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef; - - var t1 = Date.now(); - var ctx = canvas.getContext("2d"); - ctx.save(); - ctx.fillStyle = "rgb(255, 255, 255)"; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; - page.compile(gfx, fonts); - var t2 = Date.now(); - - function displayPage() { - var t3 = Date.now(); - - page.display(gfx); - - var t4 = Date.now(); - - var infoDisplay = document.getElementById("info"); - infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; - } - - // Always defer call to displayPage() to work around bug in - // Firefox error reporting from XHR callbacks. - FontLoader.bind(fonts, function () { setTimeout(displayPage, 0); }); -} - -function nextPage() { - if (pageNum < pdfDocument.numPages) - displayPage(++pageNum); -} - -function prevPage() { - if (pageNum > 1) - displayPage(--pageNum); -} - -function goToPage(num) { - if (0 <= num && num <= numPages) - displayPage(pageNum = num); -} - diff --git a/viewer_worker.html b/viewer_worker.html deleted file mode 100644 index 89fb8a0..0000000 --- a/viewer_worker.html +++ /dev/null @@ -1,46 +0,0 @@ - - - Simple pdf.js page worker viewer - - - - - - - - -
- - - - - - -- - -
- -
- -
- - - diff --git a/web/compressed.tracemonkey-pldi-09.pdf b/web/compressed.tracemonkey-pldi-09.pdf new file mode 100644 index 0000000..6557018 Binary files /dev/null and b/web/compressed.tracemonkey-pldi-09.pdf differ diff --git a/web/images/buttons.png b/web/images/buttons.png new file mode 100644 index 0000000..3357b47 Binary files /dev/null and b/web/images/buttons.png differ diff --git a/web/images/source/Buttons.psd.zip b/web/images/source/Buttons.psd.zip new file mode 100644 index 0000000..528e6ee Binary files /dev/null and b/web/images/source/Buttons.psd.zip differ diff --git a/web/images/source/FileButton.psd.zip b/web/images/source/FileButton.psd.zip new file mode 100644 index 0000000..1f2b51c Binary files /dev/null and b/web/images/source/FileButton.psd.zip differ diff --git a/web/index.html.template b/web/index.html.template new file mode 100644 index 0000000..c3086f0 --- /dev/null +++ b/web/index.html.template @@ -0,0 +1,88 @@ + + + + + + andreasgal/pdf.js @ GitHub + + + + + + Fork me on GitHub + +
+ +
+ + + + +
+ +

pdf.js + by andreasgal

+ +
+ PDF Reader in JavaScript +
+ +

Try it out!

+

Live demo lives here.

+ +

Authors

+

Vivien Nicolas (21@vingtetun.org) +
Andreas Gal (andreas.gal@gmail.com) +
Soumya Deb (debloper@gmail.com) +
Chris Jones (jones.chris.g@gmail.com) +
Justin D'Arcangelo (justindarc@gmail.com) +
sbarman (sbarman@eecs.berkeley.edu) +
+

+

Contact

+

(andreas.gal@gmail.com) +

+ + +

Download

+

+ You can download this project in either + zip or + tar formats. +

+

You can also clone the project with Git + by running: +

$ git clone git://github.com/andreasgal/pdf.js
+

+ + + +
+ + + + diff --git a/web/multi_page_viewer.css b/web/multi_page_viewer.css new file mode 100644 index 0000000..17b2537 --- /dev/null +++ b/web/multi_page_viewer.css @@ -0,0 +1,230 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +body { + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.control { + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > select { + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > span { + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; +} + +.thumbnailPageNumber { + color: #fff; + font-size: 0.55em; + text-align: right; + margin: -6px 2px 6px 0px; + width: 102px; +} + +.thumbnail { + width: 104px; + height: 134px; + margin: 0px auto 10px; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + +#pageNumber { + text-align: right; +} + +#sidebar { + position: fixed; + width: 200px; + top: 62px; + bottom: 18px; + left: -140px; + transition: left 0.25s ease-in-out 1s; + -moz-transition: left 0.25s ease-in-out 1s; + -webkit-transition: left 0.25s ease-in-out 1s; +} + +#sidebar:hover { + left: 0px; + transition: left 0.25s ease-in-out 0s; + -moz-transition: left 0.25s ease-in-out 0s; + -webkit-transition: left 0.25s ease-in-out 0s; +} + +#sidebarBox { + background-color: rgba(0, 0, 0, 0.7); + width: 150px; + height: 100%; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 10px; + bottom: 10px; + left: 10px; + width: 130px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} diff --git a/web/multi_page_viewer.html b/web/multi_page_viewer.html new file mode 100644 index 0000000..df71d66 --- /dev/null +++ b/web/multi_page_viewer.html @@ -0,0 +1,55 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + + + +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ + + + +
+ + diff --git a/web/multi_page_viewer.js b/web/multi_page_viewer.js new file mode 100644 index 0000000..01d7b4f --- /dev/null +++ b/web/multi_page_viewer.js @@ -0,0 +1,534 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + +var pageTimeout; + +var PDFViewer = { + queryParams: {}, + + element: null, + + sidebarContentView: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, + + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function(page) { + var pdfToCssUnitsCoef = 96.0 / 72.0; + var width = (page.mediaBox[2] - page.mediaBox[0]); + return width * PDFViewer.scale * pdfToCssUnitsCoef; + }, + + pageHeight: function(page) { + var pdfToCssUnitsCoef = 96.0 / 72.0; + var height = (page.mediaBox[3] - page.mediaBox[1]); + return height * PDFViewer.scale * pdfToCssUnitsCoef; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + const pageBottomMargin = 10; + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + + var pageHeight, page; + var i, n = PDFViewer.numberOfPages, currentHeight = pageBottomMargin; + for (i = 1; i <= n; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + if (currentHeight + pageHeight > windowTop) + break; + currentHeight += pageHeight; + } + + var pages = []; + for (; i <= n && currentHeight < windowBottom; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + currentHeight += pageHeight; + pages.push(i); + } + + return pages; + }, + + createThumbnail: function(num) { + if (PDFViewer.sidebarContentView) { + var anchor = document.createElement('a'); + anchor.href = '#' + num; + + var containerDiv = document.createElement('div'); + containerDiv.id = 'thumbnailContainer' + num; + containerDiv.className = 'thumbnail'; + + var pageNumberDiv = document.createElement('div'); + pageNumberDiv.className = 'thumbnailPageNumber'; + pageNumberDiv.innerHTML = '' + num; + + anchor.appendChild(containerDiv); + PDFViewer.sidebarContentView.appendChild(anchor); + PDFViewer.sidebarContentView.appendChild(pageNumberDiv); + } + }, + + removeThumbnail: function(num) { + var div = document.getElementById('thumbnailContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawThumbnail: function(num) { + if (!PDFViewer.pdf) + return; + + var div = document.getElementById('thumbnailContainer' + num); + + if (div && !div.hasChildNodes()) { + var page = PDFViewer.pdf.getPage(num); + var canvas = document.createElement('canvas'); + + canvas.id = 'thumbnail' + num; + canvas.mozOpaque = true; + + var pageWidth = PDFViewer.pageWidth(page); + var pageHeight = PDFViewer.pageHeight(page); + var thumbScale = Math.min(104 / pageWidth, 134 / pageHeight); + canvas.width = pageWidth * thumbScale; + canvas.height = pageHeight * thumbScale; + div.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + + FontLoader.bind(fonts, function() { page.display(gfx); }); + } + }, + + createPage: function(num) { + var page = PDFViewer.pdf.getPage(num); + + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth(page) + 'px'; + div.style.height = PDFViewer.pageHeight(page) + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) + return; + + var div = document.getElementById('pageContainer' + num); + + if (div && !div.hasChildNodes()) { + var page = PDFViewer.pdf.getPage(num); + var canvas = document.createElement('canvas'); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + canvas.width = PDFViewer.pageWidth(page); + canvas.height = PDFViewer.pageHeight(page); + div.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + + FontLoader.bind(fonts, function() { page.display(gfx); }); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + + // Clear the array of the last pages drawn to force a redraw. + PDFViewer.lastPagesDrawn = []; + + // Jump the scroll position to the correct page. + PDFViewer.goToPage(PDFViewer.pageNumber); + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + if (document.location.hash.substr(1) == PDFViewer.pageNumber) + // Force a "scroll event" to redraw + setTimeout(window.onscroll, 0); + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + if (this.thumbsLoadingInterval) { + // cancel thumbs loading operations + clearInterval(this.thumbsLoadingInterval); + this.thumbsLoadingInterval = null; + } + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + thumbsLoadingInterval: null, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + while (PDFViewer.sidebarContentView.hasChildNodes()) { + PDFViewer.sidebarContentView.removeChild(PDFViewer.sidebarContentView.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + + // slowly loading the thumbs (few per second) + // first time we are loading more images than subsequent + var currentPageIndex = 1, imagesToLoad = 15; + this.thumbsLoadingInterval = setInterval((function() { + while (imagesToLoad-- > 0) { + if (currentPageIndex > PDFViewer.numberOfPages) { + clearInterval(this.thumbsLoadingInterval); + this.thumbsLoadingInterval = null; + return; + } + PDFViewer.createThumbnail(currentPageIndex); + PDFViewer.drawThumbnail(currentPageIndex); + ++currentPageIndex; + } + imagesToLoad = 3; // next time loading less images + }).bind(this), 500); + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } +}; + +window.onload = function() { + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.sidebarContentView = document.getElementById('sidebarContentView'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; +}; diff --git a/web/viewer.css b/web/viewer.css new file mode 100644 index 0000000..9987492 --- /dev/null +++ b/web/viewer.css @@ -0,0 +1,36 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + margin: 6px; + padding: 0px; + background-color: #c0bdb7; +} + +#controls { + position:fixed; + left: 0px; + top: 0px; + width: 100%; + padding: 7px; + border-bottom: 1px solid black; + background-color: rgb(242, 240, 238); +} + +span#info { + float: right; + font: 14px sans-serif; + margin-right: 10px; +} + +#viewer { +} + +#canvas { + margin: auto; + display: block; +} + +#pageNumber { + text-align: right; +} diff --git a/web/viewer.html b/web/viewer.html new file mode 100644 index 0000000..c600547 --- /dev/null +++ b/web/viewer.html @@ -0,0 +1,32 @@ + + + Simple pdf.js page viewer + + + + + + + + + + + +
+ + + + + + -- + +
+ +
+ +
+ + + diff --git a/web/viewer.js b/web/viewer.js new file mode 100644 index 0000000..6702a67 --- /dev/null +++ b/web/viewer.js @@ -0,0 +1,113 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +"use strict"; + +var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages; +function load(userInput) { + canvas = document.getElementById("canvas"); + canvas.mozOpaque = true; + pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1; + pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5; + var fileName = userInput; + if (!userInput) { + fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; + } + open(fileName); +} + +function queryParams() { + var qs = window.location.search.substring(1); + var kvs = qs.split("&"); + var params = { }; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split("="); + params[unescape(kv[0])] = unescape(kv[1]); + } + return params; +} + +function open(url) { + document.title = url; + var req = new XMLHttpRequest(); + req.open("GET", url); + req.mozResponseType = req.responseType = "arraybuffer"; + req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState == 4 && req.status == req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || + req.responseArrayBuffer || req.response; + pdfDocument = new PDFDoc(new Stream(data)); + numPages = pdfDocument.numPages; + document.getElementById("numPages").innerHTML = numPages.toString(); + goToPage(pageNum); + } + }; + req.send(null); +} + +function gotoPage(num) { + if (0 <= num && num <= numPages) + pageNum = num; + displayPage(pageNum); +} + +function displayPage(num) { + document.getElementById("pageNumber").value = num; + + var t0 = Date.now(); + + var page = pdfDocument.getPage(pageNum = num); + + var pdfToCssUnitsCoef = 96.0 / 72.0; + var pageWidth = (page.mediaBox[2] - page.mediaBox[0]); + var pageHeight = (page.mediaBox[3] - page.mediaBox[1]); + canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef; + canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef; + + var t1 = Date.now(); + var ctx = canvas.getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + var t2 = Date.now(); + + function displayPage() { + var t3 = Date.now(); + + page.display(gfx); + + var t4 = Date.now(); + + var infoDisplay = document.getElementById("info"); + infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; + } + + // Always defer call to displayPage() to work around bug in + // Firefox error reporting from XHR callbacks. + FontLoader.bind(fonts, function () { setTimeout(displayPage, 0); }); +} + +function nextPage() { + if (pageNum < pdfDocument.numPages) + displayPage(++pageNum); +} + +function prevPage() { + if (pageNum > 1) + displayPage(--pageNum); +} + +function goToPage(num) { + if (0 <= num && num <= numPages) + displayPage(pageNum = num); +} + diff --git a/web/viewer_worker.html b/web/viewer_worker.html new file mode 100644 index 0000000..89fb8a0 --- /dev/null +++ b/web/viewer_worker.html @@ -0,0 +1,46 @@ + + + Simple pdf.js page worker viewer + + + + + + + + +
+ + + + + + -- + +
+ +
+ +
+ + +