Compare commits

..

No commits in common. "master" and "v2.10.377" have entirely different histories.

1382 changed files with 106528 additions and 224224 deletions

View File

@ -1,6 +1,6 @@
root = true root = true
[*.{js,jsm,mjs,json,html,css,pdf.link}] [*.{js,jsm,html,css}]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 2 indent_size = 2
@ -9,12 +9,9 @@ insert_final_newline = true
max_line_length = 80 max_line_length = 80
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.{json,pdf.link}]
max_line_length = off
[*.md] [*.md]
max_line_length = off max_line_length = 0
trim_trailing_whitespace = false trim_trailing_whitespace = false
[COMMIT_EDITMSG] [COMMIT_EDITMSG]
max_line_length = off max_line_length = 0

15
.eslintignore Normal file
View File

@ -0,0 +1,15 @@
build/
l10n/
docs/
node_modules/
external/bcmaps/
external/webL10n/
external/builder/fixtures/
external/builder/fixtures_esprima/
external/quickjs/
src/shared/cffStandardStrings.js
src/shared/fonts_utils.js
test/tmp/
test/pdfs/
test/resources/
*~/

222
.eslintrc Normal file
View File

@ -0,0 +1,222 @@
{
"parserOptions": {
"ecmaVersion": 2021,
"sourceType": "module",
},
"plugins": [
"import",
"json",
"mozilla",
"no-unsanitized",
"sort-exports",
"unicorn",
],
"extends": [
"plugin:json/recommended",
"plugin:prettier/recommended"
],
"env": {
"browser": true,
"es2021": true,
"worker": true,
"amd": true,
},
"globals": {
"PDFJSDev": false,
"exports": false,
"SystemJS": false,
},
"rules": {
// Plugins
"import/extensions": ["error", "always", { "ignorePackages": true, }],
"import/no-unresolved": ["error", {
"ignore": ["pdfjs", "pdfjs-lib", "pdfjs-web"]
}],
"mozilla/avoid-removeChild": "error",
"mozilla/use-includes-instead-of-indexOf": "error",
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
"sort-exports/sort-exports": ["error", {
"ignoreCase": true,
}],
"unicorn/no-abusive-eslint-disable": "error",
"unicorn/no-array-push-push": "error",
"unicorn/no-instanceof-array": "error",
"unicorn/prefer-string-starts-ends-with": "error",
// Possible errors
"for-direction": "error",
"getter-return": "error",
"no-async-promise-executor": "error",
"no-cond-assign": ["error", "except-parens"],
"no-constant-condition": ["error", { "checkLoops": false, }],
"no-debugger": "error",
"no-dupe-args": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": ["error", { "allowEmptyCatch": true, }],
"no-empty-character-class": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-func-assign": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-obj-calls": "error",
"no-promise-executor-return": "error",
"no-regex-spaces": "error",
"no-setter-return": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": ["error", { "disallowArithmeticOperators": true }],
"use-isnan": ["error", { "enforceForIndexOf": true, }],
"valid-typeof": ["error", { "requireStringLiterals": true, }],
// Best Practices
"accessor-pairs": ["error", {
"setWithoutGet": true,
"enforceForClassMembers": true,
}],
"consistent-return": "error",
"curly": ["error", "all"],
"default-case-last": "error",
"dot-notation": "error",
"eqeqeq": ["error", "always"],
"grouped-accessor-pairs": ["error", "getBeforeSet"],
"no-alert": "error",
"no-caller": "error",
"no-else-return": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-lone-blocks": "error",
"no-multi-str": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-new": "error",
"no-octal-escape": "error",
"no-octal": "error",
"no-redeclare": "error",
"no-return-await": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-throw-literal": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-concat": "error",
"no-useless-escape": "error",
"no-useless-return": "error",
"prefer-promise-reject-errors": "error",
"wrap-iife": ["error", "any"],
"yoda": ["error", "never", {
"exceptRange": true,
}],
// Strict Mode
"strict": ["off", "global"],
// Variables
"no-catch-shadow": "error",
"no-delete-var": "error",
"no-label-var": "error",
"no-shadow": "error",
"no-shadow-restricted-names": "error",
"no-undef-init": "error",
"no-undef": ["error", { "typeof": true, }],
"no-unused-vars": ["error", {
"vars": "local",
"args": "none",
}],
"no-use-before-define": ["error", {
"functions": false,
"classes": false,
"variables": false,
}],
// Node.js and CommonJS
"no-buffer-constructor": "error",
// Stylistic Issues
"lines-between-class-members": ["error", "always"],
"max-len": ["error", {
"code": 1000,
"comments": 80,
"ignoreUrls": true
}],
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
"no-array-constructor": "error",
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0, "maxBOF": 1, }],
"no-nested-ternary": "error",
"no-new-object": "error",
"no-restricted-syntax": ["error",
{
"selector": "BinaryExpression[operator='instanceof'][right.name='Object']",
"message": "Use `typeof` rather than `instanceof Object`.",
},
{
"selector": "CallExpression[callee.name='assert'][arguments.length!=2]",
"message": "`assert()` must always be invoked with two arguments.",
},
{
"selector": "NewExpression[callee.name='Cmd']",
"message": "Use `Cmd.get()` rather than `new Cmd()`.",
},
{
"selector": "NewExpression[callee.name='Name']",
"message": "Use `Name.get()` rather than `new Name()`.",
},
{
"selector": "NewExpression[callee.name='Ref']",
"message": "Use `Ref.get()` rather than `new Ref()`.",
},
],
"no-unneeded-ternary": "error",
"operator-assignment": "error",
"prefer-exponentiation-operator": "error",
"spaced-comment": ["error", "always", {
"block": {
"balanced": true,
}
}],
// ECMAScript 6
"constructor-super": "error",
"no-class-assign": "error",
"no-confusing-arrow": "error",
"no-const-assign": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"no-this-before-super": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-var": "error",
"object-shorthand": ["error", "always", {
"avoidQuotes": true,
}],
"prefer-const": "error",
"sort-imports": ["error", {
"ignoreCase": true,
}],
"template-curly-spacing": ["error", "never"],
},
}

View File

@ -1,6 +0,0 @@
# Auto-format `.js` files with ESLint/Prettier
de36b2aabab2b7fd647d9591f959c4540129541d
# Auto-format `.css` files with Stylelint/Prettier
8aa2718d225ad701a5b8a2788b42d221f1e4327d
# Auto-format `.json` files with Prettier
29de9bdce6c9785574994fda0e51533d796a9bb4

2
.gitattributes vendored
View File

@ -4,7 +4,7 @@
*.css text eol=lf *.css text eol=lf
*.html text eol=lf *.html text eol=lf
*.md text eol=lf *.md text eol=lf
*.ftl text eol=lf *.properties text eol=lf
*.yml text eol=lf *.yml text eol=lf
*.json text eol=lf *.json text eol=lf
*.config text eol=lf *.config text eol=lf

1
.github/CODEOWNERS vendored
View File

@ -1 +0,0 @@
l10n/en-US/*.ftl @mozilla/pdfjs-l10n

17
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,17 @@
Attach (recommended) or Link to PDF file here:
Configuration:
- Web browser and its version:
- Operating system and its version:
- PDF.js version:
- Is a browser extension:
Steps to reproduce the problem:
1.
2.
What is the expected behavior? (add screenshot)
What went wrong? (add screenshot)
Link to a viewer (if hosted on a site other than mozilla.github.io/pdf.js or as Firefox/Chrome extension):

View File

@ -1,81 +0,0 @@
name: Bug Report
description: Report a bug in PDF.js
title: "[Bug]: "
body:
- type: textarea
attributes:
label: Attach (recommended) or Link to PDF file
description: Without this information the issue may be closed without comment
placeholder: Please place only the PDF file in this field
validations:
required: true
- type: markdown
attributes: { value: "---" }
- type: input
attributes:
label: Web browser and its version
description: Please ensure that it's supported, refer to [the FAQ](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support)
validations:
required: true
- type: input
attributes:
label: Operating system and its version
validations:
required: true
- type: input
attributes:
label: PDF.js version
description: Please find official releases [here](https://github.com/mozilla/pdf.js/releases)
validations:
required: true
- type: dropdown
attributes:
label: Is the bug present in the latest PDF.js version?
description: Please check the [online demo](https://github.com/mozilla/pdf.js#online-demo)
options: ["Yes", "No"]
default: 0
validations:
required: true
- type: dropdown
attributes:
label: Is a browser extension
options: ["Yes", "No"]
default: 1
validations:
required: true
- type: markdown
attributes: { value: "---" }
- type: textarea
attributes:
label: Steps to reproduce the problem
placeholder: "1.\n2."
validations:
required: true
- type: textarea
attributes:
label: What is the expected behavior?
description: Also add a screenshot
validations:
required: true
- type: textarea
attributes:
label: What went wrong?
description: Also add a screenshot
validations:
required: true
- type: input
attributes:
label: Link to a viewer
description: Needed if hosted on a site other than mozilla.github.io/pdf.js or as Firefox/Chrome extension
- type: textarea
attributes:
label: Additional context
description: Do you have anything to add that doesn't fit in the issue template?

View File

@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Need help?
url: https://github.com/mozilla/pdf.js/discussions
about: If you need help on how to use PDF.js, please open a discussion where other community members can reply

View File

@ -1,23 +0,0 @@
name: Feature request
description: Propose a new feature or enhancement for PDF.js
title: "[Feature]: "
body:
- type: dropdown
attributes:
label: Is the feature relevant to the Firefox PDF Viewer?
options: ["Yes", "No"]
default: 1
validations:
required: true
- type: textarea
attributes:
label: Feature description
description: What new feature would you like PDF.js to have? Why would it be useful? What are the current workarounds?
validations:
required: true
- type: textarea
attributes:
label: Other PDF viewers
description: Do other PDF viewers implement similar functionality? Add descriptions, links, and/or screenshots.

13
.github/SECURITY.md vendored
View File

@ -1,13 +0,0 @@
# Security policy
Mozilla takes the security of our software seriously. If you believe you have found a security vulnerability in PDF.js, please report it to us as described below.
## Reporting security vulnerabilities
**Please don't report security vulnerabilities through public GitHub issues.**
Instead, please report security vulnerabilities in [Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=PDF%20Viewer&groups=firefox-core-security) and make sure that the checkbox in the "Security" section is checked so the required access controls are automatically configured:
![Security checkbox](https://github.com/mozilla/pdf.js/blob/master/.github/security.png)
The Mozilla security team will process the bug as described in [Mozilla's security bugs policy](https://www.mozilla.org/en-US/about/governance/policies/security-group/bugs).

View File

@ -1,8 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"

View File

@ -1,29 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# See https://github.com/mozilla-l10n/moz-fluent-linter/blob/main/src/fluent_linter/config.yml
# for details
---
ID01:
enabled: true
exclusions:
messages: []
files: []
ID02:
enabled: true
min_length: 9
exclusions:
messages: []
files: []
CO01:
enabled: true
brands:
- Firefox
- Mozilla
exclusions:
files: []
messages: []
VC:
disabled: false

View File

@ -1 +0,0 @@
moz-fluent-linter==0.4.*

BIN
.github/security.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,34 +1,14 @@
name: CI name: CI
on: [push, pull_request] on: [push, pull_request]
permissions:
contents: read
jobs: jobs:
test: build:
name: Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20, 22, 24]
steps: steps:
- name: Checkout repository - uses: actions/checkout@v2
uses: actions/checkout@v6 - name: Use Node.js 14 LTS
uses: actions/setup-node@v1
with: with:
fetch-depth: 0 node-version: 14.x
- run: npm install -g gulp-cli
- name: Use Node.js ${{ matrix.node-version }} - run: npm install
uses: actions/setup-node@v6 - run: npm test
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run external tests
run: npx gulp externaltest
- name: Run CLI unit tests
run: npx gulp unittestcli

View File

@ -1,35 +0,0 @@
name: CodeQL
on: [push, pull_request]
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
language: [javascript]
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
queries: security-and-quality
- name: Autobuild CodeQL
uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v4

View File

@ -1,42 +0,0 @@
name: Lint Fluent Reference Files
on:
push:
paths:
- 'l10n/en-US/**.ftl'
- '.github/fluent_linter_config.yml'
- '.github/workflows/fluent_linter.yml'
branches:
- master
pull_request:
paths:
- 'l10n/en-US/**.ftl'
- '.github/fluent_linter_config.yml'
- '.github/workflows/fluent_linter.yml'
branches:
- master
workflow_dispatch:
permissions:
contents: read
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Use Python 3.14
uses: actions/setup-python@v6
with:
python-version: '3.14'
cache: 'pip'
- name: Install Fluent dependencies
run: |
pip install -r .github/requirements.txt
- name: Lint Fluent reference files
run: |
moz-fluent-lint ./l10n/en-US --config .github/fluent_linter_config.yml

View File

@ -1,61 +0,0 @@
name: Font tests
on:
push:
paths:
- 'gulpfile.mjs'
- 'src/**'
- 'test/test.mjs'
- 'test/font/**'
- '.github/workflows/font_tests.yml'
branches:
- master
pull_request:
paths:
- 'gulpfile.mjs'
- 'src/**'
- 'test/test.mjs'
- 'test/font/**'
- '.github/workflows/font_tests.yml'
branches:
- master
workflow_dispatch:
permissions:
contents: read
jobs:
test:
name: Test
strategy:
fail-fast: false
matrix:
node-version: [lts/*]
os: [windows-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Use Python 3.14
uses: actions/setup-python@v6
with:
python-version: '3.14'
cache: 'pip'
- name: Install Fonttools
run: pip install fonttools
- name: Run font tests
run: npx gulp fonttest --headless

View File

@ -1,34 +0,0 @@
name: Lint
on: [push, pull_request]
permissions:
contents: read
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [lts/*]
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run lint
run: npx gulp lint
- name: Run lint-chromium
run: npx gulp lint-chromium

View File

@ -1,37 +0,0 @@
name: Publish release
on:
release:
types: [published]
permissions:
contents: read
id-token: write
jobs:
publish:
name: Publish
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [lts/*]
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build the `pdfjs-dist` library
run: npx gulp dist
- name: Publish the `pdfjs-dist` library to NPM
run: npm publish ./build/dist

View File

@ -1,69 +0,0 @@
name: Publish website
on:
push:
branches:
- master
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [lts/*]
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Build the website
run: npx gulp web
- name: Archive the website
shell: sh
run: |
chmod -c -R +rX "$INPUT_PATH" | while read line; do
echo "::warning title=Invalid file permissions automatically fixed::$line"
done
tar \
--dereference --hard-dereference \
--directory "$INPUT_PATH" \
-cvf "$RUNNER_TEMP/website.tar" \
--exclude=.git \
--exclude=.github \
.
env:
INPUT_PATH: build/gh-pages
- name: Upload the website
uses: actions/upload-artifact@v5
with:
name: github-pages
path: ${{ runner.temp }}/website.tar
retention-days: 1
if-no-files-found: error
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build
permissions:
pages: write # Required to deploy to GitHub Pages.
id-token: write # Required to verify that the deployment originates from this workflow.
steps:
- name: Deploy the website
uses: actions/deploy-pages@v4

View File

@ -1,31 +0,0 @@
name: Types tests
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [lts/*]
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run types tests
run: npx gulp typestest

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "test/ttx/fonttools-code"]
path = test/ttx/fonttools-code
url = https://github.com/behdad/fonttools.git

7
.gitpod.Dockerfile vendored Normal file
View File

@ -0,0 +1,7 @@
FROM gitpod/workspace-full-vnc
USER gitpod
RUN sudo apt-get update && \
sudo apt-get install -yq firefox && \
sudo rm -rf /var/lib/apt/lists/*

13
.gitpod.yml Normal file
View File

@ -0,0 +1,13 @@
image:
file: .gitpod.Dockerfile
tasks:
- command: |
gp await-port 8888 && gp preview $(gp url 8888)/web/viewer.html && echo '[{"name": "Firefox","path": "/usr/bin/firefox"}]' | jq '.' > test/resources/browser_manifests/browser_manifest.json
- init: npm install -g gulp-cli && npm install
command: gulp server
ports:
- port: 8888
onOpen: ignore
- port: 6080
onOpen: ignore

View File

@ -1,15 +0,0 @@
build/
l10n/
docs/
node_modules/
external/bcmaps/
external/builder/fixtures/
external/builder/fixtures_babel/
external/openjpeg/
external/qcms/
external/quickjs/
test/stats/results/
test/tmp/
test/pdfs/
web/locale/
*~/

View File

@ -5,21 +5,5 @@
"semi": true, "semi": true,
"tabWidth": 2, "tabWidth": 2,
"trailingComma": "es5", "trailingComma": "es5",
"useTabs": false, "useTabs": false
"overrides": [
{
"files": ["tsconfig.json", ".prettierrc"],
"options": {
"parser": "json"
}
},
{
"files": ["**/*.html"],
"options": {
"parser": "html",
"printWidth": 160
}
}
]
} }

View File

@ -1,9 +0,0 @@
{
"chrome": {
"skipDownload": false
},
"firefox": {
"skipDownload": false,
"version": "nightly"
}
}

View File

@ -3,11 +3,15 @@ l10n/
docs/ docs/
node_modules/ node_modules/
external/bcmaps/ external/bcmaps/
external/webL10n/
external/cmapscompress/
external/builder/fixtures/ external/builder/fixtures/
external/builder/fixtures_babel/ external/builder/fixtures_esprima/
external/quickjs/ src/shared/cffStandardStrings.js
test/stats/results/ src/shared/fonts_utils.js
test/tmp/ test/tmp/
test/features/
test/pdfs/ test/pdfs/
web/locale/ test/resources/
test/font/*_spec.js
*~/ *~/

View File

@ -3,23 +3,16 @@
"stylelint-prettier" "stylelint-prettier"
], ],
"rules": { "extends": [
"prettier/prettier": true, "stylelint-prettier/recommended"
],
"alpha-value-notation": "number",
"rules": {
"block-no-empty": true, "block-no-empty": true,
"color-function-notation": "modern",
"color-hex-length": "short",
"color-no-invalid-hex": true,
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-redundant-longhand-properties": true,
"declaration-property-value-disallowed-list": {
"float": ["inline-start", "inline-end"]
},
"length-zero-no-unit": [true, { "length-zero-no-unit": [true, {
ignore: ["custom-properties"] ignore: ["custom-properties"]
}], }],
"selector-pseudo-element-colon-notation": "double",
"shorthand-property-no-redundant-values": true, "shorthand-property-no-redundant-values": true,
}, },
} }

View File

@ -1,35 +0,0 @@
export default {
rules: {
valid: true,
custom: [
(reporter, $, ast, { filename }) => {
reporter.name = "no-svg-fill-context-fill";
const svg = $.find("svg");
const fill = svg.attr("fill");
if (fill === "context-fill") {
reporter.error(
"Fill attribute on svg element must not be set to 'context-fill'",
svg[0],
ast
);
}
},
],
},
ignore: [
"build/**",
"l10n/**",
"docs/**",
"node_modules/**",
"external/bcmaps/**",
"external/builder/fixtures/**",
"external/builder/fixtures_babel/**",
"external/quickjs/**",
"test/tmp/**",
"test/pdfs/**",
"web/locale/**",
"*~/**",
],
};

View File

@ -8,21 +8,16 @@ Andreas Gal <gal@mozilla.com>
Artur Adib <aadib@mozilla.com> Artur Adib <aadib@mozilla.com>
Brendan Dahl <bdahl@mozilla.com> Brendan Dahl <bdahl@mozilla.com>
Bill Walker <bwalker@mozilla.com> Bill Walker <bwalker@mozilla.com>
Calixte Denizet <calixte@mozilla.com>
Chris G Jones <cjones@mozilla.com> Chris G Jones <cjones@mozilla.com>
David Quintana <gigaherz@gmail.com> David Quintana <gigaherz@gmail.com>
Emily Wachowiak <ewachowiak@mozilla.com>
Felix Kälberer <@fkaelberer> Felix Kälberer <@fkaelberer>
Jakob Miland <saebekassebil@gmail.com> Jakob Miland <saebekassebil@gmail.com>
Jonas Jenwald <jonas.jenwald@gmail.com> Jonas Jenwald <jonas.jenwald@gmail.com>
Julian Viereck Julian Viereck
Justin D'Arcangelo <justindarc@gmail.com> Justin D'Arcangelo <justindarc@gmail.com>
Kalervo Kujala Kalervo Kujala
Marco Castelluccio <mcastelluccio@mozilla.com>
Marie-Lilas Onanga Ozavino <monangaozavino@mozilla.com>
Michał Gołębiowski-Owczarek <m.goleb@gmail.com> Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
Ophir Lojkine <@lovasoa> Ophir Lojkine <@lovasoa>
Ryan Casey <rcasey@mozilla.com>
Rob Wu <rob@robwu.nl> Rob Wu <rob@robwu.nl>
Shaon Barman <shaon.barman@gmail.com> Shaon Barman <shaon.barman@gmail.com>
Sehyun Park <premed055515@gmail.com> Sehyun Park <premed055515@gmail.com>

View File

@ -1,4 +1,4 @@
# PDF.js [![CI](https://github.com/mozilla/pdf.js/actions/workflows/ci.yml/badge.svg?query=branch%3Amaster)](https://github.com/mozilla/pdf.js/actions/workflows/ci.yml?query=branch%3Amaster) # PDF.js [![Build Status](https://github.com/mozilla/pdf.js/workflows/CI/badge.svg?branch=master)](https://github.com/mozilla/pdf.js/actions?query=workflow%3ACI+branch%3Amaster)
[PDF.js](https://mozilla.github.io/pdf.js/) is a Portable Document Format (PDF) viewer that is built with HTML5. [PDF.js](https://mozilla.github.io/pdf.js/) is a Portable Document Format (PDF) viewer that is built with HTML5.
@ -14,7 +14,7 @@ get involved, visit:
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md) + [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md)
+ [Code Contribution Guide](https://github.com/mozilla/pdf.js/wiki/Contributing) + [Code Contribution Guide](https://github.com/mozilla/pdf.js/wiki/Contributing)
+ [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions) + [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?q=is%3Aissue%20state%3Aopen%20label%3Agood-beginner-bug) + [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=5-good-beginner-bug&page=1&sort=created&state=open)
+ [Projects](https://github.com/mozilla/pdf.js/projects) + [Projects](https://github.com/mozilla/pdf.js/projects)
Feel free to stop by our [Matrix room](https://chat.mozilla.org/#/room/#pdfjs:mozilla.org) for questions or guidance. Feel free to stop by our [Matrix room](https://chat.mozilla.org/#/room/#pdfjs:mozilla.org) for questions or guidance.
@ -23,8 +23,9 @@ Feel free to stop by our [Matrix room](https://chat.mozilla.org/#/room/#pdfjs:mo
### Online demo ### Online demo
Please note that the "Modern browsers" version assumes native support for the Please note that the "Modern browsers" version assumes native support for
latest JavaScript features; please also see [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support). features such as e.g. `async`/`await`, `ReadableStream`, optional chaining, and
nullish coalescing.
+ Modern browsers: https://mozilla.github.io/pdf.js/web/viewer.html + Modern browsers: https://mozilla.github.io/pdf.js/web/viewer.html
@ -40,7 +41,7 @@ PDF.js is built into version 19+ of Firefox.
+ The official extension for Chrome can be installed from the [Chrome Web Store](https://chrome.google.com/webstore/detail/pdf-viewer/oemmndcbldboiebfnladdacbdfmadadm). + The official extension for Chrome can be installed from the [Chrome Web Store](https://chrome.google.com/webstore/detail/pdf-viewer/oemmndcbldboiebfnladdacbdfmadadm).
*This extension is maintained by [@Rob--W](https://github.com/Rob--W).* *This extension is maintained by [@Rob--W](https://github.com/Rob--W).*
+ Build Your Own - Get the code as explained below and issue `npx gulp chromium`. Then open + Build Your Own - Get the code as explained below and issue `gulp chromium`. Then open
Chrome, go to `Tools > Extension` and load the (unpackaged) extension from the Chrome, go to `Tools > Extension` and load the (unpackaged) extension from the
directory `build/chromium`. directory `build/chromium`.
@ -52,21 +53,25 @@ To get a local copy of the current code, clone it using git:
$ cd pdf.js $ cd pdf.js
Next, install Node.js via the [official package](https://nodejs.org) or via Next, install Node.js via the [official package](https://nodejs.org) or via
[nvm](https://github.com/creationix/nvm). If everything worked out, install [nvm](https://github.com/creationix/nvm). You need to install the gulp package
all dependencies for PDF.js: globally (see also [gulp's getting started](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md#getting-started)):
$ npm install -g gulp-cli
If everything worked out, install all dependencies for PDF.js:
$ npm install $ npm install
Finally, you need to start a local web server as some browsers do not allow opening Finally, you need to start a local web server as some browsers do not allow opening
PDF files using a `file://` URL. Run: PDF files using a `file://` URL. Run:
$ npx gulp server $ gulp server
and then you can open: and then you can open:
+ http://localhost:8888/web/viewer.html + http://localhost:8888/web/viewer.html
Please keep in mind that this assumes the latest version of Mozilla Firefox; refer to [Building PDF.js](https://github.com/mozilla/pdf.js/blob/master/README.md#building-pdfjs) for non-development usage of the PDF.js library. Please keep in mind that this requires a modern and fully up-to-date browser; refer to [Building PDF.js](https://github.com/mozilla/pdf.js/blob/master/README.md#building-pdfjs) for non-development usage of the PDF.js library.
It is also possible to view all test PDF files on the right side by opening: It is also possible to view all test PDF files on the right side by opening:
@ -77,11 +82,11 @@ It is also possible to view all test PDF files on the right side by opening:
In order to bundle all `src/` files into two production scripts and build the generic In order to bundle all `src/` files into two production scripts and build the generic
viewer, run: viewer, run:
$ npx gulp generic $ gulp generic
If you need to support older browsers, run: If you need to support older browsers, run:
$ npx gulp generic-legacy $ gulp generic-legacy
This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory (respectively `build/generic-legacy/build/`). This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory (respectively `build/generic-legacy/build/`).
Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will
@ -90,7 +95,7 @@ be loaded by `pdf.js`. The PDF.js files are large and should be minified for pro
## Using PDF.js in a web application ## Using PDF.js in a web application
To use PDF.js in a web application you can choose to use a pre-built version of the library To use PDF.js in a web application you can choose to use a pre-built version of the library
or to build it from source. We supply pre-built versions for usage with NPM under or to build it from source. We supply pre-built versions for usage with NPM and Bower under
the `pdfjs-dist` name. For more information and examples please refer to the the `pdfjs-dist` name. For more information and examples please refer to the
[wiki page](https://github.com/mozilla/pdf.js/wiki/Setup-pdf.js-in-a-website) on this subject. [wiki page](https://github.com/mozilla/pdf.js/wiki/Setup-pdf.js-in-a-website) on this subject.
@ -107,7 +112,7 @@ You can play with the PDF.js API directly from your browser using the live demos
+ [Interactive examples](https://mozilla.github.io/pdf.js/examples/index.html#interactive-examples) + [Interactive examples](https://mozilla.github.io/pdf.js/examples/index.html#interactive-examples)
More examples can be found in the [examples folder](https://github.com/mozilla/pdf.js/tree/master/examples/). Some of them are using the pdfjs-dist package, which can be built and installed in this repo directory via `npx gulp dist-install` command. More examples can be found in the [examples folder](https://github.com/mozilla/pdf.js/tree/master/examples/). Some of them are using the pdfjs-dist package, which can be built and installed in this repo directory via `gulp dist-install` command.
For an introduction to the PDF.js code, check out the presentation by our For an introduction to the PDF.js code, check out the presentation by our
contributor Julian Viereck: contributor Julian Viereck:
@ -134,4 +139,8 @@ Talk to us on Matrix:
File an issue: File an issue:
+ https://github.com/mozilla/pdf.js/issues/new/choose + https://github.com/mozilla/pdf.js/issues/new
Follow us on twitter: @pdfjs
+ https://twitter.com/pdfjs

20
docs/config.json Normal file
View File

@ -0,0 +1,20 @@
{
"locals": {
"url": "http://localhost:8080",
"name": "PDF.js Documentation",
"description": ""
},
"require": {
"typogr": "typogr"
},
"jade": {
"pretty": true
},
"markdown": {
"smartLists": true,
"smartypants": true
},
"plugins": [
"./plugins/wintersmith-makerelative.coffee"
]
}

View File

@ -1,11 +1,8 @@
--- ---
title: API title: API
layout: layout.njk template: layout.jade
slug: api
--- ---
# API # API
The generated API documentation, from the inline comments in [api.js](https://github.com/mozilla/pdf.js/blob/master/src/display/api.js), is available below. We're currently working on <a href="draft/index.html">better API docs</a>, but the API is well documented in [api.js](https://github.com/mozilla/pdf.js/blob/master/src/display/api.js).
<iframe src="draft/index.html" title="PDF.js API documentation"></iframe>

View File

@ -1,100 +0,0 @@
/*!
Theme: a11y-light
Author: @ericwbailey
Maintainer: @ericwbailey
Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css
Original source: https://github.com/highlightjs/highlight.js/blob/main/src/styles/a11y-light.css
*/
.hljs {
background: #fefefe;
color: #545454;
}
/* Comment */
.hljs-comment,
.hljs-quote {
color: #696969;
}
/* Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #d91e18;
}
/* Orange */
.hljs-number,
.hljs-built_in,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #aa5d00;
}
/* Yellow */
.hljs-attribute {
color: #aa5d00;
}
/* Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #008000;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #007faa;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #7928a1;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
@media screen and (-ms-high-contrast: active) {
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,40 +1,119 @@
header { body {
background-color: #f8f8f8; }
border-bottom: 1px solid #e5e7e8; .starter-template {
padding: 0 15px;
}
.navbar-brand { .navbar-brand {
padding: 0; padding: 4px 15px;
}
img { .navbar-brand img {
height: 42px; height: 42px;
} }
.navbar {
border-color: #e5e7e8;
} }
} .navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
main { .navbar-default .navbar-nav > .active > a:focus {
margin: 50px 0; background-color: #fff;
border: 1px solid #e5e7e8;
.description { border-width: 0 1px;
font-size: 20px; position: relative;
} top: 1px;
pre {
background-color: #f5f5f5;
border: 1px solid #cccccc;
border-radius: 4px;
padding: 10px;
}
iframe {
border: none;
height: calc(0.55 * 100vh);
width: 100%;
}
} }
footer { footer {
border-top: 1px solid #e5e5e5; padding-top: 40px;
color: #777777; padding-bottom: 40px;
padding: 40px 0; margin-top: 100px;
color: #777;
text-align: center; text-align: center;
border-top: 1px solid #E5E5E5;
}
/* code styling */
code {
font-family: 'Anonymous Pro', monospace;
font-size: 0.85em;
color: #000;
}
pre code {
display: block;
line-height: 1.1;
}
p code {
padding: 0.1em 0.3em 0.2em;
border-radius: 0.3em;
position: relative;
top: -0.15em;
background: #444;
color: #fff;
white-space: nowrap;
}
/* syntax hl stuff */
code.lang-markdown {
color: #424242;
}
code.lang-markdown .header,
code.lang-markdown .strong {
font-weight: bold;
}
code.lang-markdown .emphasis {
font-style: italic;
}
code.lang-markdown .horizontal_rule,
code.lang-markdown .link_label,
code.lang-markdown .code,
code.lang-markdown .header,
code.lang-markdown .link_url {
color: #555;
}
code.lang-markdown .blockquote,
code.lang-markdown .bullet {
color: #bbb;
}
/* Tomorrow Theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
.tomorrow-comment, pre .comment, pre .title {
color: #8e908c;
}
.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo {
color: #c82829;
}
.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant {
color: #f5871f;
}
.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute {
color: #eab700;
}
.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata {
color: #718c00;
}
.tomorrow-aqua, pre .css .hexcolor {
color: #3e999f;
}
.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title {
color: #4271ae;
}
.tomorrow-purple, pre .keyword, pre .javascript .function {
color: #8959a8;
} }

View File

@ -1,7 +1,6 @@
--- ---
title: Examples title: Examples
layout: layout.njk template: layout.jade
slug: examples
--- ---
## Hello World Walkthrough ## Hello World Walkthrough
@ -45,24 +44,14 @@ Each PDF page has its own viewport which defines the size in pixels(72DPI) and i
```js ```js
var scale = 1.5; var scale = 1.5;
var viewport = page.getViewport({ scale: scale, }); var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens.
var outputScale = window.devicePixelRatio || 1;
var canvas = document.getElementById('the-canvas'); var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d'); var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = Math.floor(viewport.width * outputScale); canvas.width = viewport.width;
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
var transform = outputScale !== 1
? [outputScale, 0, 0, outputScale, 0, 0]
: null;
var renderContext = { var renderContext = {
canvasContext: context, canvasContext: context,
transform: transform,
viewport: viewport viewport: viewport
}; };
page.render(renderContext); page.render(renderContext);
@ -82,19 +71,19 @@ var scaledViewport = page.getViewport({ scale: scale, });
### Hello World with document load error handling ### Hello World with document load error handling
The example demonstrates how promises can be used to handle errors during loading. The example demonstrates how promises can be used to handle errors during loading.
It also demonstrates how to wait until a page is loaded and rendered. It also demonstrates how to wait until page loaded and rendered.
<script async src="https://jsfiddle.net/pdfjs/9engc9mw/embed/html,css,result/"></script> <script async src="//jsfiddle.net/pdfjs/9engc9mw/embed/js,html,css,result/"></script>
### Hello World using base64 encoded PDF ### Hello World using base64 encoded PDF
The PDF.js can accept any decoded base64 data as an array. The PDF.js can accept any decoded base64 data as an array.
<script async src="https://jsfiddle.net/pdfjs/cq0asLqz/embed/html,css,result/"></script> <script async src="//jsfiddle.net/pdfjs/cq0asLqz/embed/js,html,css,result/"></script>
### Previous/Next example ### Previous/Next example
The same canvas cannot be used to perform to draw two pages at the same time -- The same canvas cannot be used to perform to draw two pages at the same time --
the example demonstrates how to wait on previous operation to be complete. the example demonstrates how to wait on previous operation to be complete.
<script async src="https://jsfiddle.net/pdfjs/wagvs9Lf/embed/html,css,result/"></script> <script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/js,html,css,result/"></script>

View File

@ -1,7 +1,6 @@
--- ---
title: Getting Started title: Getting Started
layout: layout.njk template: layout.jade
slug: getting_started
--- ---
# Getting Started # Getting Started
@ -38,22 +37,26 @@ Before downloading PDF.js please take a moment to understand the different layer
## Download ## Download
Please refer to [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support) for information about supported browsers.
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<h3>Prebuilt (modern browsers)</h3> <h3>Prebuilt</h3>
<p> <p>
Includes the generic build of PDF.js and the viewer. Includes the generic build of PDF.js and the viewer.
</p> </p>
<span class="GROUP_CLASS">
<a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-dist.zip">Stable (vSTABLE_VERSION)</a> <a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-dist.zip">Stable (vSTABLE_VERSION)</a>
<a type="button" class="btn btn-warning HIDDEN_CLASS" href="https://github.com/mozilla/pdf.js/releases/download/vBETA_VERSION/pdfjs-BETA_VERSION-dist.zip">Beta (vBETA_VERSION)</a>
</span>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<h3>Prebuilt (older browsers)</h3> <h3>Prebuilt (for older browsers)</h3>
<p> <p>
Includes the generic build of PDF.js and the viewer. Includes the generic build of PDF.js and the viewer.
</p> </p>
<span class="GROUP_CLASS">
<a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-legacy-dist.zip">Stable (vSTABLE_VERSION)</a> <a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-legacy-dist.zip">Stable (vSTABLE_VERSION)</a>
<a type="button" class="btn btn-warning HIDDEN_CLASS" href="https://github.com/mozilla/pdf.js/releases/download/vBETA_VERSION/pdfjs-BETA_VERSION-legacy-dist.zip">Beta (vBETA_VERSION)</a>
</span>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<h3>Source</h3> <h3>Source</h3>
@ -77,50 +80,52 @@ Note that we only mention the most relevant files and folders.
### Prebuilt ### Prebuilt
```plaintext ```
├── build/ ├── build/
├── pdf.mjs - display layer    ├── pdf.js - display layer
├── pdf.mjs.map - display layer's source map    ├── pdf.js.map - display layer's source map
├── pdf.worker.mjs - core layer    ├── pdf.worker.js - core layer
└── pdf.worker.mjs.map - core layer's source map    └── pdf.worker.js.map - core layer's source map
├── web/ ├── web/
│ ├── cmaps/ - character maps (required by core) │ ├── cmaps/ - character maps (required by core)
│ ├── compressed.tracemonkey-pldi-09.pdf - PDF file for testing purposes │ ├── compressed.tracemonkey-pldi-09.pdf - PDF file for testing purposes
│ ├── debugger.js - helpful debugging features
│ ├── images/ - images for the viewer and annotation icons │ ├── images/ - images for the viewer and annotation icons
│ ├── locale/ - translation files │ ├── locale/ - translation files
│ ├── viewer.css - viewer style sheet │ ├── viewer.css - viewer style sheet
│ ├── viewer.html - viewer layout │ ├── viewer.html - viewer layout
│ ├── viewer.mjs - viewer layer │ ├── viewer.js - viewer layer
│ └── viewer.mjs.map - viewer layer's source map │ └── viewer.js.map - viewer layer's source map
└── LICENSE └── LICENSE
``` ```
### Source ### Source
```plaintext ```
├── docs/ - website source code ├── docs/ - website source code
├── examples/ - simple usage examples ├── examples/ - simple usage examples
├── extensions/ - browser extension source code ├── extensions/ - browser extension source code
├── external/ - third party code ├── external/ - third party code
├── l10n/ - translation files ├── l10n/ - translation files
├── src/ ├── src/
│ ├── core/ - core layer │   ├── core/ - core layer
│ ├── display/ - display layer │   ├── display/ - display layer
│ ├── shared/ - shared code between the core and display layers │   ├── shared/ - shared code between the core and display layers
│ ├── interfaces.js - interface definitions for the core/display layers │   ├── interfaces.js - interface definitions for the core/display layers
│ └── pdf.*.js - wrapper files for bundling │   ├── pdf.*.js - wrapper files for bundling
├── test/ - unit, font, reference, and integration tests │   └── worker_loader.js - used for developer builds to load worker files
├── test/ - unit, font and reference tests
├── web/ - viewer layer ├── web/ - viewer layer
├── LICENSE ├── LICENSE
├── README.md ├── README.md
├── gulpfile.mjs - build scripts/logic ├── gulpfile.js - build scripts/logic
├── package-lock.json - pinned dependency versions ├── package-lock.json - pinned dependency versions
└── package.json - package definition and dependencies └── package.json - package definition and dependencies
``` ```
## Trying the Viewer ## Trying the Viewer
With the prebuilt or source version, open `web/viewer.html` in a browser and the test pdf should load. Note: the worker is not enabled for file:// urls, so use a server. If you're using the source build and have node, you can run `npx gulp server`. With the prebuilt or source version, open `web/viewer.html` in a browser and the test pdf should load. Note: the worker is not enabled for file:// urls, so use a server. If you're using the source build and have node, you can run `gulp server`.
## More Information ## More Information

View File

@ -1,13 +1,14 @@
--- ---
title: Home title: PDF.js
layout: layout.njk template: layout.jade
slug: home
--- ---
<h1 class="text-center">PDF.js</h1> <h1 class="text-center">PDF.js</h1>
<p class="text-center description">A general-purpose, web standards-based platform for parsing and rendering PDFs.</p> <p class="text-center" style="font-size: 20px">A general-purpose, web standards-based platform for parsing and rendering PDFs.
<p class="text-center"> </p>
<a type="button" class="btn btn-outline-dark" href="/getting_started/#download">Download</a> <p class="text-center">
<a type="button" class="btn btn-outline-dark" href="https://github.com/mozilla/pdf.js#online-demo">Demo</a> <a type="button" class="btn btn-lg btn-default" href="getting_started/#download">Download</a>
<a type="button" class="btn btn-outline-dark" href="https://github.com/mozilla/pdf.js">GitHub Project</a> <a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js#online-demo">Demo</a>
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js">GitHub Project</a>
</p> </p>

File diff suppressed because one or more lines are too long

4
docs/contents/js/jquery-2.1.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
module.exports = (env, callback) ->
count = (string, substr) ->
num = pos = 0
return 1/0 unless substr.length
num++ while pos = 1 + string.indexOf(substr, pos)
num
env.helpers.makeRelative = (source, dest) ->
return dest unless dest.indexOf("/") == 0
depth = count(source, '/') # 1 being /
ret = ""
ret += "../" while depth = depth - 1
ret + dest.substring(1)
callback()

52
docs/templates/layout.jade vendored Normal file
View File

@ -0,0 +1,52 @@
- makeRelative = env.helpers.makeRelative
doctype html
html(lang='en')
head
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name='description', content='A general-purpose, web standards-based platform for parsing and rendering PDFs.')
meta(name='author', content='')
link(rel='shortcut icon', href=makeRelative(page.url, '/images/favicon.ico'))
title=page.title
// Bootstrap core CSS
link(href=makeRelative(page.url, '/css/bootstrap.min.css'), rel='stylesheet')
// Custom styles for this template
link(href=makeRelative(page.url, '/css/main.css'), rel='stylesheet')
body
header.navbar.navbar-default.navbar-static-top
.container
.navbar-header
button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='#')
img(src=makeRelative(page.url, '/images/logo.svg'))
.collapse.navbar-collapse
ul.nav.navbar-nav
li(class=(page.url === '/' ? 'active' : ''))
a(href=makeRelative(page.url, '/')) Home
li(class=(page.url === '/getting_started/' ? 'active' : ''))
a(href=makeRelative(page.url, '/getting_started/')) Getting Started
li(class=(page.url === '/examples/' ? 'active' : ''))
a(href=makeRelative(page.url, '/examples/')) Examples
li
a(href='https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions') FAQ
li(class=(page.url === '/api/' ? 'active' : ''))
a(href=makeRelative(page.url, '/api/')) API
.container
.starter-template
section.content!= typogr(page.html).typogrify()
.container
footer
p &copy;Mozilla and individual contributors
:markdown-it
PDF.js is licensed under [Apache](https://github.com/mozilla/pdf.js/blob/master/LICENSE),
documentation is licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/)
// Bootstrap core JavaScript
script(src=makeRelative(page.url, '/js/jquery-2.1.0.min.js'))
script(src=makeRelative(page.url, '/js/bootstrap.min.js'))

View File

@ -1,56 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>{{ sitename }} - {{ title }}</title>
<meta charset="utf-8">
<meta name="description" content="{{ description }}">
<meta name="viewport" content="device-width, initial-scale=1.0">
<script src="/js/jquery-3.7.1.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<link rel="shortcut icon" href="/images/favicon.ico">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/a11y-light.css">
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<div class="navbar-brand"><img src="/images/logo.svg"></div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item {{ 'active' if slug == 'home' else '' }}">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item {{ 'active' if slug == 'getting_started' else '' }}">
<a class="nav-link" href="/getting_started">Getting started</a>
</li>
<li class="nav-item {{ 'active' if slug == 'examples' else '' }}">
<a class="nav-link" href="/examples">Examples</a>
</li>
<li class="nav-item {{ 'active' if slug == 'api' else '' }}">
<a class="nav-link" href="/api">API</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions">FAQ</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main class="container">
{{ contents | safe }}
</main>
<footer>
<p>&copy; Mozilla and individual contributors</p>
<p>
PDF.js is licensed under <a href="https://github.com/mozilla/pdf.js/blob/master/LICENSE">Apache 2.0</a>,
documentation is licensed under <a href="https://creativecommons.org/licenses/by-sa/2.5">CC BY-SA 2.5</a>.
</p>
</footer>
</body>
</html>

View File

@ -1,473 +0,0 @@
import globals from "globals";
import import_ from "eslint-plugin-import";
import jasmine from "eslint-plugin-jasmine";
import json from "eslint-plugin-json";
import noUnsanitized from "eslint-plugin-no-unsanitized";
import perfectionist from "eslint-plugin-perfectionist";
import prettierRecommended from "eslint-plugin-prettier/recommended";
import unicorn from "eslint-plugin-unicorn";
const jsFiles = folder => {
const prefix = folder === "." ? "" : folder + "/";
return [prefix + "**/*.js", prefix + "**/*.jsm", prefix + "**/*.mjs"];
};
// Include all files referenced in extensions/chromium/background.js
const chromiumExtensionServiceWorkerFiles = [
"extensions/chromium/extension-router.js",
"extensions/chromium/options/migration.js",
"extensions/chromium/pdfHandler.js",
"extensions/chromium/preserve-referer.js",
"extensions/chromium/suppress-update.js",
"extensions/chromium/telemetry.js",
];
export default [
{
ignores: [
"**/build/",
"**/l10n/",
"**/docs/",
"**/node_modules/",
"external/bcmaps/",
"external/builder/fixtures/",
"external/builder/fixtures_babel/",
"external/openjpeg/",
"external/qcms/",
"external/quickjs/",
"test/stats/results/",
"test/tmp/",
"test/pdfs/",
"web/locale/",
"web/wasm/",
"**/*~/",
],
},
/* ======================================================================== *\
Base configuration
\* ======================================================================== */
prettierRecommended,
{
files: ["**/*.json"],
...json.configs.recommended,
},
{
files: jsFiles("."),
ignores: chromiumExtensionServiceWorkerFiles,
languageOptions: {
globals: globals.browser,
},
},
{
files: jsFiles("."),
plugins: {
import: import_.flatConfigs.recommended.plugins.import,
json,
"no-unsanitized": noUnsanitized,
perfectionist,
unicorn,
},
languageOptions: {
globals: {
...globals.worker,
PDFJSDev: "readonly",
__raw_import__: "readonly",
},
ecmaVersion: 2025,
sourceType: "module",
},
rules: {
"import/export": "error",
"import/exports-last": "error",
"import/extensions": ["error", "always", { ignorePackages: true }],
"import/first": "error",
"import/named": "error",
"import/no-cycle": "error",
"import/no-empty-named-blocks": "error",
"import/no-commonjs": "error",
"import/no-mutable-exports": "error",
"import/no-restricted-paths": [
"error",
{
zones: [
{
target: "./web",
from: "./src",
},
],
},
],
"import/no-self-import": "error",
"import/no-unresolved": [
"error",
{
ignore: [
"display",
"pdfjs",
"pdfjs-lib",
"pdfjs-web",
"web",
"fluent-bundle",
"fluent-dom",
// See https://github.com/firebase/firebase-admin-node/discussions/1359.
"eslint-plugin-perfectionist",
],
},
],
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
"perfectionist/sort-exports": "error",
"perfectionist/sort-named-exports": "error",
"unicorn/no-abusive-eslint-disable": "error",
"unicorn/no-array-reduce": ["error", { allowSimpleOperations: true }],
"unicorn/no-console-spaces": "error",
"unicorn/no-instanceof-builtins": "error",
"unicorn/no-invalid-remove-event-listener": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-single-promise-in-promise-methods": "error",
"unicorn/no-typeof-undefined": ["error", { checkGlobalVariables: false }],
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/no-useless-spread": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-dom-node-remove": "error",
"unicorn/prefer-import-meta-properties": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-logical-operator-over-ternary": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-modern-math-apis": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-single-call": "error",
"unicorn/prefer-string-replace-all": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-ternary": ["error", "only-single-line"],
"unicorn/throw-new-error": "error",
// Possible errors
"for-direction": "error",
"getter-return": "error",
"no-async-promise-executor": "error",
"no-cond-assign": ["error", "except-parens"],
"no-constant-condition": ["error", { checkLoops: false }],
"no-debugger": "error",
"no-dupe-args": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": ["error", { allowEmptyCatch: true }],
"no-empty-character-class": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-func-assign": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-obj-calls": "error",
"no-promise-executor-return": "error",
"no-regex-spaces": "error",
"no-setter-return": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": [
"error",
{ disallowArithmeticOperators: true },
],
"no-unused-private-class-members": "error",
"use-isnan": ["error", { enforceForIndexOf: true }],
"valid-typeof": ["error", { requireStringLiterals: true }],
// Best Practices
"accessor-pairs": [
"error",
{ setWithoutGet: true, enforceForClassMembers: true },
],
"consistent-return": "error",
curly: ["error", "all"],
"default-case-last": "error",
"dot-notation": "error",
eqeqeq: ["error", "always"],
"grouped-accessor-pairs": ["error", "getBeforeSet"],
"no-alert": "error",
"no-caller": "error",
"no-else-return": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-multi-str": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-octal": "error",
"no-redeclare": "error",
"no-return-await": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-throw-literal": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-concat": "error",
"no-useless-escape": "error",
"no-useless-return": "error",
"prefer-promise-reject-errors": "error",
"prefer-spread": "error",
"wrap-iife": ["error", "any"],
yoda: ["error", "never", { exceptRange: true }],
// Strict Mode
strict: ["off", "global"],
// Variables
"no-delete-var": "error",
"no-label-var": "error",
"no-shadow": "error",
"no-shadow-restricted-names": "error",
"no-undef-init": "error",
"no-undef": ["error", { typeof: true }],
"no-unused-vars": ["error", { vars: "all", args: "none" }],
"no-use-before-define": [
"error",
{ functions: false, classes: false, variables: false },
],
// Stylistic Issues
"lines-between-class-members": ["error", "always"],
"max-len": ["error", { code: 1000, comments: 80, ignoreUrls: true }],
"new-cap": ["error", { newIsCap: true, capIsNew: false }],
"no-array-constructor": "error",
"no-multiple-empty-lines": ["error", { max: 1, maxEOF: 0, maxBOF: 1 }],
"no-nested-ternary": "error",
"no-new-object": "error",
"no-restricted-syntax": [
"error",
{
selector:
"BinaryExpression[operator='instanceof'][right.name='Object']",
message: "Use `typeof` rather than `instanceof Object`.",
},
{
selector: "CallExpression[callee.name='assert'][arguments.length!=2]",
message: "`assert()` must always be invoked with two arguments.",
},
{
selector: "CallExpression[callee.name='isCmd'][arguments.length<2]",
message:
"Use `instanceof Cmd` rather than `isCmd()` with one argument.",
},
{
selector: "CallExpression[callee.name='isDict'][arguments.length<2]",
message:
"Use `instanceof Dict` rather than `isDict()` with one argument.",
},
{
selector: "CallExpression[callee.name='isName'][arguments.length<2]",
message:
"Use `instanceof Name` rather than `isName()` with one argument.",
},
{
selector: "NewExpression[callee.name='Cmd']",
message: "Use `Cmd.get()` rather than `new Cmd()`.",
},
{
selector: "NewExpression[callee.name='Name']",
message: "Use `Name.get()` rather than `new Name()`.",
},
{
selector: "NewExpression[callee.name='ObjectLoader']",
message:
"Use `ObjectLoader.load()` rather than `new ObjectLoader()`.",
},
{
selector: "NewExpression[callee.name='Ref']",
message: "Use `Ref.get()` rather than `new Ref()`.",
},
{
selector: "ExportNamedDeclaration[declaration]",
message:
"Separate the declaration and the export statement, using `export { ... }`.",
},
{
selector: "ExportDefaultDeclaration:has(> :declaration)",
message:
"Separate the declaration and the export statement, using `export default <variable name>`.",
},
],
"no-unneeded-ternary": "error",
"operator-assignment": "error",
"prefer-exponentiation-operator": "error",
"spaced-comment": ["error", "always", { block: { balanced: true } }],
// ECMAScript 6
"arrow-body-style": ["error", "as-needed"],
"constructor-super": "error",
"no-class-assign": "error",
"no-const-assign": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"no-this-before-super": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-var": "error",
"object-shorthand": ["error", "always", { avoidQuotes: true }],
"prefer-const": "error",
"require-yield": "error",
"sort-imports": ["error", { ignoreCase: true }],
"template-curly-spacing": ["error", "never"],
},
},
{
files: jsFiles("src"),
rules: {
"no-console": "error",
},
},
/* ======================================================================== *\
Test-specific rules
\* ======================================================================== */
{
files: jsFiles("test"),
plugins: { jasmine },
languageOptions: {
globals: {
...globals.node,
...globals.jasmine,
},
},
rules: {
...jasmine.configs.recommended.rules,
"jasmine/new-line-before-expect": "off",
"jasmine/new-line-between-declarations": "off",
"jasmine/no-focused-tests": "error",
"jasmine/no-pending-tests": "off",
"jasmine/no-spec-dupes": ["error", "branch"],
"jasmine/no-suite-dupes": ["error", "branch"],
"jasmine/prefer-jasmine-matcher": "off",
"jasmine/prefer-toHaveBeenCalledWith": "off",
},
},
{
files: jsFiles("test/unit"),
rules: {
"import/no-unresolved": ["error", { ignore: ["pdfjs/"] }],
"no-console": ["error", { allow: ["warn", "error"] }],
},
},
{
files: jsFiles("test/integration"),
rules: {
"no-console": ["error", { allow: ["warn", "error"] }],
"no-restricted-syntax": [
"error",
{
selector: "CallExpression[callee.name='waitForTimeout']",
message:
"`waitForTimeout` can cause intermittent failures and should not be used (see issue #17656 for replacements).",
},
],
},
},
/* ======================================================================== *\
External libraries
\* ======================================================================== */
{
files: jsFiles("external"),
languageOptions: { globals: globals.node },
},
/* ======================================================================== *\
Examples
\* ======================================================================== */
{
files: jsFiles("examples"),
languageOptions: {
globals: {
pdfjsImageDecoders: false,
pdfjsLib: false,
pdfjsViewer: false,
},
},
},
{
files: [...jsFiles("examples/node"), ...jsFiles("examples/webpack")],
languageOptions: { globals: globals.node },
},
/* ======================================================================== *\
Chromium extension
\* ======================================================================== */
{
files: jsFiles("extensions/chromium"),
languageOptions: {
globals: globals.webextensions,
sourceType: "script",
},
rules: {
"no-var": "off",
},
},
{
files: chromiumExtensionServiceWorkerFiles,
languageOptions: {
globals: globals.serviceworker,
sourceType: "script",
},
},
/* ======================================================================== *\
Other
\* ======================================================================== */
{
files: ["gulpfile.mjs"],
languageOptions: { globals: globals.node },
},
];

11
examples/.eslintrc Normal file
View File

@ -0,0 +1,11 @@
{
"extends": [
"../.eslintrc"
],
"globals": {
"pdfjsImageDecoders": false,
"pdfjsLib": false,
"pdfjsViewer": false,
},
}

1
examples/browserify/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

@ -0,0 +1,26 @@
## Overview
Example to demonstrate PDF.js library usage with Browserify.
## Getting started
Build project and install the example dependencies:
$ gulp dist-install
$ cd examples/browserify
$ npm install
To build Browserify bundles, run `gulp build`. If you are running
a web server, you can observe the build results at
http://localhost:8888/examples/browserify/index.html
See main.js, worker.js and gulpfile.js files. Please notice that PDF.js
packaging requires packaging of the main application and PDF.js worker code,
and the `workerSrc` path shall be set to the latter file. The pdf.worker.js file
shall be excluded from the main bundle.
Alternatives to the gulp commands (without compression) are:
$ mkdir -p ../../build/browserify
$ node_modules/.bin/browserify main.js -u ./node_modules/pdfjs-dist/build/pdf.worker.js -o ../../build/browserify/main.bundle.js
$ node_modules/.bin/browserify worker.js -o ../../build/browserify/pdf.worker.bundle.js

View File

@ -0,0 +1,40 @@
const gulp = require("gulp");
const browserify = require("browserify");
const streamify = require("gulp-streamify");
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
const source = require("vinyl-source-stream");
const OUTPUT_PATH = "../../build/browserify";
const TMP_FILE_PREFIX = "../../build/browserify_";
gulp.task("build-bundle", function () {
return browserify("main.js", { output: TMP_FILE_PREFIX + "main.tmp" })
.ignore(require.resolve("pdfjs-dist/build/pdf.worker")) // Reducing size
.bundle()
.pipe(source(TMP_FILE_PREFIX + "main.tmp"))
.pipe(streamify(uglify()))
.pipe(rename("main.bundle.js"))
.pipe(gulp.dest(OUTPUT_PATH));
});
gulp.task("build-worker", function () {
// We can create our own viewer (see worker.js) or use already defined one.
const workerSrc = require.resolve("pdfjs-dist/build/pdf.worker.entry");
return browserify(workerSrc, { output: TMP_FILE_PREFIX + "worker.tmp" })
.bundle()
.pipe(source(TMP_FILE_PREFIX + "worker.tmp"))
.pipe(
streamify(
uglify({
compress: {
sequences: false, // Chrome has issue with the generated code if true
},
})
)
)
.pipe(rename("pdf.worker.bundle.js"))
.pipe(gulp.dest(OUTPUT_PATH));
});
gulp.task("build", gulp.series("build-bundle", "build-worker"));

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>browserify example</title>
<script src="../../build/browserify/main.bundle.js"></script>
</head>
<body>
<canvas id="theCanvas"></canvas>
</body>
</html>

View File

@ -0,0 +1,35 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for browserify.
const pdfjsLib = require("pdfjs-dist");
const pdfPath = "../learning/helloworld.pdf";
// Setting worker path to worker bundle.
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../build/browserify/pdf.worker.bundle.js";
// Loading a document.
const loadingTask = pdfjsLib.getDocument(pdfPath);
loadingTask.promise
.then(function (pdfDocument) {
// Request a first page
return pdfDocument.getPage(1).then(function (pdfPage) {
// Display page on the existing canvas with 100% scale.
const viewport = pdfPage.getViewport({ scale: 1.0 });
const canvas = document.getElementById("theCanvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport,
});
return renderTask.promise;
});
})
.catch(function (reason) {
console.error("Error: " + reason);
});

View File

@ -0,0 +1,16 @@
{
"name": "browserify-pdf.js-example",
"version": "0.1.0",
"devDependencies": {
"browserify": "^13.0.0",
"gulp": "^3.9.1",
"gulp-rename": "^1.2.2",
"gulp-streamify": "^1.0.2",
"gulp-uglify": "^1.5.3",
"pdfjs-dist": "../../node_modules/pdfjs-dist",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"build": "gulp build"
}
}

View File

@ -0,0 +1,9 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for browserify: worker bundle.
(typeof window !== "undefined"
? window
: {}
).pdfjsWorker = require("pdfjs-dist/build/pdf.worker");

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<!-- <!--
Copyright 2014 Mozilla Foundation Copyright 2014 Mozilla Foundation
@ -16,9 +16,9 @@ limitations under the License.
--> -->
<html dir="ltr" mozdisallowselectionprint> <html dir="ltr" mozdisallowselectionprint>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate" /> <meta name="google" content="notranslate">
<title>PDF.js page viewer using built components</title> <title>PDF.js page viewer using built components</title>
<style> <style>
@ -29,15 +29,15 @@ limitations under the License.
} }
</style> </style>
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" /> <link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
</head> </head>
<body tabindex="1"> <body tabindex="1">
<div id="pageContainer" class="pdfViewer singlePageView"></div> <div id="pageContainer" class="pdfViewer singlePageView"></div>
<script src="pageviewer.mjs" type="module"></script> <script src="pageviewer.js"></script>
</body> </body>
</html> </html>

View File

@ -13,6 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) { if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`"); alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
@ -21,7 +23,7 @@ if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
// The workerSrc property shall be specified. // The workerSrc property shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; "../../node_modules/pdfjs-dist/build/pdf.worker.js";
// Some PDFs need external cmaps. // Some PDFs need external cmaps.
// //
@ -32,8 +34,6 @@ const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
const PAGE_TO_VIEW = 1; const PAGE_TO_VIEW = 1;
const SCALE = 1.0; const SCALE = 1.0;
const ENABLE_XFA = true;
const container = document.getElementById("pageContainer"); const container = document.getElementById("pageContainer");
const eventBus = new pdfjsViewer.EventBus(); const eventBus = new pdfjsViewer.EventBus();
@ -43,13 +43,10 @@ const loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL, url: DEFAULT_URL,
cMapUrl: CMAP_URL, cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED, cMapPacked: CMAP_PACKED,
enableXfa: ENABLE_XFA,
}); });
loadingTask.promise.then(function (pdfDocument) {
const pdfDocument = await loadingTask.promise;
// Document loaded, retrieving the page. // Document loaded, retrieving the page.
const pdfPage = await pdfDocument.getPage(PAGE_TO_VIEW); return pdfDocument.getPage(PAGE_TO_VIEW).then(function (pdfPage) {
// Creating the page view with default parameters. // Creating the page view with default parameters.
const pdfPageView = new pdfjsViewer.PDFPageView({ const pdfPageView = new pdfjsViewer.PDFPageView({
container, container,
@ -57,7 +54,12 @@ const pdfPageView = new pdfjsViewer.PDFPageView({
scale: SCALE, scale: SCALE,
defaultViewport: pdfPage.getViewport({ scale: SCALE }), defaultViewport: pdfPage.getViewport({ scale: SCALE }),
eventBus, eventBus,
// We can enable text/annotations layers, if needed
textLayerFactory: new pdfjsViewer.DefaultTextLayerFactory(),
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
}); });
// Associate the actual page with the view, and draw it. // Associates the actual page with the view, and drawing it
pdfPageView.setPdfPage(pdfPage); pdfPageView.setPdfPage(pdfPage);
pdfPageView.draw(); return pdfPageView.draw();
});
});

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<!-- <!--
Copyright 2014 Mozilla Foundation Copyright 2014 Mozilla Foundation
@ -16,9 +16,9 @@ limitations under the License.
--> -->
<html dir="ltr" mozdisallowselectionprint> <html dir="ltr" mozdisallowselectionprint>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate" /> <meta name="google" content="notranslate">
<title>PDF.js viewer using built components</title> <title>PDF.js viewer using built components</title>
<style> <style>
@ -35,10 +35,10 @@ limitations under the License.
} }
</style> </style>
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" /> <link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
</head> </head>
<body tabindex="1"> <body tabindex="1">
@ -46,6 +46,6 @@ limitations under the License.
<div id="viewer" class="pdfViewer"></div> <div id="viewer" class="pdfViewer"></div>
</div> </div>
<script src="simpleviewer.mjs" type="module"></script> <script src="simpleviewer.js"></script>
</body> </body>
</html> </html>

View File

@ -13,6 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) { if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`"); alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
@ -21,7 +23,7 @@ if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
// The workerSrc property shall be specified. // The workerSrc property shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; "../../node_modules/pdfjs-dist/build/pdf.worker.js";
// Some PDFs need external cmaps. // Some PDFs need external cmaps.
// //
@ -30,15 +32,12 @@ const CMAP_PACKED = true;
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf"; const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
// To test the AcroForm and/or scripting functionality, try e.g. this file: // To test the AcroForm and/or scripting functionality, try e.g. this file:
// "../../test/pdfs/160F-2019.pdf" // var DEFAULT_URL = "../../test/pdfs/160F-2019.pdf";
const ENABLE_XFA = true; const SEARCH_FOR = ""; // try 'Mozilla';
const SEARCH_FOR = ""; // try "Mozilla";
const SANDBOX_BUNDLE_SRC = new URL( // For scripting support, note also `enableScripting` below.
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs", const SANDBOX_BUNDLE_SRC = "../../node_modules/pdfjs-dist/build/pdf.sandbox.js";
window.location
);
const container = document.getElementById("viewerContainer"); const container = document.getElementById("viewerContainer");
@ -67,6 +66,7 @@ const pdfViewer = new pdfjsViewer.PDFViewer({
linkService: pdfLinkService, linkService: pdfLinkService,
findController: pdfFindController, findController: pdfFindController,
scriptingManager: pdfScriptingManager, scriptingManager: pdfScriptingManager,
enableScripting: true,
}); });
pdfLinkService.setViewer(pdfViewer); pdfLinkService.setViewer(pdfViewer);
pdfScriptingManager.setViewer(pdfViewer); pdfScriptingManager.setViewer(pdfViewer);
@ -77,7 +77,7 @@ eventBus.on("pagesinit", function () {
// We can try searching for things. // We can try searching for things.
if (SEARCH_FOR) { if (SEARCH_FOR) {
eventBus.dispatch("find", { type: "", query: SEARCH_FOR }); pdfFindController.executeCommand("find", { query: SEARCH_FOR });
} }
}); });
@ -86,12 +86,11 @@ const loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL, url: DEFAULT_URL,
cMapUrl: CMAP_URL, cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED, cMapPacked: CMAP_PACKED,
enableXfa: ENABLE_XFA,
}); });
loadingTask.promise.then(function (pdfDocument) {
const pdfDocument = await loadingTask.promise;
// Document loaded, specifying document for the viewer and // Document loaded, specifying document for the viewer and
// the (optional) linkService. // the (optional) linkService.
pdfViewer.setDocument(pdfDocument); pdfViewer.setDocument(pdfDocument);
pdfLinkService.setDocument(pdfDocument, null); pdfLinkService.setDocument(pdfDocument, null);
});

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<!-- <!--
Copyright 2014 Mozilla Foundation Copyright 2014 Mozilla Foundation
@ -16,9 +16,9 @@ limitations under the License.
--> -->
<html dir="ltr" mozdisallowselectionprint> <html dir="ltr" mozdisallowselectionprint>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate" /> <meta name="google" content="notranslate">
<title>PDF.js Single Page Viewer using built components</title> <title>PDF.js Single Page Viewer using built components</title>
<style> <style>
@ -35,10 +35,10 @@ limitations under the License.
} }
</style> </style>
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" /> <link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
</head> </head>
<body tabindex="1"> <body tabindex="1">
@ -46,6 +46,6 @@ limitations under the License.
<div id="viewer" class="pdfViewer"></div> <div id="viewer" class="pdfViewer"></div>
</div> </div>
<script src="singlepageviewer.mjs" type="module"></script> <script src="singlepageviewer.js"></script>
</body> </body>
</html> </html>

View File

@ -13,6 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) { if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`"); alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
@ -21,7 +23,7 @@ if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
// The workerSrc property shall be specified. // The workerSrc property shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; "../../node_modules/pdfjs-dist/build/pdf.worker.js";
// Some PDFs need external cmaps. // Some PDFs need external cmaps.
// //
@ -30,15 +32,12 @@ const CMAP_PACKED = true;
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf"; const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
// To test the AcroForm and/or scripting functionality, try e.g. this file: // To test the AcroForm and/or scripting functionality, try e.g. this file:
// "../../test/pdfs/160F-2019.pdf" // var DEFAULT_URL = "../../test/pdfs/160F-2019.pdf";
const ENABLE_XFA = true; const SEARCH_FOR = ""; // try 'Mozilla';
const SEARCH_FOR = ""; // try "Mozilla";
const SANDBOX_BUNDLE_SRC = new URL( // For scripting support, note also `enableScripting` below.
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs", const SANDBOX_BUNDLE_SRC = "../../node_modules/pdfjs-dist/build/pdf.sandbox.js";
window.location
);
const container = document.getElementById("viewerContainer"); const container = document.getElementById("viewerContainer");
@ -67,6 +66,7 @@ const pdfSinglePageViewer = new pdfjsViewer.PDFSinglePageViewer({
linkService: pdfLinkService, linkService: pdfLinkService,
findController: pdfFindController, findController: pdfFindController,
scriptingManager: pdfScriptingManager, scriptingManager: pdfScriptingManager,
enableScripting: true,
}); });
pdfLinkService.setViewer(pdfSinglePageViewer); pdfLinkService.setViewer(pdfSinglePageViewer);
pdfScriptingManager.setViewer(pdfSinglePageViewer); pdfScriptingManager.setViewer(pdfSinglePageViewer);
@ -77,7 +77,7 @@ eventBus.on("pagesinit", function () {
// We can try searching for things. // We can try searching for things.
if (SEARCH_FOR) { if (SEARCH_FOR) {
eventBus.dispatch("find", { type: "", query: SEARCH_FOR }); pdfFindController.executeCommand("find", { query: SEARCH_FOR });
} }
}); });
@ -86,12 +86,11 @@ const loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL, url: DEFAULT_URL,
cMapUrl: CMAP_URL, cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED, cMapPacked: CMAP_PACKED,
enableXfa: ENABLE_XFA,
}); });
loadingTask.promise.then(function (pdfDocument) {
const pdfDocument = await loadingTask.promise;
// Document loaded, specifying document for the viewer and // Document loaded, specifying document for the viewer and
// the (optional) linkService. // the (optional) linkService.
pdfSinglePageViewer.setDocument(pdfDocument); pdfSinglePageViewer.setDocument(pdfDocument);
pdfLinkService.setDocument(pdfDocument, null); pdfLinkService.setDocument(pdfDocument, null);
});

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<!-- <!--
Copyright 2018 Mozilla Foundation Copyright 2018 Mozilla Foundation
@ -16,9 +16,9 @@ limitations under the License.
--> -->
<html dir="ltr" mozdisallowselectionprint> <html dir="ltr" mozdisallowselectionprint>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate" /> <meta name="google" content="notranslate">
<title>PDF.js standalone JpegImage parser</title> <title>PDF.js standalone JpegImage parser</title>
<style> <style>
@ -29,12 +29,12 @@ limitations under the License.
} }
</style> </style>
<script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.js"></script>
</head> </head>
<body tabindex="1"> <body tabindex="1">
<canvas id="jpegCanvas" width="0" height="0"></canvas> <canvas id="jpegCanvas" width="0" height="0"></canvas>
<script src="jpeg_viewer.mjs" type="module"></script> <script src="jpeg_viewer.js"></script>
</body> </body>
</html> </html>

View File

@ -13,6 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict";
if (!pdfjsImageDecoders.JpegImage) { if (!pdfjsImageDecoders.JpegImage) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using `gulp dist-install`"); alert("Please build the pdfjs-dist library using `gulp dist-install`");
@ -25,11 +27,32 @@ const jpegCtx = jpegCanvas.getContext("2d");
// Load the image data, and convert it to a Uint8Array. // Load the image data, and convert it to a Uint8Array.
// //
const response = await fetch(JPEG_IMAGE); let nonBinaryRequest = false;
if (!response.ok) { const request = new XMLHttpRequest();
throw new Error(response.statusText); request.open("GET", JPEG_IMAGE, false);
try {
request.responseType = "arraybuffer";
nonBinaryRequest = request.responseType !== "arraybuffer";
} catch (e) {
nonBinaryRequest = true;
}
if (nonBinaryRequest && request.overrideMimeType) {
request.overrideMimeType("text/plain; charset=x-user-defined");
}
request.send(null);
let typedArrayImage;
if (nonBinaryRequest) {
const str = request.responseText,
length = str.length;
const bytes = new Uint8Array(length);
for (let i = 0; i < length; ++i) {
bytes[i] = str.charCodeAt(i) & 0xff;
}
typedArrayImage = bytes;
} else {
typedArrayImage = new Uint8Array(request.response);
} }
const typedArrayImage = new Uint8Array(await response.arrayBuffer());
// Parse the image data using `JpegImage`. // Parse the image data using `JpegImage`.
// //

View File

@ -1,71 +1,68 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<title>'Hello, world!' example</title> <title>'Hello, world!' example</title>
</head> </head>
<body> <body>
<h1>'Hello, world!' example</h1> <h1>'Hello, world!' example</h1>
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas> <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script id="script" type="module"> <script id="script">
// //
// If absolute URL from the remote server is provided, configure the CORS // If absolute URL from the remote server is provided, configure the CORS
// header on that server. // header on that server.
// //
const url = "./helloworld.pdf"; var url = './helloworld.pdf';
// //
// The workerSrc property shall be specified. // The workerSrc property shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; pdfjsLib.GlobalWorkerOptions.workerSrc =
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
// //
// Asynchronous download PDF // Asynchronous download PDF
// //
const loadingTask = pdfjsLib.getDocument(url); var loadingTask = pdfjsLib.getDocument(url);
const pdf = await loadingTask.promise; loadingTask.promise.then(function(pdf) {
// //
// Fetch the first page // Fetch the first page
// //
const page = await pdf.getPage(1); pdf.getPage(1).then(function(page) {
const scale = 1.5; var scale = 1.5;
const viewport = page.getViewport({ scale }); var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens.
const outputScale = window.devicePixelRatio || 1;
// //
// Prepare canvas using PDF page dimensions // Prepare canvas using PDF page dimensions
// //
const canvas = document.getElementById("the-canvas"); var canvas = document.getElementById('the-canvas');
const context = canvas.getContext("2d"); var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = Math.floor(viewport.width * outputScale); canvas.width = viewport.width;
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
// //
// Render PDF page into canvas context // Render PDF page into canvas context
// //
const renderContext = { var renderContext = {
canvasContext: context, canvasContext: context,
transform, viewport: viewport,
viewport,
}; };
page.render(renderContext); page.render(renderContext);
});
});
</script> </script>
<hr /> <hr>
<h2>JavaScript code:</h2> <h2>JavaScript code:</h2>
<pre id="code"></pre> <pre id="code"></pre>
<script> <script>
document.getElementById("code").textContent = document.getElementById("script").text; document.getElementById('code').textContent =
document.getElementById('script').text;
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,77 +1,73 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<title>'Hello, world!' base64 example</title> <title>'Hello, world!' base64 example</title>
</head> </head>
<body> <body>
<h1>'Hello, world!' example</h1> <h1>'Hello, world!' example</h1>
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas> <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script id="script" type="module"> <script id="script">
// atob() is used to convert base64 encoded PDF to binary-like data. // atob() is used to convert base64 encoded PDF to binary-like data.
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/ // (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
// Base64_encoding_and_decoding.) // Base64_encoding_and_decoding.)
var pdfData = atob( var pdfData = atob(
"JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog" + 'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
"IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv" + 'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
"TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K" + 'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
"Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg" + 'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
"L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+" + 'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
"PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u" + 'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
"dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq" + 'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
"Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU" + 'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
"CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu" + 'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
"ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g" + 'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
"CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw" + 'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
"MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v" + 'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
"dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G" 'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
);
// //
// The workerSrc property shall be specified. // The workerSrc property shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; pdfjsLib.GlobalWorkerOptions.workerSrc =
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
// Opening PDF by passing its binary data as a string. It is still preferable // Opening PDF by passing its binary data as a string. It is still preferable
// to use Uint8Array, but string or array-like structure will work too. // to use Uint8Array, but string or array-like structure will work too.
var loadingTask = pdfjsLib.getDocument({ data: pdfData }); var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
var pdf = await loadingTask.promise; loadingTask.promise.then(function(pdf) {
// Fetch the first page. // Fetch the first page.
var page = await pdf.getPage(1); pdf.getPage(1).then(function(page) {
var scale = 1.5; var scale = 1.5;
var viewport = page.getViewport({ scale: scale }); var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens.
var outputScale = window.devicePixelRatio || 1;
// Prepare canvas using PDF page dimensions. // Prepare canvas using PDF page dimensions.
var canvas = document.getElementById("the-canvas"); var canvas = document.getElementById('the-canvas');
var context = canvas.getContext("2d"); var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = Math.floor(viewport.width * outputScale); canvas.width = viewport.width;
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
// Render PDF page into canvas context. // Render PDF page into canvas context.
var renderContext = { var renderContext = {
canvasContext: context, canvasContext: context,
transform, viewport: viewport,
viewport,
}; };
page.render(renderContext); page.render(renderContext);
});
});
</script> </script>
<hr /> <hr>
<h2>JavaScript code:</h2> <h2>JavaScript code:</h2>
<pre id="code"></pre> <pre id="code"></pre>
<script> <script>
document.getElementById("code").textContent = document.getElementById("script").text; document.getElementById('code').textContent =
document.getElementById('script').text;
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,46 +1,48 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<title>Previous/Next example</title> <title>Previous/Next example</title>
</head> </head>
<body> <body>
<h1>'Previous/Next' example</h1> <h1>'Previous/Next' example</h1>
<div> <div>
<button id="prev" type="button">Previous</button> <button id="prev">Previous</button>
<button id="next" type="button">Next</button> <button id="next">Next</button>
&nbsp; &nbsp; &nbsp; &nbsp;
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span> <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
</div> </div>
<div> <div>
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas> <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
</div> </div>
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script id="script" type="module"> <script id="script">
// //
// If absolute URL from the remote server is provided, configure the CORS // If absolute URL from the remote server is provided, configure the CORS
// header on that server. // header on that server.
// //
var url = "../../web/compressed.tracemonkey-pldi-09.pdf"; var url = '../../web/compressed.tracemonkey-pldi-09.pdf';
// //
// In cases when the pdf.worker.js is located at the different folder than the // In cases when the pdf.worker.js is located at the different folder than the
// PDF.js's one, or the PDF.js is executed via eval(), the workerSrc property // PDF.js's one, or the PDF.js is executed via eval(), the workerSrc property
// shall be specified. // shall be specified.
// //
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; pdfjsLib.GlobalWorkerOptions.workerSrc =
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
var pdfDoc = null, var pdfDoc = null,
pageNum = 1, pageNum = 1,
pageRendering = false, pageRendering = false,
pageNumPending = null, pageNumPending = null,
scale = 0.8, scale = 0.8,
canvas = document.getElementById("the-canvas"), canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext("2d"); ctx = canvas.getContext('2d');
/** /**
* Get page info from document, resize canvas accordingly, and render page. * Get page info from document, resize canvas accordingly, and render page.
@ -50,21 +52,13 @@
pageRendering = true; pageRendering = true;
// Using promise to fetch the page // Using promise to fetch the page
pdfDoc.getPage(num).then(function(page) { pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport({ scale: scale }); var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens. canvas.height = viewport.height;
var outputScale = window.devicePixelRatio || 1; canvas.width = viewport.width;
canvas.width = Math.floor(viewport.width * outputScale);
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
// Render PDF page into canvas context // Render PDF page into canvas context
var renderContext = { var renderContext = {
canvasContext: ctx, canvasContext: ctx,
transform: transform,
viewport: viewport, viewport: viewport,
}; };
var renderTask = page.render(renderContext); var renderTask = page.render(renderContext);
@ -81,12 +75,12 @@
}); });
// Update page counters // Update page counters
document.getElementById("page_num").textContent = num; document.getElementById('page_num').textContent = num;
} }
/** /**
* If another page rendering in progress, waits until the rendering is * If another page rendering in progress, waits until the rendering is
* finished. Otherwise, executes rendering immediately. * finised. Otherwise, executes rendering immediately.
*/ */
function queueRenderPage(num) { function queueRenderPage(num) {
if (pageRendering) { if (pageRendering) {
@ -106,7 +100,7 @@
pageNum--; pageNum--;
queueRenderPage(pageNum); queueRenderPage(pageNum);
} }
document.getElementById("prev").addEventListener("click", onPrevPage); document.getElementById('prev').addEventListener('click', onPrevPage);
/** /**
* Displays next page. * Displays next page.
@ -118,17 +112,20 @@
pageNum++; pageNum++;
queueRenderPage(pageNum); queueRenderPage(pageNum);
} }
document.getElementById("next").addEventListener("click", onNextPage); document.getElementById('next').addEventListener('click', onNextPage);
/** /**
* Asynchronously downloads PDF. * Asynchronously downloads PDF.
*/ */
var loadingTask = pdfjsLib.getDocument(url); var loadingTask = pdfjsLib.getDocument(url);
pdfDoc = await loadingTask.promise; loadingTask.promise.then(function(pdfDoc_) {
document.getElementById("page_count").textContent = pdfDoc.numPages; pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
// Initial/first page rendering // Initial/first page rendering
renderPage(pageNum); renderPage(pageNum);
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -26,12 +26,12 @@ html {
} }
header { header {
background-color: rgb(244 244 244 / 1); background-color: rgba(244, 244, 244, 1);
} }
header h1 { header h1 {
border-bottom: 1px solid rgb(216 216 216 / 1); border-bottom: 1px solid rgba(216, 216, 216, 1);
color: rgb(133 133 133 / 1); color: rgba(133, 133, 133, 1);
font-size: 23px; font-size: 23px;
font-style: italic; font-style: italic;
font-weight: normal; font-weight: normal;
@ -44,7 +44,7 @@ header h1 {
body { body {
background: url(images/document_bg.png); background: url(images/document_bg.png);
color: rgb(255 255 255 / 1); color: rgba(255, 255, 255, 1);
font-family: sans-serif; font-family: sans-serif;
font-size: 10px; font-size: 10px;
height: 100%; height: 100%;
@ -71,7 +71,7 @@ footer {
left: 0; left: 0;
right: 0; right: 0;
z-index: 1; z-index: 1;
box-shadow: 0 -0.2rem 0.5rem rgb(50 50 50 / 0.75); box-shadow: 0 -0.2rem 0.5rem rgba(50, 50, 50, 0.75);
} }
.toolbarButton { .toolbarButton {
@ -81,7 +81,7 @@ footer {
border-width: 0; border-width: 0;
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: rgb(0 0 0 / 0); background-color: rgba(0, 0, 0, 0);
} }
.toolbarButton.pageUp { .toolbarButton.pageUp {
@ -110,11 +110,11 @@ footer {
left: 36%; left: 36%;
text-align: center; text-align: center;
border: 0; border: 0;
background-color: rgb(0 0 0 / 0); background-color: rgba(0, 0, 0, 0);
font-size: 1.2rem; font-size: 1.2rem;
color: rgb(255 255 255 / 1); color: rgba(255, 255, 255, 1);
background-image: background-image: url(images/div_line_left.png),
url(images/div_line_left.png), url(images/div_line_right.png); url(images/div_line_right.png);
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: left, right; background-position: left, right;
background-size: 0.2rem, 0.2rem; background-size: 0.2rem, 0.2rem;
@ -153,7 +153,10 @@ footer {
position: absolute; position: absolute;
overflow: auto; overflow: auto;
width: 100%; width: 100%;
inset: 5rem 0 4rem; top: 5rem;
bottom: 4rem;
left: 0;
right: 0;
} }
canvas { canvas {
@ -184,47 +187,41 @@ canvas {
} }
#loadingBar { #loadingBar {
/* Define this variable here, and not in :root, to avoid reflowing the
entire viewer when updating progress (see issue 15958). */
--progressBar-percent: 0%;
position: relative; position: relative;
height: 0.6rem; height: 0.6rem;
background-color: rgb(51 51 51 / 1); background-color: rgba(51, 51, 51, 1);
border-bottom: 1px solid rgb(51 51 51 / 1); border-bottom: 1px solid rgba(51, 51, 51, 1);
margin-top: 5rem;
} }
#loadingBar .progress { #loadingBar .progress {
position: absolute; position: absolute;
left: 0; left: 0;
width: 100%; width: 0;
transform: scaleX(var(--progressBar-percent));
transform-origin: 0 0;
height: 100%; height: 100%;
background-color: rgb(221 221 221 / 1); background-color: rgba(221, 221, 221, 1);
overflow: hidden; overflow: hidden;
transition: transform 200ms; transition: width 200ms;
} }
@keyframes progressIndeterminate { @keyframes progressIndeterminate {
0% { 0% {
transform: translateX(0%); left: 0;
} }
50% { 50% {
transform: translateX(100%); left: 100%;
} }
100% { 100% {
transform: translateX(100%); left: 100%;
} }
} }
#loadingBar.indeterminate .progress { #loadingBar .progress.indeterminate {
transform: none; background-color: rgba(153, 153, 153, 1);
background-color: rgb(153 153 153 / 1);
transition: none; transition: none;
} }
#loadingBar.indeterminate .progress .glimmer { #loadingBar .indeterminate .glimmer {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -232,11 +229,39 @@ canvas {
width: 5rem; width: 5rem;
background-image: linear-gradient( background-image: linear-gradient(
to right, to right,
rgb(153 153 153 / 1) 0%, rgba(153, 153, 153, 1) 0%,
rgb(255 255 255 / 1) 50%, rgba(255, 255, 255, 1) 50%,
rgb(153 153 153 / 1) 100% rgba(153, 153, 153, 1) 100%
); );
background-size: 100% 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
animation: progressIndeterminate 2s linear infinite; animation: progressIndeterminate 2s linear infinite;
} }
#errorWrapper {
background: none repeat scroll 0 0 rgba(255, 85, 85, 1);
color: rgba(255, 255, 255, 1);
left: 0;
position: absolute;
right: 0;
top: 3.2rem;
z-index: 1000;
padding: 0.3rem;
font-size: 0.8em;
}
#errorMessageLeft {
float: left;
}
#errorMessageRight {
float: right;
}
#errorMoreInfo {
background-color: rgba(255, 255, 255, 1);
color: rgba(0, 0, 0, 1);
padding: 0.3rem;
margin: 0.3rem;
width: 98%;
}

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<!-- <!--
Copyright 2016 Mozilla Foundation Copyright 2016 Mozilla Foundation
@ -16,16 +16,16 @@ limitations under the License.
--> -->
<html dir="ltr"> <html dir="ltr">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>PDF.js viewer</title> <title>PDF.js viewer</title>
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" /> <link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
<link rel="stylesheet" type="text/css" href="viewer.css" /> <link rel="stylesheet" type="text/css" href="viewer.css">
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
</head> </head>
<body> <body>
@ -42,16 +42,35 @@ limitations under the License.
<div class="glimmer"></div> <div class="glimmer"></div>
</div> </div>
<div id="errorWrapper" hidden="true">
<div id="errorMessageLeft">
<span id="errorMessage"></span>
<button id="errorShowMore">
More Information
</button>
<button id="errorShowLess">
Less Information
</button>
</div>
<div id="errorMessageRight">
<button id="errorClose">
Close
</button>
</div>
<div class="clearBoth"></div>
<textarea id="errorMoreInfo" hidden="true" readonly="readonly"></textarea>
</div>
<footer> <footer>
<button class="toolbarButton pageUp" title="Previous Page" id="previous" type="button"></button> <button class="toolbarButton pageUp" title="Previous Page" id="previous"></button>
<button class="toolbarButton pageDown" title="Next Page" id="next" type="button"></button> <button class="toolbarButton pageDown" title="Next Page" id="next"></button>
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" /> <input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1">
<button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut" type="button"></button> <button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut"></button>
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn" type="button"></button> <button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
</footer> </footer>
<script src="viewer.mjs" type="module"></script> <script src="viewer.js"></script>
</body> </body>
</html> </html>

View File

@ -13,19 +13,21 @@
* limitations under the License. * limitations under the License.
*/ */
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) { if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`"); alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
} }
const MAX_CANVAS_PIXELS = 0; // CSS-only zooming. const USE_ONLY_CSS_ZOOM = true;
const TEXT_LAYER_MODE = 0; // DISABLE const TEXT_LAYER_MODE = 0; // DISABLE
const MAX_IMAGE_SIZE = 1024 * 1024; const MAX_IMAGE_SIZE = 1024 * 1024;
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/"; const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true; const CMAP_PACKED = true;
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; "../../node_modules/pdfjs-dist/build/pdf.worker.js";
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf"; const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
const DEFAULT_SCALE_DELTA = 1.1; const DEFAULT_SCALE_DELTA = 1.1;
@ -80,24 +82,46 @@ const PDFViewerApplication = {
self.pdfDocument = pdfDocument; self.pdfDocument = pdfDocument;
self.pdfViewer.setDocument(pdfDocument); self.pdfViewer.setDocument(pdfDocument);
self.pdfLinkService.setDocument(pdfDocument); self.pdfLinkService.setDocument(pdfDocument);
self.pdfHistory.initialize({ self.pdfHistory.initialize({ fingerprint: pdfDocument.fingerprint });
fingerprint: pdfDocument.fingerprints[0],
});
self.loadingBar.hide(); self.loadingBar.hide();
self.setTitleUsingMetadata(pdfDocument); self.setTitleUsingMetadata(pdfDocument);
}, },
function (reason) { function (exception) {
let key = "pdfjs-loading-error"; const message = exception && exception.message;
if (reason instanceof pdfjsLib.InvalidPDFException) { const l10n = self.l10n;
key = "pdfjs-invalid-file-error"; let loadingErrorMessage;
} else if (reason instanceof pdfjsLib.ResponseException) {
key = reason.missing if (exception instanceof pdfjsLib.InvalidPDFException) {
? "pdfjs-missing-file-error" // change error message also for other builds
: "pdfjs-unexpected-response-error"; loadingErrorMessage = l10n.get(
"invalid_file_error",
null,
"Invalid or corrupted PDF file."
);
} else if (exception instanceof pdfjsLib.MissingPDFException) {
// special message for missing PDFs
loadingErrorMessage = l10n.get(
"missing_file_error",
null,
"Missing PDF file."
);
} else if (exception instanceof pdfjsLib.UnexpectedResponseException) {
loadingErrorMessage = l10n.get(
"unexpected_response_error",
null,
"Unexpected server response."
);
} else {
loadingErrorMessage = l10n.get(
"loading_error",
null,
"An error occurred while loading the PDF."
);
} }
self.l10n.get(key).then(msg => {
self.error(msg, { message: reason?.message }); loadingErrorMessage.then(function (msg) {
self.error(msg, { message });
}); });
self.loadingBar.hide(); self.loadingBar.hide();
} }
@ -110,6 +134,9 @@ const PDFViewerApplication = {
* destruction is completed. * destruction is completed.
*/ */
close() { close() {
const errorWrapper = document.getElementById("errorWrapper");
errorWrapper.hidden = true;
if (!this.pdfLoadingTask) { if (!this.pdfLoadingTask) {
return Promise.resolve(); return Promise.resolve();
} }
@ -132,12 +159,9 @@ const PDFViewerApplication = {
}, },
get loadingBar() { get loadingBar() {
const bar = document.getElementById("loadingBar"); const bar = new pdfjsViewer.ProgressBar("#loadingBar", {});
return pdfjsLib.shadow(
this, return pdfjsLib.shadow(this, "loadingBar", bar);
"loadingBar",
new pdfjsViewer.ProgressBar(bar)
);
}, },
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
@ -145,7 +169,7 @@ const PDFViewerApplication = {
let title = pdfjsLib.getFilenameFromUrl(url) || url; let title = pdfjsLib.getFilenameFromUrl(url) || url;
try { try {
title = decodeURIComponent(title); title = decodeURIComponent(title);
} catch { } catch (e) {
// decodeURIComponent may throw URIError, // decodeURIComponent may throw URIError,
// fall back to using the unprocessed url in that case // fall back to using the unprocessed url in that case
} }
@ -163,7 +187,7 @@ const PDFViewerApplication = {
// Provides some basic debug information // Provides some basic debug information
console.log( console.log(
"PDF " + "PDF " +
pdfDocument.fingerprints[0] + pdfDocument.fingerprint +
" [" + " [" +
info.PDFFormatVersion + info.PDFFormatVersion +
" " + " " +
@ -202,25 +226,79 @@ const PDFViewerApplication = {
}, },
error: function pdfViewError(message, moreInfo) { error: function pdfViewError(message, moreInfo) {
const l10n = this.l10n;
const moreInfoText = [ const moreInfoText = [
`PDF.js v${pdfjsLib.version || "?"} (build: ${pdfjsLib.build || "?"})`, l10n.get(
"error_version_info",
{ version: pdfjsLib.version || "?", build: pdfjsLib.build || "?" },
"PDF.js v{{version}} (build: {{build}})"
),
]; ];
if (moreInfo) {
moreInfoText.push(`Message: ${moreInfo.message}`);
if (moreInfo) {
moreInfoText.push(
l10n.get(
"error_message",
{ message: moreInfo.message },
"Message: {{message}}"
)
);
if (moreInfo.stack) { if (moreInfo.stack) {
moreInfoText.push(`Stack: ${moreInfo.stack}`); moreInfoText.push(
l10n.get("error_stack", { stack: moreInfo.stack }, "Stack: {{stack}}")
);
} else { } else {
if (moreInfo.filename) { if (moreInfo.filename) {
moreInfoText.push(`File: ${moreInfo.filename}`); moreInfoText.push(
l10n.get(
"error_file",
{ file: moreInfo.filename },
"File: {{file}}"
)
);
} }
if (moreInfo.lineNumber) { if (moreInfo.lineNumber) {
moreInfoText.push(`Line: ${moreInfo.lineNumber}`); moreInfoText.push(
l10n.get(
"error_line",
{ line: moreInfo.lineNumber },
"Line: {{line}}"
)
);
} }
} }
} }
console.error(`${message}\n\n${moreInfoText.join("\n")}`); const errorWrapper = document.getElementById("errorWrapper");
errorWrapper.hidden = false;
const errorMessage = document.getElementById("errorMessage");
errorMessage.textContent = message;
const closeButton = document.getElementById("errorClose");
closeButton.onclick = function () {
errorWrapper.hidden = true;
};
const errorMoreInfo = document.getElementById("errorMoreInfo");
const moreInfoButton = document.getElementById("errorShowMore");
const lessInfoButton = document.getElementById("errorShowLess");
moreInfoButton.onclick = function () {
errorMoreInfo.hidden = false;
moreInfoButton.hidden = true;
lessInfoButton.hidden = false;
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px";
};
lessInfoButton.onclick = function () {
errorMoreInfo.hidden = true;
moreInfoButton.hidden = false;
lessInfoButton.hidden = true;
};
moreInfoButton.hidden = false;
lessInfoButton.hidden = true;
Promise.all(moreInfoText).then(function (parts) {
errorMoreInfo.value = parts.join("\n");
});
}, },
progress: function pdfViewProgress(level) { progress: function pdfViewProgress(level) {
@ -272,7 +350,7 @@ const PDFViewerApplication = {
}); });
this.pdfLinkService = linkService; this.pdfLinkService = linkService;
this.l10n = new pdfjsViewer.GenericL10n(); this.l10n = pdfjsViewer.NullL10n;
const container = document.getElementById("viewerContainer"); const container = document.getElementById("viewerContainer");
const pdfViewer = new pdfjsViewer.PDFViewer({ const pdfViewer = new pdfjsViewer.PDFViewer({
@ -280,7 +358,7 @@ const PDFViewerApplication = {
eventBus, eventBus,
linkService, linkService,
l10n: this.l10n, l10n: this.l10n,
maxCanvasPixels: MAX_CANVAS_PIXELS, useOnlyCssZoom: USE_ONLY_CSS_ZOOM,
textLayerMode: TEXT_LAYER_MODE, textLayerMode: TEXT_LAYER_MODE,
}); });
this.pdfViewer = pdfViewer; this.pdfViewer = pdfViewer;

9
examples/node/.eslintrc Normal file
View File

@ -0,0 +1,9 @@
{
"extends": [
"../.eslintrc"
],
"env": {
"node": true,
},
}

276
examples/node/domstubs.js Normal file
View File

@ -0,0 +1,276 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function xmlEncode(s) {
let i = 0,
ch;
s = String(s);
while (
i < s.length &&
(ch = s[i]) !== "&" &&
ch !== "<" &&
ch !== '"' &&
ch !== "\n" &&
ch !== "\r" &&
ch !== "\t"
) {
i++;
}
if (i >= s.length) {
return s;
}
let buf = s.substring(0, i);
while (i < s.length) {
ch = s[i++];
switch (ch) {
case "&":
buf += "&amp;";
break;
case "<":
buf += "&lt;";
break;
case '"':
buf += "&quot;";
break;
case "\n":
buf += "&#xA;";
break;
case "\r":
buf += "&#xD;";
break;
case "\t":
buf += "&#x9;";
break;
default:
buf += ch;
break;
}
}
return buf;
}
function DOMElement(name) {
this.nodeName = name;
this.childNodes = [];
this.attributes = {};
this.textContent = "";
if (name === "style") {
this.sheet = {
cssRules: [],
insertRule(rule) {
this.cssRules.push(rule);
},
};
}
}
DOMElement.prototype = {
getAttribute: function DOMElement_getAttribute(name) {
if (name in this.attributes) {
return this.attributes[name];
}
return null;
},
getAttributeNS: function DOMElement_getAttributeNS(NS, name) {
// Fast path
if (name in this.attributes) {
return this.attributes[name];
}
// Slow path - used by test/unit/display_svg_spec.js
// Assuming that there is only one matching attribute for a given name,
// across all namespaces.
if (NS) {
const suffix = ":" + name;
for (const fullName in this.attributes) {
if (fullName.slice(-suffix.length) === suffix) {
return this.attributes[fullName];
}
}
}
return null;
},
setAttribute: function DOMElement_setAttribute(name, value) {
this.attributes[name] = value || "";
},
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) {
this.setAttribute(name, value);
},
appendChild: function DOMElement_appendChild(element) {
const childNodes = this.childNodes;
if (!childNodes.includes(element)) {
childNodes.push(element);
}
},
hasChildNodes: function DOMElement_hasChildNodes() {
return this.childNodes.length !== 0;
},
cloneNode: function DOMElement_cloneNode() {
const newNode = new DOMElement(this.nodeName);
newNode.childNodes = this.childNodes;
newNode.attributes = this.attributes;
newNode.textContent = this.textContent;
return newNode;
},
// This method is offered for convenience. It is recommended to directly use
// getSerializer because that allows you to process the chunks as they come
// instead of requiring the whole image to fit in memory.
toString: function DOMElement_toString() {
const buf = [];
const serializer = this.getSerializer();
let chunk;
while ((chunk = serializer.getNext()) !== null) {
buf.push(chunk);
}
return buf.join("");
},
getSerializer: function DOMElement_getSerializer() {
return new DOMElementSerializer(this);
},
};
function DOMElementSerializer(node) {
this._node = node;
this._state = 0;
this._loopIndex = 0;
this._attributeKeys = null;
this._childSerializer = null;
}
DOMElementSerializer.prototype = {
/**
* Yields the next chunk in the serialization of the element.
*
* @returns {string|null} null if the element has fully been serialized.
*/
getNext: function DOMElementSerializer_getNext() {
const node = this._node;
switch (this._state) {
case 0: // Start opening tag.
++this._state;
return "<" + node.nodeName;
case 1: // Add SVG namespace if this is the root element.
++this._state;
if (node.nodeName === "svg:svg") {
return (
' xmlns:xlink="http://www.w3.org/1999/xlink"' +
' xmlns:svg="http://www.w3.org/2000/svg"'
);
}
/* falls through */
case 2: // Initialize variables for looping over attributes.
++this._state;
this._loopIndex = 0;
this._attributeKeys = Object.keys(node.attributes);
/* falls through */
case 3: // Serialize any attributes and end opening tag.
if (this._loopIndex < this._attributeKeys.length) {
const name = this._attributeKeys[this._loopIndex++];
return " " + name + '="' + xmlEncode(node.attributes[name]) + '"';
}
++this._state;
return ">";
case 4: // Serialize textContent for tspan/style elements.
if (node.nodeName === "svg:tspan" || node.nodeName === "svg:style") {
this._state = 6;
return xmlEncode(node.textContent);
}
++this._state;
this._loopIndex = 0;
/* falls through */
case 5: // Serialize child nodes (only for non-tspan/style elements).
while (true) {
const value =
this._childSerializer && this._childSerializer.getNext();
if (value !== null) {
return value;
}
const nextChild = node.childNodes[this._loopIndex++];
if (nextChild) {
this._childSerializer = new DOMElementSerializer(nextChild);
} else {
this._childSerializer = null;
++this._state;
break;
}
}
/* falls through */
case 6: // Ending tag.
++this._state;
return "</" + node.nodeName + ">";
case 7: // Done.
return null;
default:
throw new Error("Unexpected serialization state: " + this._state);
}
},
};
const document = {
childNodes: [],
get currentScript() {
return { src: "" };
},
get documentElement() {
return this;
},
createElementNS(NS, element) {
const elObject = new DOMElement(element);
return elObject;
},
createElement(element) {
return this.createElementNS("", element);
},
getElementsByTagName(element) {
if (element === "head") {
return [this.head || (this.head = new DOMElement("head"))];
}
return [];
},
};
function Image() {
this._src = null;
this.onload = null;
}
Image.prototype = {
get src() {
return this._src;
},
set src(value) {
this._src = value;
if (this.onload) {
this.onload();
}
},
};
exports.document = document;
exports.Image = Image;
const exported_symbols = Object.keys(exports);
exports.setStubs = function (namespace) {
exported_symbols.forEach(function (key) {
console.assert(!(key in namespace), "property should not be set: " + key);
namespace[key] = exports[key];
});
};
exports.unsetStubs = function (namespace) {
exported_symbols.forEach(function (key) {
console.assert(key in namespace, "property should be set: " + key);
delete namespace[key];
});
};

View File

@ -3,10 +3,12 @@
// //
// Basic node example that prints document metadata and text content. // Basic node example that prints document metadata and text content.
// Requires single file built version of PDF.js -- please run
// `gulp singlefile` before running the example.
// //
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files. // Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs"; const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");
// Loading file from file system into typed array // Loading file from file system into typed array
const pdfPath = const pdfPath =
@ -14,7 +16,7 @@ const pdfPath =
// Will be using promises to load document, pages and misc data instead of // Will be using promises to load document, pages and misc data instead of
// callback. // callback.
const loadingTask = getDocument(pdfPath); const loadingTask = pdfjsLib.getDocument(pdfPath);
loadingTask.promise loadingTask.promise
.then(function (doc) { .then(function (doc) {
const numPages = doc.numPages; const numPages = doc.numPages;
@ -51,8 +53,6 @@ loadingTask.promise
}); });
console.log("## Text Content"); console.log("## Text Content");
console.log(strings.join(" ")); console.log(strings.join(" "));
// Release page resources.
page.cleanup();
}) })
.then(function () { .then(function () {
console.log(); console.log();

View File

@ -9,7 +9,9 @@ Install the dependencies and build the PDF.js library:
$ npm install $ npm install
$ gulp dist-install $ gulp dist-install
Run the example to convert the first page of a PDF file to a PNG image: Install the Node canvas library and run the example to convert the first page of a
PDF file to a PNG image:
$ npm install canvas
$ cd examples/node/pdf2png $ cd examples/node/pdf2png
$ node pdf2png.mjs $ node pdf2png.js

View File

@ -0,0 +1,110 @@
/* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const Canvas = require("canvas");
const assert = require("assert").strict;
const fs = require("fs");
function NodeCanvasFactory() {}
NodeCanvasFactory.prototype = {
create: function NodeCanvasFactory_create(width, height) {
assert(width > 0 && height > 0, "Invalid canvas size");
const canvas = Canvas.createCanvas(width, height);
const context = canvas.getContext("2d");
return {
canvas,
context,
};
},
reset: function NodeCanvasFactory_reset(canvasAndContext, width, height) {
assert(canvasAndContext.canvas, "Canvas is not specified");
assert(width > 0 && height > 0, "Invalid canvas size");
canvasAndContext.canvas.width = width;
canvasAndContext.canvas.height = height;
},
destroy: function NodeCanvasFactory_destroy(canvasAndContext) {
assert(canvasAndContext.canvas, "Canvas is not specified");
// Zeroing the width and height cause Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
canvasAndContext.canvas.width = 0;
canvasAndContext.canvas.height = 0;
canvasAndContext.canvas = null;
canvasAndContext.context = null;
},
};
const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");
// Some PDFs need external cmaps.
const CMAP_URL = "../../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
// Where the standard fonts are located.
const STANDARD_FONT_DATA_URL =
"../../../node_modules/pdfjs-dist/standard_fonts/";
// Loading file from file system into typed array.
const pdfPath =
process.argv[2] || "../../../web/compressed.tracemonkey-pldi-09.pdf";
const data = new Uint8Array(fs.readFileSync(pdfPath));
// Load the PDF file.
const loadingTask = pdfjsLib.getDocument({
data,
cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
standardFontDataUrl: STANDARD_FONT_DATA_URL,
});
loadingTask.promise
.then(function (pdfDocument) {
console.log("# PDF document loaded.");
// Get the first page.
pdfDocument.getPage(1).then(function (page) {
// Render the page on a Node canvas with 100% scale.
const viewport = page.getViewport({ scale: 1.0 });
const canvasFactory = new NodeCanvasFactory();
const canvasAndContext = canvasFactory.create(
viewport.width,
viewport.height
);
const renderContext = {
canvasContext: canvasAndContext.context,
viewport,
canvasFactory,
};
const renderTask = page.render(renderContext);
renderTask.promise.then(function () {
// Convert the canvas to an image buffer.
const image = canvasAndContext.canvas.toBuffer();
fs.writeFile("output.png", image, function (error) {
if (error) {
console.error("Error: " + error);
} else {
console.log(
"Finished converting first page of PDF file to a PNG image."
);
}
});
});
});
})
.catch(function (reason) {
console.log(reason);
});

View File

@ -1,72 +0,0 @@
/* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from "fs";
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
// Some PDFs need external cmaps.
const CMAP_URL = "../../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
// Where the standard fonts are located.
const STANDARD_FONT_DATA_URL =
"../../../node_modules/pdfjs-dist/standard_fonts/";
// Loading file from file system into typed array.
const pdfPath =
process.argv[2] || "../../../web/compressed.tracemonkey-pldi-09.pdf";
const data = new Uint8Array(fs.readFileSync(pdfPath));
// Load the PDF file.
const loadingTask = getDocument({
data,
cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
standardFontDataUrl: STANDARD_FONT_DATA_URL,
});
try {
const pdfDocument = await loadingTask.promise;
console.log("# PDF document loaded.");
// Get the first page.
const page = await pdfDocument.getPage(1);
// Render the page on a Node canvas with 100% scale.
const canvasFactory = pdfDocument.canvasFactory;
const viewport = page.getViewport({ scale: 1.0 });
const canvasAndContext = canvasFactory.create(
viewport.width,
viewport.height
);
const renderContext = {
canvasContext: canvasAndContext.context,
viewport,
};
const renderTask = page.render(renderContext);
await renderTask.promise;
// Convert the canvas to an image buffer.
const image = canvasAndContext.canvas.toBuffer("image/png");
fs.writeFile("output.png", image, function (error) {
if (error) {
console.error("Error: " + error);
} else {
console.log("Finished converting first page of PDF file to a PNG image.");
}
});
// Release page resources.
page.cleanup();
} catch (reason) {
console.log(reason);
}

142
examples/node/pdf2svg.js Normal file
View File

@ -0,0 +1,142 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
//
// Node tool to dump SVG output into a file.
//
const fs = require("fs");
const util = require("util");
const path = require("path");
const stream = require("stream");
// HACK few hacks to let PDF.js be loaded not as a module in global space.
require("./domstubs.js").setStubs(global);
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");
// Some PDFs need external cmaps.
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
// Loading file from file system into typed array
const pdfPath =
process.argv[2] || "../../web/compressed.tracemonkey-pldi-09.pdf";
const data = new Uint8Array(fs.readFileSync(pdfPath));
const outputDirectory = "./svgdump";
try {
// Note: This creates a directory only one level deep. If you want to create
// multiple subdirectories on the fly, use the mkdirp module from npm.
fs.mkdirSync(outputDirectory);
} catch (e) {
if (e.code !== "EEXIST") {
throw e;
}
}
// Dumps svg outputs to a folder called svgdump
function getFilePathForPage(pageNum) {
const name = path.basename(pdfPath, path.extname(pdfPath));
return path.join(outputDirectory, name + "-" + pageNum + ".svg");
}
/**
* A readable stream which offers a stream representing the serialization of a
* given DOM element (as defined by domstubs.js).
*
* @param {object} options
* @param {DOMElement} options.svgElement The element to serialize
*/
function ReadableSVGStream(options) {
if (!(this instanceof ReadableSVGStream)) {
return new ReadableSVGStream(options);
}
stream.Readable.call(this, options);
this.serializer = options.svgElement.getSerializer();
}
util.inherits(ReadableSVGStream, stream.Readable);
// Implements https://nodejs.org/api/stream.html#stream_readable_read_size_1
ReadableSVGStream.prototype._read = function () {
let chunk;
while ((chunk = this.serializer.getNext()) !== null) {
if (!this.push(chunk)) {
return;
}
}
this.push(null);
};
// Streams the SVG element to the given file path.
function writeSvgToFile(svgElement, filePath) {
let readableSvgStream = new ReadableSVGStream({
svgElement,
});
const writableStream = fs.createWriteStream(filePath);
return new Promise(function (resolve, reject) {
readableSvgStream.once("error", reject);
writableStream.once("error", reject);
writableStream.once("finish", resolve);
readableSvgStream.pipe(writableStream);
}).catch(function (err) {
readableSvgStream = null; // Explicitly null because of v8 bug 6512.
writableStream.end();
throw err;
});
}
// Will be using promises to load document, pages and misc data instead of
// callback.
const loadingTask = pdfjsLib.getDocument({
data,
cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
fontExtraProperties: true,
});
loadingTask.promise
.then(function (doc) {
const numPages = doc.numPages;
console.log("# Document Loaded");
console.log("Number of Pages: " + numPages);
console.log();
let lastPromise = Promise.resolve(); // will be used to chain promises
const loadPage = function (pageNum) {
return doc.getPage(pageNum).then(function (page) {
console.log("# Page " + pageNum);
const viewport = page.getViewport({ scale: 1.0 });
console.log("Size: " + viewport.width + "x" + viewport.height);
console.log();
return page.getOperatorList().then(function (opList) {
const svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
svgGfx.embedFonts = true;
return svgGfx.getSVG(opList, viewport).then(function (svg) {
return writeSvgToFile(svg, getFilePathForPage(pageNum)).then(
function () {
console.log("Page: " + pageNum);
},
function (err) {
console.log("Error: " + err);
}
);
});
});
});
};
for (let i = 1; i <= numPages; i++) {
lastPromise = lastPromise.then(loadPage.bind(null, i));
}
return lastPromise;
})
.then(
function () {
console.log("# End of Document");
},
function (err) {
console.error("Error: " + err);
}
);

View File

@ -0,0 +1,8 @@
## PDF.js using SVG
This is a project for implementing alternate backend for PDF.js using Scalable Vector Graphics. This is still a WIP.
Take a look at [proposal](https://docs.google.com/document/d/1k4nPx1RrHbxXi94kSdvW5ay8KMkjwLmBEiCNupyzlwk/pub) for this project.
## Getting started
Take a look at src/display/svg.js to see the SVG rendering code.

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<!--
Copyright 2014 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html dir="ltr" mozdisallowselectionprint>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate">
<title>PDF.js SVG viewer using built components</title>
<style>
body {
background-color: #808080;
margin: 0;
padding: 0;
}
#viewerContainer {
overflow: auto;
position: absolute;
width: 100%;
height: 100%;
}
</style>
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
</head>
<body tabindex="1">
<div id="viewerContainer">
<div id="viewer" class="pdfViewer"></div>
</div>
<script src="viewer.js"></script>
</body>
</html>

View File

@ -0,0 +1,70 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
// eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
}
// The workerSrc property shall be specified.
//
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
// Some PDFs need external cmaps.
//
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
const container = document.getElementById("viewerContainer");
const eventBus = new pdfjsViewer.EventBus();
// (Optionally) enable hyperlinks within PDF files.
const pdfLinkService = new pdfjsViewer.PDFLinkService({
eventBus,
});
const pdfViewer = new pdfjsViewer.PDFViewer({
container,
eventBus,
linkService: pdfLinkService,
renderer: "svg",
textLayerMode: 0,
});
pdfLinkService.setViewer(pdfViewer);
eventBus.on("pagesinit", function () {
// We can use pdfViewer now, e.g. let's change default scale.
pdfViewer.currentScaleValue = "page-width";
});
// Loading document.
const loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL,
cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
});
loadingTask.promise.then(function (pdfDocument) {
// Document loaded, specifying document for the viewer and
// the (optional) linkService.
pdfViewer.setDocument(pdfDocument);
pdfLinkService.setDocument(pdfDocument, null);
});

View File

@ -1,13 +1,14 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<title>Text-only PDF.js example</title> <title>Text-only PDF.js example</title>
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script> <script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
<script src="pdf2svg.mjs" type="module"></script> <script src="pdf2svg.js"></script>
</head> </head>
<body> <body>
<p>Text-only PDF.js example</p> <p>Text-only PDF.js example</p>
<div id="pageContainer" style="display: inline-block; border: solid 1px black"></div> <div id="pageContainer" style="display: inline-block; border: solid 1px black;">
</div>
</body> </body>
</html> </html>

View File

@ -19,7 +19,7 @@ const PAGE_SCALE = 1.5;
const SVG_NS = "http://www.w3.org/2000/svg"; const SVG_NS = "http://www.w3.org/2000/svg";
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs"; "../../node_modules/pdfjs-dist/build/pdf.worker.js";
function buildSVG(viewport, textContent) { function buildSVG(viewport, textContent) {
// Building SVG with size of the viewport (for simplicity) // Building SVG with size of the viewport (for simplicity)
@ -43,23 +43,24 @@ function buildSVG(viewport, textContent) {
text.setAttribute("transform", "matrix(" + tx.join(" ") + ")"); text.setAttribute("transform", "matrix(" + tx.join(" ") + ")");
text.setAttribute("font-family", style.fontFamily); text.setAttribute("font-family", style.fontFamily);
text.textContent = textItem.str; text.textContent = textItem.str;
svg.append(text); svg.appendChild(text);
}); });
return svg; return svg;
} }
async function pageLoaded() { function pageLoaded() {
// Loading document and page text content // Loading document and page text content
const loadingTask = pdfjsLib.getDocument({ url: PDF_PATH }); const loadingTask = pdfjsLib.getDocument({ url: PDF_PATH });
const pdfDocument = await loadingTask.promise; loadingTask.promise.then(function (pdfDocument) {
const page = await pdfDocument.getPage(PAGE_NUMBER); pdfDocument.getPage(PAGE_NUMBER).then(function (page) {
const viewport = page.getViewport({ scale: PAGE_SCALE }); const viewport = page.getViewport({ scale: PAGE_SCALE });
const textContent = await page.getTextContent(); page.getTextContent().then(function (textContent) {
// building SVG and adding that to the DOM // building SVG and adding that to the DOM
const svg = buildSVG(viewport, textContent); const svg = buildSVG(viewport, textContent);
document.getElementById("pageContainer").append(svg); document.getElementById("pageContainer").appendChild(svg);
// Release page resources. });
page.cleanup(); });
});
} }
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {

View File

@ -0,0 +1,9 @@
{
"extends": [
"../.eslintrc"
],
"env": {
"node": true,
},
}

View File

@ -27,7 +27,12 @@ otherwise the build is not guaranteed to work correctly.
## Worker loading ## Worker loading
If you are getting the `Setting up fake worker` warning, make sure you are If you are getting the `Setting up fake worker` warning, make sure you are
importing `pdfjs-dist/webpack.mjs` which is the zero-configuration method for importing `pdfjs-dist/webpack` which is the zero-configuration method for
Webpack users. Installing `worker-loader` is no longer necessary. Webpack users. You will need to install
[worker-loader](https://github.com/webpack-contrib/worker-loader) (version 3.0.0 or higher is required), as a
dependency in your project in order to use `pdfjs-dist/webpack` (configuring
`worker-loader` is not necessary; just installing it is sufficient).
import * as pdfjsLib from 'pdfjs-dist/webpack.mjs'; import * as pdfjsLib from 'pdfjs-dist/webpack';
For a full working example refer to [this repository](https://github.com/yurydelendik/pdfjs-react).

View File

@ -1,7 +1,7 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<title>webpack example</title> <title>webpack example</title>
<script src="../../build/webpack/main.bundle.js"></script> <script src="../../build/webpack/main.bundle.js"></script>
</head> </head>

35
examples/webpack/main.js Normal file
View File

@ -0,0 +1,35 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for webpack.
const pdfjsLib = require("pdfjs-dist");
const pdfPath = "../learning/helloworld.pdf";
// Setting worker path to worker bundle.
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../build/webpack/pdf.worker.bundle.js";
// Loading a document.
const loadingTask = pdfjsLib.getDocument(pdfPath);
loadingTask.promise
.then(function (pdfDocument) {
// Request a first page
return pdfDocument.getPage(1).then(function (pdfPage) {
// Display page on the existing canvas with 100% scale.
const viewport = pdfPage.getViewport({ scale: 1.0 });
const canvas = document.getElementById("theCanvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport,
});
return renderTask.promise;
});
})
.catch(function (reason) {
console.error("Error: " + reason);
});

View File

@ -1,29 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for webpack.
import * as pdfjsLib from "pdfjs-dist";
const pdfPath = "../learning/helloworld.pdf";
// Setting worker path to worker bundle.
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../build/webpack/pdf.worker.bundle.js";
// Loading a document.
const loadingTask = pdfjsLib.getDocument(pdfPath);
const pdfDocument = await loadingTask.promise;
// Request a first page
const pdfPage = await pdfDocument.getPage(1);
// Display page on the existing canvas with 100% scale.
const viewport = pdfPage.getViewport({ scale: 1.0 });
const canvas = document.getElementById("theCanvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport,
});
await renderTask.promise;

View File

@ -1,12 +1,12 @@
{ {
"name": "webpack-pdf.js-example", "name": "webpack-pdf.js-example",
"version": "0.2.0", "version": "0.1.0",
"scripts": { "scripts": {
"build": "webpack" "build": "webpack"
}, },
"devDependencies": { "devDependencies": {
"webpack": "^5.89.0", "webpack": "^5.11.1",
"webpack-cli": "^5.1.4", "webpack-cli": "^4.3.1",
"pdfjs-dist": "../../node_modules/pdfjs-dist" "pdfjs-dist": "../../node_modules/pdfjs-dist"
} }
} }

View File

@ -1,13 +1,11 @@
/* eslint-disable import/no-commonjs */
const webpack = require("webpack"); // eslint-disable-line no-unused-vars const webpack = require("webpack"); // eslint-disable-line no-unused-vars
const path = require("path"); const path = require("path");
module.exports = { module.exports = {
context: __dirname, context: __dirname,
entry: { entry: {
main: "./main.mjs", main: "./main.js",
"pdf.worker": "pdfjs-dist/build/pdf.worker.mjs", "pdf.worker": "pdfjs-dist/build/pdf.worker.entry",
}, },
mode: "none", mode: "none",
output: { output: {

View File

@ -0,0 +1,23 @@
{
"extends": [
../../.eslintrc
],
"env": {
"webextensions": true
},
"plugins": [
"mozilla"
],
"parserOptions": {
"sourceType": "script"
},
"rules": {
"mozilla/import-globals": "error",
"no-var": "off",
"object-shorthand": "off",
},
}

View File

@ -16,15 +16,16 @@ limitations under the License.
"use strict"; "use strict";
var VIEWER_URL = chrome.runtime.getURL("content/web/viewer.html"); var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
function getViewerURL(pdf_url) { function getViewerURL(pdf_url) {
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url); return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
} }
if (CSS.supports("animation", "0s")) {
document.addEventListener("animationstart", onAnimationStart, true); document.addEventListener("animationstart", onAnimationStart, true);
if (document.contentType === "application/pdf") { } else {
chrome.runtime.sendMessage({ action: "canRequestBody" }, maybeRenderPdfDoc); document.addEventListener("webkitAnimationStart", onAnimationStart, true);
} }
function onAnimationStart(event) { function onAnimationStart(event) {
@ -127,15 +128,11 @@ function updateEmbedElement(elem) {
var parentNode = elem.parentNode; var parentNode = elem.parentNode;
var nextSibling = elem.nextSibling; var nextSibling = elem.nextSibling;
if (parentNode) { if (parentNode) {
elem.remove(); parentNode.removeChild(elem);
} }
elem.type = "text/html"; elem.type = "text/html";
elem.src = getEmbeddedViewerURL(elem.src); elem.src = getEmbeddedViewerURL(elem.src);
if (parentNode) { if (parentNode) {
// Suppress linter warning: insertBefore is preferable to
// nextSibling.before(elem) because nextSibling may be null.
// eslint-disable-next-line unicorn/prefer-modern-dom-apis
parentNode.insertBefore(elem, nextSibling); parentNode.insertBefore(elem, nextSibling);
} }
} }
@ -163,7 +160,7 @@ function updateObjectElement(elem) {
if (!iframe || !iframe.__inserted_by_pdfjs) { if (!iframe || !iframe.__inserted_by_pdfjs) {
iframe = createFullSizeIframe(); iframe = createFullSizeIframe();
elem.textContent = ""; elem.textContent = "";
elem.append(iframe); elem.appendChild(iframe);
iframe.__inserted_by_pdfjs = true; iframe.__inserted_by_pdfjs = true;
} }
iframe.src = getEmbeddedViewerURL(elem.data); iframe.src = getEmbeddedViewerURL(elem.data);
@ -224,38 +221,3 @@ function getEmbeddedViewerURL(path) {
path = a.href; path = a.href;
return getViewerURL(path) + fragment; return getViewerURL(path) + fragment;
} }
function maybeRenderPdfDoc(isNotPOST) {
if (!isNotPOST) {
// The document was loaded through a POST request, but we cannot access the
// original response body, nor safely send a new request to fetch the PDF.
// Until #4483 is fixed, POST requests should be ignored.
return;
}
// Detected PDF that was not redirected by the declarativeNetRequest rules.
// Maybe because this was served without Content-Type and sniffed as PDF.
// Or because this is Chrome 127-, which does not support responseHeaders
// condition in declarativeNetRequest (DNR), and PDF requests are therefore
// not redirected via DNR.
// In any case, load the viewer.
console.log(`Detected PDF via document, opening viewer for ${document.URL}`);
// Ideally we would use logic consistent with the DNR logic, like this:
// location.href = getEmbeddedViewerURL(document.URL);
// ... unfortunately, this causes Chrome to crash until version 129, fixed by
// https://chromium.googlesource.com/chromium/src/+/8c42358b2cc549553d939efe7d36515d80563da7%5E%21/
// Work around this by replacing the body with an iframe of the viewer.
// Interestingly, Chrome's built-in PDF viewer uses a similar technique.
const shadowRoot = document.body.attachShadow({ mode: "closed" });
const iframe = document.createElement("iframe");
iframe.style.position = "absolute";
iframe.style.top = "0";
iframe.style.left = "0";
iframe.style.width = "100%";
iframe.style.height = "100%";
iframe.style.border = "0 none";
iframe.src = getEmbeddedViewerURL(document.URL);
shadowRoot.append(iframe);
}

View File

@ -1,6 +1,11 @@
/** /**
* Detect creation of <embed> and <object> tags. * Detect creation of <embed> and <object> tags.
*/ */
@-webkit-keyframes pdfjs-detected-object-or-embed {
from {
/* empty */
}
}
@keyframes pdfjs-detected-object-or-embed { @keyframes pdfjs-detected-object-or-embed {
from { from {
/* empty */ /* empty */
@ -8,6 +13,9 @@
} }
object, object,
embed { embed {
-webkit-animation-delay: 0s !important;
-webkit-animation-name: pdfjs-detected-object-or-embed !important;
-webkit-animation-play-state: running !important;
animation-delay: 0s !important; animation-delay: 0s !important;
animation-name: pdfjs-detected-object-or-embed !important; animation-name: pdfjs-detected-object-or-embed !important;
animation-play-state: running !important; animation-play-state: running !important;

View File

@ -17,12 +17,13 @@ limitations under the License.
"use strict"; "use strict";
(function ExtensionRouterClosure() { (function ExtensionRouterClosure() {
var VIEWER_URL = chrome.runtime.getURL("content/web/viewer.html"); var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
var CRX_BASE_URL = chrome.runtime.getURL("/"); var CRX_BASE_URL = chrome.extension.getURL("/");
var schemes = [ var schemes = [
"http", "http",
"https", "https",
"ftp",
"file", "file",
"chrome-extension", "chrome-extension",
"blob", "blob",
@ -46,8 +47,7 @@ limitations under the License.
} }
var scheme = url.slice(0, schemeIndex).toLowerCase(); var scheme = url.slice(0, schemeIndex).toLowerCase();
if (schemes.includes(scheme)) { if (schemes.includes(scheme)) {
// NOTE: We cannot use the `updateUrlHash` function in this context. url = url.split("#")[0];
url = url.split("#", 1)[0];
if (url.charAt(schemeIndex) === ":") { if (url.charAt(schemeIndex) === ":") {
url = encodeURIComponent(url); url = encodeURIComponent(url);
} }
@ -56,50 +56,73 @@ limitations under the License.
return undefined; return undefined;
} }
function resolveViewerURL(originalUrl) { // TODO(rob): Use declarativeWebRequest once declared URL-encoding is
if (originalUrl.startsWith(CRX_BASE_URL)) { // supported, see http://crbug.com/273589
// (or rewrite the query string parser in viewer.js to get it to
// recognize the non-URL-encoded PDF URL.)
chrome.webRequest.onBeforeRequest.addListener(
function (details) {
// This listener converts chrome-extension://.../http://...pdf to // This listener converts chrome-extension://.../http://...pdf to
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf // chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
var url = parseExtensionURL(originalUrl); var url = parseExtensionURL(details.url);
if (url) { if (url) {
url = VIEWER_URL + "?file=" + url; url = VIEWER_URL + "?file=" + url;
var i = originalUrl.indexOf("#"); var i = details.url.indexOf("#");
if (i > 0) { if (i > 0) {
url += originalUrl.slice(i); url += details.url.slice(i);
}
return url;
} }
console.log("Redirecting " + details.url + " to " + url);
return { redirectUrl: url };
} }
return undefined; return undefined;
}
self.addEventListener("fetch", event => {
const req = event.request;
if (req.destination === "document") {
var url = resolveViewerURL(req.url);
if (url) {
console.log("Redirecting " + req.url + " to " + url);
event.respondWith(Response.redirect(url));
}
}
});
// Ctrl + F5 bypasses service worker. the pretty extension URLs will fail to
// resolve in that case. Catch this and redirect to destination.
chrome.webNavigation.onErrorOccurred.addListener(
details => {
if (details.frameId !== 0) {
// Not a top-level frame. Cannot easily navigate a specific child frame.
return;
}
const url = resolveViewerURL(details.url);
if (url) {
console.log(`Redirecting ${details.url} to ${url} (fallback)`);
chrome.tabs.update(details.tabId, { url });
}
}, },
{ url: [{ urlPrefix: CRX_BASE_URL }] } {
types: ["main_frame", "sub_frame"],
urls: schemes.map(function (scheme) {
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
return CRX_BASE_URL + scheme + "*";
}),
},
["blocking"]
); );
// When session restore is used, viewer pages may be loaded before the
// webRequest event listener is attached (= page not found).
// Or the extension could have been crashed (OOM), leaving a sad tab behind.
// Reload these tabs.
chrome.tabs.query(
{
url: CRX_BASE_URL + "*:*",
},
function (tabsFromLastSession) {
for (var i = 0; i < tabsFromLastSession.length; ++i) {
chrome.tabs.reload(tabsFromLastSession[i].id);
}
}
);
console.log("Set up extension URL router."); console.log("Set up extension URL router.");
Object.keys(localStorage).forEach(function (key) {
// The localStorage item is set upon unload by chromecom.js.
var parsedKey = /^unload-(\d+)-(true|false)-(.+)/.exec(key);
if (parsedKey) {
var timeStart = parseInt(parsedKey[1], 10);
var isHidden = parsedKey[2] === "true";
var url = parsedKey[3];
if (Date.now() - timeStart < 3000) {
// Is it a new item (younger than 3 seconds)? Assume that the extension
// just reloaded, so restore the tab (work-around for crbug.com/511670).
chrome.tabs.create({
url:
chrome.runtime.getURL("restoretab.html") +
"?" +
encodeURIComponent(url) +
"#" +
encodeURIComponent(localStorage.getItem(key)),
active: !isHidden,
});
}
localStorage.removeItem(key);
}
});
})(); })();

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,6 +1,5 @@
{ {
"minimum_chrome_version": "103", "manifest_version": 2,
"manifest_version": 3,
"name": "PDF Viewer", "name": "PDF Viewer",
"version": "PDFJSSCRIPT_VERSION", "version": "PDFJSSCRIPT_VERSION",
"description": "Uses HTML5 to display PDF files directly in the browser.", "description": "Uses HTML5 to display PDF files directly in the browser.",
@ -10,52 +9,63 @@
"16": "icon16.png" "16": "icon16.png"
}, },
"permissions": [ "permissions": [
"alarms", "fileBrowserHandler",
"declarativeNetRequestWithHostAccess", "webRequest", "webRequestBlocking",
"webRequest", "<all_urls>",
"tabs", "tabs",
"webNavigation", "webNavigation",
"storage" "storage"
], ],
"host_permissions": ["<all_urls>"], "content_scripts": [{
"content_scripts": [ "matches": [
{ "http://*/*",
"matches": ["http://*/*", "https://*/*", "file://*/*"], "https://*/*",
"ftp://*/*",
"file://*/*"
],
"run_at": "document_start", "run_at": "document_start",
"all_frames": true, "all_frames": true,
"css": ["contentstyle.css"], "css": ["contentstyle.css"],
"js": ["contentscript.js"] "js": ["contentscript.js"]
} }],
], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"content_security_policy": { "file_browser_handlers": [{
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'" "id": "open-as-pdf",
}, "default_title": "Open with PDF Viewer",
"file_filters": [
"filesystem:*.pdf"
]
}],
"storage": { "storage": {
"managed_schema": "preferences_schema.json" "managed_schema": "preferences_schema.json"
}, },
"options_ui": { "options_ui": {
"page": "options/options.html" "page": "options/options.html",
"chrome_style": true
}, },
"options_page": "options/options.html", "options_page": "options/options.html",
"background": { "background": {
"service_worker": "background.js" "page": "pdfHandler.html"
},
"page_action": {
"default_icon": {
"19": "icon19.png",
"38": "icon38.png"
},
"default_title": "Show PDF URL",
"default_popup": "pageActionPopup.html"
}, },
"incognito": "split", "incognito": "split",
"web_accessible_resources": [ "web_accessible_resources": [
{
"resources": [
"content/web/viewer.html", "content/web/viewer.html",
"http:/*", "http:/*",
"https:/*", "https:/*",
"ftp:/*",
"file:/*", "file:/*",
"chrome-extension:/*", "chrome-extension:/*",
"blob:*", "blob:*",
"data:*", "data:*",
"filesystem:/*", "filesystem:/*",
"drive:*" "drive:*"
],
"matches": ["<all_urls>"],
"extension_ids": ["*"]
}
] ]
} }

View File

@ -13,14 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
"use strict"; /* eslint strict: ["error", "function"] */
chrome.runtime.onInstalled.addListener(({ reason }) => { (function () {
if (reason !== "update") { "use strict";
// We only need to run migration logic for extension updates, not for new
// installs or browser updates.
return;
}
var storageLocal = chrome.storage.local; var storageLocal = chrome.storage.local;
var storageSync = chrome.storage.sync; var storageSync = chrome.storage.sync;
@ -41,12 +37,16 @@ chrome.runtime.onInstalled.addListener(({ reason }) => {
}); });
}); });
async function getStorageNames(callback) { function getStorageNames(callback) {
var x = new XMLHttpRequest();
var schema_location = chrome.runtime.getManifest().storage.managed_schema; var schema_location = chrome.runtime.getManifest().storage.managed_schema;
var res = await fetch(chrome.runtime.getURL(schema_location)); x.open("get", chrome.runtime.getURL(schema_location));
var storageManifest = await res.json(); x.onload = function () {
var storageKeys = Object.keys(storageManifest.properties); var storageKeys = Object.keys(x.response.properties);
callback(storageKeys); callback(storageKeys);
};
x.responseType = "json";
x.send();
} }
// Save |values| to storage.sync and delete the values with that key from // Save |values| to storage.sync and delete the values with that key from
@ -109,10 +109,17 @@ chrome.runtime.onInstalled.addListener(({ reason }) => {
} }
// Migration code for https://github.com/mozilla/pdf.js/pull/9479. // Migration code for https://github.com/mozilla/pdf.js/pull/9479.
if (typeof items.disableTextLayer === "boolean") { if (typeof items.disableTextLayer === "boolean") {
var textLayerMode = 1;
if (items.disableTextLayer) { if (items.disableTextLayer) {
textLayerMode = 0;
} else if (items.enhanceTextSelection) {
textLayerMode = 2;
}
if (textLayerMode !== 1) {
// Overwrite if computed textLayerMode is not the default value (1).
storageSync.set( storageSync.set(
{ {
textLayerMode: 0, textLayerMode: textLayerMode,
}, },
function () { function () {
if (!chrome.runtime.lastError) { if (!chrome.runtime.lastError) {
@ -150,4 +157,4 @@ chrome.runtime.onInstalled.addListener(({ reason }) => {
} }
); );
} }
}); })();

View File

@ -16,51 +16,33 @@ limitations under the License.
--> -->
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<title>PDF.js viewer options</title> <title>PDF.js viewer options</title>
<style> <style>
/* TODO: Remove as much custom CSS as possible - crbug.com/446511 */
body { body {
min-width: 400px; /* a page at the settings page is at least 400px wide */ min-width: 400px; /* a page at the settings page is at least 400px wide */
margin: 14px 17px; /* already added by default in Chrome 40.0.2212.0 */ margin: 14px 17px; /* already added by default in Chrome 40.0.2212.0 */
} }
.settings-row { .settings-row {
margin: 1em 0; margin: 0.65em 0;
}
.checkbox label {
display: inline-flex;
align-items: center;
}
.checkbox label input {
flex-shrink: 0;
} }
</style> </style>
</head> </head>
<body> <body>
<div id="settings-boxes"></div> <div id="settings-boxes"></div>
<button id="reset-button" type="button">Restore default settings</button> <button id="reset-button">Restore default settings</button>
<template id="checkbox-template"> <template id="checkbox-template">
<div class="settings-row checkbox"> <!-- Chromium's style: //src/extensions/renderer/resources/extension.css -->
<div class="checkbox">
<label> <label>
<input type="checkbox" /> <input type="checkbox">
<span></span> <span></span>
</label> </label>
</div> </div>
</template> </template>
<template id="viewerCssTheme-template">
<div class="settings-row">
<label>
<span></span>
<select>
<option value="0">Use system theme</option>
<option value="1">Light theme</option>
<option value="2">Dark theme</option>
</select>
</label>
</div>
</template>
<template id="viewOnLoad-template"> <template id="viewOnLoad-template">
<div class="settings-row"> <div class="settings-row">
<label> <label>
@ -131,6 +113,7 @@ limitations under the License.
<select> <select>
<option value="0">Disable text selection</option> <option value="0">Disable text selection</option>
<option value="1">Enable text selection</option> <option value="1">Enable text selection</option>
<option value="2">Enable enhanced mode (experimental)</option>
</select> </select>
</label> </label>
</div> </div>
@ -157,7 +140,6 @@ limitations under the License.
<span></span> <span></span>
<select> <select>
<option value="-1">Default</option> <option value="-1">Default</option>
<option value="3">Page scrolling</option>
<option value="0">Vertical scrolling</option> <option value="0">Vertical scrolling</option>
<option value="1">Horizontal scrolling</option> <option value="1">Horizontal scrolling</option>
<option value="2">Wrapped scrolling</option> <option value="2">Wrapped scrolling</option>

View File

@ -155,7 +155,7 @@ function renderBooleanPref(shortDescription, description, prefName) {
storageArea.set(pref); storageArea.set(pref);
}; };
wrapper.querySelector("span").textContent = shortDescription; wrapper.querySelector("span").textContent = shortDescription;
document.getElementById("settings-boxes").append(wrapper); document.getElementById("settings-boxes").appendChild(wrapper);
function renderPreference(value) { function renderPreference(value) {
checkbox.checked = value; checkbox.checked = value;
@ -172,7 +172,7 @@ function renderEnumPref(shortDescription, prefName) {
storageArea.set(pref); storageArea.set(pref);
}; };
wrapper.querySelector("span").textContent = shortDescription; wrapper.querySelector("span").textContent = shortDescription;
document.getElementById("settings-boxes").append(wrapper); document.getElementById("settings-boxes").appendChild(wrapper);
function renderPreference(value) { function renderPreference(value) {
select.value = value; select.value = value;
@ -189,7 +189,7 @@ function renderDefaultZoomValue(shortDescription) {
}); });
}; };
wrapper.querySelector("span").textContent = shortDescription; wrapper.querySelector("span").textContent = shortDescription;
document.getElementById("settings-boxes").append(wrapper); document.getElementById("settings-boxes").appendChild(wrapper);
function renderPreference(value) { function renderPreference(value) {
value = value || "auto"; value = value || "auto";

Some files were not shown because too many files have changed in this diff Show More