Compare commits
No commits in common. "master" and "v2.13.216" have entirely different histories.
@ -1,6 +1,6 @@
|
||||
root = true
|
||||
|
||||
[*.{js,jsm,mjs,json,html,css,pdf.link}]
|
||||
[*.{js,jsm,json,html,css,pdf.link}]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
|
@ -3,10 +3,12 @@ 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/
|
||||
web/locale/
|
||||
*~/
|
||||
|
50
.eslintrc
50
.eslintrc
@ -22,27 +22,21 @@
|
||||
"browser": true,
|
||||
"es2022": true,
|
||||
"worker": true,
|
||||
"amd": true,
|
||||
},
|
||||
|
||||
"globals": {
|
||||
"PDFJSDev": "readonly",
|
||||
"__non_webpack_import__": "readonly",
|
||||
"PDFJSDev": false,
|
||||
"exports": false,
|
||||
"structuredClone": false,
|
||||
"SystemJS": false,
|
||||
},
|
||||
|
||||
"rules": {
|
||||
// Plugins
|
||||
"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-self-import": "error",
|
||||
"import/no-unresolved": ["error", {
|
||||
"ignore": ["display", "pdfjs", "pdfjs-lib", "pdfjs-web", "web", "fluent-bundle", "fluent-dom"],
|
||||
"ignore": ["pdfjs", "pdfjs-lib", "pdfjs-web"]
|
||||
}],
|
||||
"mozilla/avoid-removeChild": "error",
|
||||
"mozilla/use-includes-instead-of-indexOf": "error",
|
||||
@ -53,32 +47,12 @@
|
||||
}],
|
||||
"unicorn/no-abusive-eslint-disable": "error",
|
||||
"unicorn/no-array-push-push": "error",
|
||||
"unicorn/no-instanceof-array": "error",
|
||||
"unicorn/no-invalid-remove-event-listener": "error",
|
||||
"unicorn/no-new-buffer": "error",
|
||||
"unicorn/no-typeof-undefined": ["error", {
|
||||
"checkGlobalVariables": false,
|
||||
}],
|
||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
||||
"unicorn/no-instanceof-array": "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-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-string-replace-all": "error",
|
||||
"unicorn/prefer-string-starts-ends-with": "error",
|
||||
"unicorn/prefer-ternary": ["error", "only-single-line"],
|
||||
|
||||
// Possible errors
|
||||
"for-direction": "error",
|
||||
@ -140,12 +114,10 @@
|
||||
"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-new": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-octal": "error",
|
||||
"no-redeclare": "error",
|
||||
@ -161,7 +133,6 @@
|
||||
"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,
|
||||
@ -178,7 +149,7 @@
|
||||
"no-undef-init": "error",
|
||||
"no-undef": ["error", { "typeof": true, }],
|
||||
"no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"vars": "local",
|
||||
"args": "none",
|
||||
}],
|
||||
"no-use-before-define": ["error", {
|
||||
@ -243,9 +214,9 @@
|
||||
}],
|
||||
|
||||
// ECMAScript 6
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"constructor-super": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-confusing-arrow": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
@ -258,7 +229,6 @@
|
||||
"avoidQuotes": true,
|
||||
}],
|
||||
"prefer-const": "error",
|
||||
"require-yield": "error",
|
||||
"sort-imports": ["error", {
|
||||
"ignoreCase": true,
|
||||
}],
|
||||
|
@ -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
2
.gitattributes
vendored
@ -4,7 +4,7 @@
|
||||
*.css text eol=lf
|
||||
*.html text eol=lf
|
||||
*.md text eol=lf
|
||||
*.ftl text eol=lf
|
||||
*.properties text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.json text eol=lf
|
||||
*.config text eol=lf
|
||||
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -1 +0,0 @@
|
||||
l10n/en-US/*.ftl @mozilla/pdfjs-l10n
|
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -1,8 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "dependencies"
|
27
.github/fluent_linter_config.yml
vendored
27
.github/fluent_linter_config.yml
vendored
@ -1,27 +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: []
|
1
.github/requirements.txt
vendored
1
.github/requirements.txt
vendored
@ -1 +0,0 @@
|
||||
moz-fluent-linter==0.4.*
|
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@ -1,28 +1,18 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18, lts/*, latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
- name: Use Node.js 16 LTS
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Gulp
|
||||
run: npm install -g gulp-cli
|
||||
@ -30,8 +20,5 @@ jobs:
|
||||
- name: Install other dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run external tests
|
||||
run: gulp externaltest
|
||||
|
||||
- name: Run CLI unit tests
|
||||
run: gulp unittestcli
|
||||
- name: Run tests
|
||||
run: gulp ci-test
|
||||
|
15
.github/workflows/codeql.yml
vendored
15
.github/workflows/codeql.yml
vendored
@ -1,14 +1,13 @@
|
||||
name: CodeQL
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
@ -18,18 +17,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: security-and-quality
|
||||
|
||||
- name: Autobuild CodeQL
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
42
.github/workflows/fluent_linter.yml
vendored
42
.github/workflows/fluent_linter.yml
vendored
@ -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@v4
|
||||
|
||||
- name: Use Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
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
|
64
.github/workflows/font_tests.yml
vendored
64
.github/workflows/font_tests.yml
vendored
@ -1,64 +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@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Gulp
|
||||
run: npm install -g gulp-cli
|
||||
|
||||
- name: Install other dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Use Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install Fonttools
|
||||
run: pip install fonttools
|
||||
|
||||
- name: Run font tests
|
||||
run: gulp fonttest --headless
|
37
.github/workflows/lint.yml
vendored
37
.github/workflows/lint.yml
vendored
@ -1,37 +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@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Gulp
|
||||
run: npm install -g gulp-cli
|
||||
|
||||
- name: Install other dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run lint
|
||||
run: gulp lint
|
||||
|
||||
- name: Run lint-chromium
|
||||
run: gulp lint-chromium
|
72
.github/workflows/publish_website.yml
vendored
72
.github/workflows/publish_website.yml
vendored
@ -1,72 +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@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Gulp
|
||||
run: npm install -g gulp-cli
|
||||
|
||||
- name: Install other dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build the website
|
||||
run: 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@v4
|
||||
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
|
34
.github/workflows/types_tests.yml
vendored
34
.github/workflows/types_tests.yml
vendored
@ -1,34 +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@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Gulp
|
||||
run: npm install -g gulp-cli
|
||||
|
||||
- name: Install other dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run types tests
|
||||
run: gulp typestest
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "test/ttx/fonttools-code"]
|
||||
path = test/ttx/fonttools-code
|
||||
url = https://github.com/behdad/fonttools.git
|
@ -1,12 +0,0 @@
|
||||
build/
|
||||
l10n/
|
||||
docs/
|
||||
node_modules/
|
||||
external/bcmaps/
|
||||
external/builder/fixtures/
|
||||
external/builder/fixtures_esprima/
|
||||
external/quickjs/
|
||||
test/tmp/
|
||||
test/pdfs/
|
||||
web/locale/
|
||||
*~/
|
11
.prettierrc
11
.prettierrc
@ -5,14 +5,5 @@
|
||||
"semi": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false,
|
||||
|
||||
"overrides": [
|
||||
{
|
||||
files: ["tsconfig.json"],
|
||||
options: {
|
||||
parser: "json",
|
||||
},
|
||||
},
|
||||
]
|
||||
"useTabs": false
|
||||
}
|
||||
|
@ -3,10 +3,12 @@ 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/
|
||||
web/locale/
|
||||
*~/
|
||||
|
17
.stylelintrc
17
.stylelintrc
@ -3,23 +3,16 @@
|
||||
"stylelint-prettier"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
"prettier/prettier": true,
|
||||
"extends": [
|
||||
"stylelint-prettier/recommended"
|
||||
],
|
||||
|
||||
"alpha-value-notation": "number",
|
||||
|
||||
"rules": {
|
||||
"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, {
|
||||
ignore: ["custom-properties"]
|
||||
}],
|
||||
"selector-pseudo-element-colon-notation": "double",
|
||||
"shorthand-property-no-redundant-values": true,
|
||||
},
|
||||
}
|
||||
|
22
README.md
22
README.md
@ -14,7 +14,7 @@ get involved, visit:
|
||||
+ [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)
|
||||
+ [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
|
||||
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=good-beginner-bug&page=1&sort=created&state=open)
|
||||
+ [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)
|
||||
|
||||
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
|
||||
|
||||
Please note that the "Modern browsers" version assumes native support for the
|
||||
latest JavaScript features; please also see [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support).
|
||||
Please note that the "Modern browsers" version assumes native support for
|
||||
features such as `async`/`await`, optional chaining, nullish coalescing,
|
||||
and private `class` fields/methods.
|
||||
|
||||
+ Modern browsers: https://mozilla.github.io/pdf.js/web/viewer.html
|
||||
|
||||
@ -53,19 +54,14 @@ To get a local copy of the current code, clone it using git:
|
||||
|
||||
Next, install Node.js via the [official package](https://nodejs.org) or via
|
||||
[nvm](https://github.com/creationix/nvm). You need to install the gulp package
|
||||
globally (see also [gulp's getting started](https://github.com/gulpjs/gulp/tree/master/docs/getting-started)):
|
||||
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@^2.3.0
|
||||
|
||||
If you prefer to not install `gulp-cli` globally, you have to prefix all the `gulp` commands with `npx` (for example, `npx gulp server` instead of `gulp server`).
|
||||
$ npm install -g gulp-cli
|
||||
|
||||
If everything worked out, install all dependencies for PDF.js:
|
||||
|
||||
$ npm install
|
||||
|
||||
> [!NOTE]
|
||||
> On MacOS M1/M2 you may see some `node-gyp`-related errors when running `npm install`. This is because one of our dependencies, `"canvas"`, does not provide pre-built binaries for this platform and instead `npm` will try to build it from source. Please make sure to first install the necessary native dependencies using `brew`: https://github.com/Automattic/node-canvas#compiling.
|
||||
|
||||
Finally, you need to start a local web server as some browsers do not allow opening
|
||||
PDF files using a `file://` URL. Run:
|
||||
|
||||
@ -75,7 +71,7 @@ and then you can open:
|
||||
|
||||
+ 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:
|
||||
|
||||
@ -144,3 +140,7 @@ Talk to us on Matrix:
|
||||
File an issue:
|
||||
|
||||
+ https://github.com/mozilla/pdf.js/issues/new
|
||||
|
||||
Follow us on twitter: @pdfjs
|
||||
|
||||
+ https://twitter.com/pdfjs
|
||||
|
@ -83,17 +83,17 @@ var scaledViewport = page.getViewport({ scale: scale, });
|
||||
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.
|
||||
|
||||
<script async src="//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
|
||||
|
||||
The PDF.js can accept any decoded base64 data as an array.
|
||||
|
||||
<script async src="//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
|
||||
|
||||
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.
|
||||
|
||||
<script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/html,css,result/"></script>
|
||||
<script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/js,html,css,result/"></script>
|
||||
|
@ -37,18 +37,16 @@ Before downloading PDF.js please take a moment to understand the different layer
|
||||
|
||||
## 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="col-md-4">
|
||||
<h3>Prebuilt (modern browsers)</h3>
|
||||
<h3>Prebuilt</h3>
|
||||
<p>
|
||||
Includes the generic build of PDF.js and the viewer.
|
||||
</p>
|
||||
<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>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h3>Prebuilt (older browsers)</h3>
|
||||
<h3>Prebuilt (for older browsers)</h3>
|
||||
<p>
|
||||
Includes the generic build of PDF.js and the viewer.
|
||||
</p>
|
||||
@ -108,7 +106,8 @@ Note that we only mention the most relevant files and folders.
|
||||
│ ├── display/ - display layer
|
||||
│ ├── shared/ - shared code between the core and display layers
|
||||
│ ├── interfaces.js - interface definitions for the core/display layers
|
||||
│ └── pdf.*.js - wrapper files for bundling
|
||||
│ ├── pdf.*.js - wrapper files for bundling
|
||||
│ └── worker_loader.js - used for developer builds to load worker files
|
||||
├── test/ - unit, font, reference, and integration tests
|
||||
├── web/ - viewer layer
|
||||
├── LICENSE
|
||||
|
1
examples/browserify/.gitignore
vendored
Normal file
1
examples/browserify/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
26
examples/browserify/README.md
Normal file
26
examples/browserify/README.md
Normal 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
|
40
examples/browserify/gulpfile.js
Normal file
40
examples/browserify/gulpfile.js
Normal 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"));
|
11
examples/browserify/index.html
Normal file
11
examples/browserify/index.html
Normal 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>
|
35
examples/browserify/main.js
Normal file
35
examples/browserify/main.js
Normal 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);
|
||||
});
|
16
examples/browserify/package.json
Normal file
16
examples/browserify/package.json
Normal 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"
|
||||
}
|
||||
}
|
9
examples/browserify/worker.js
Normal file
9
examples/browserify/worker.js
Normal 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");
|
@ -31,13 +31,13 @@ limitations under the License.
|
||||
|
||||
<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/web/pdf_viewer.mjs" type="module"></script>
|
||||
<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="pageContainer" class="pdfViewer singlePageView"></div>
|
||||
|
||||
<script src="pageviewer.mjs" type="module"></script>
|
||||
<script src="pageviewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
74
examples/components/pageviewer.js
Normal file
74
examples/components/pageviewer.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* 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.PDFPageView) {
|
||||
// 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 PAGE_TO_VIEW = 1;
|
||||
const SCALE = 1.0;
|
||||
|
||||
const ENABLE_XFA = true;
|
||||
|
||||
const container = document.getElementById("pageContainer");
|
||||
|
||||
const eventBus = new pdfjsViewer.EventBus();
|
||||
|
||||
// Loading document.
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
url: DEFAULT_URL,
|
||||
cMapUrl: CMAP_URL,
|
||||
cMapPacked: CMAP_PACKED,
|
||||
enableXfa: ENABLE_XFA,
|
||||
});
|
||||
(async function () {
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Document loaded, retrieving the page.
|
||||
const pdfPage = await pdfDocument.getPage(PAGE_TO_VIEW);
|
||||
// Creating the page view with default parameters.
|
||||
const pdfPageView = new pdfjsViewer.PDFPageView({
|
||||
container,
|
||||
id: PAGE_TO_VIEW,
|
||||
scale: SCALE,
|
||||
defaultViewport: pdfPage.getViewport({ scale: SCALE }),
|
||||
eventBus,
|
||||
// We can enable text/annotation/xfa/struct-layers, as needed.
|
||||
textLayerFactory: !pdfDocument.isPureXfa
|
||||
? new pdfjsViewer.DefaultTextLayerFactory()
|
||||
: null,
|
||||
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||
xfaLayerFactory: pdfDocument.isPureXfa
|
||||
? new pdfjsViewer.DefaultXfaLayerFactory()
|
||||
: null,
|
||||
structTreeLayerFactory: new pdfjsViewer.DefaultStructTreeLayerFactory(),
|
||||
});
|
||||
// Associate the actual page with the view, and draw it.
|
||||
pdfPageView.setPdfPage(pdfPage);
|
||||
return pdfPageView.draw();
|
||||
})();
|
@ -37,8 +37,8 @@ limitations under the License.
|
||||
|
||||
<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/web/pdf_viewer.mjs" type="module"></script>
|
||||
<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">
|
||||
@ -46,6 +46,6 @@ limitations under the License.
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
|
||||
<script src="simpleviewer.mjs" type="module"></script>
|
||||
<script src="simpleviewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,6 +13,8 @@
|
||||
* 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`");
|
||||
@ -21,7 +23,7 @@ if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
@ -35,10 +37,7 @@ const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
const ENABLE_XFA = true;
|
||||
const SEARCH_FOR = ""; // try "Mozilla";
|
||||
|
||||
const SANDBOX_BUNDLE_SRC = new URL(
|
||||
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs",
|
||||
window.location
|
||||
);
|
||||
const SANDBOX_BUNDLE_SRC = "../../node_modules/pdfjs-dist/build/pdf.sandbox.js";
|
||||
|
||||
const container = document.getElementById("viewerContainer");
|
||||
|
||||
@ -67,6 +66,7 @@ const pdfViewer = new pdfjsViewer.PDFViewer({
|
||||
linkService: pdfLinkService,
|
||||
findController: pdfFindController,
|
||||
scriptingManager: pdfScriptingManager,
|
||||
enableScripting: true, // Only necessary in PDF.js version 2.10.377 and below.
|
||||
});
|
||||
pdfLinkService.setViewer(pdfViewer);
|
||||
pdfScriptingManager.setViewer(pdfViewer);
|
||||
@ -77,7 +77,11 @@ eventBus.on("pagesinit", function () {
|
||||
|
||||
// We can try searching for things.
|
||||
if (SEARCH_FOR) {
|
||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
||||
if (!pdfFindController._onFind) {
|
||||
pdfFindController.executeCommand("find", { query: SEARCH_FOR });
|
||||
} else {
|
||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -88,10 +92,11 @@ const loadingTask = pdfjsLib.getDocument({
|
||||
cMapPacked: CMAP_PACKED,
|
||||
enableXfa: ENABLE_XFA,
|
||||
});
|
||||
(async function () {
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Document loaded, specifying document for the viewer and
|
||||
// the (optional) linkService.
|
||||
pdfViewer.setDocument(pdfDocument);
|
||||
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Document loaded, specifying document for the viewer and
|
||||
// the (optional) linkService.
|
||||
pdfViewer.setDocument(pdfDocument);
|
||||
|
||||
pdfLinkService.setDocument(pdfDocument, null);
|
||||
pdfLinkService.setDocument(pdfDocument, null);
|
||||
})();
|
@ -37,8 +37,8 @@ limitations under the License.
|
||||
|
||||
<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/web/pdf_viewer.mjs" type="module"></script>
|
||||
<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">
|
||||
@ -46,6 +46,6 @@ limitations under the License.
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
|
||||
<script src="singlepageviewer.mjs" type="module"></script>
|
||||
<script src="singlepageviewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,6 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
|
||||
// eslint-disable-next-line no-alert
|
||||
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.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
@ -35,10 +37,7 @@ const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
const ENABLE_XFA = true;
|
||||
const SEARCH_FOR = ""; // try "Mozilla";
|
||||
|
||||
const SANDBOX_BUNDLE_SRC = new URL(
|
||||
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs",
|
||||
window.location
|
||||
);
|
||||
const SANDBOX_BUNDLE_SRC = "../../node_modules/pdfjs-dist/build/pdf.sandbox.js";
|
||||
|
||||
const container = document.getElementById("viewerContainer");
|
||||
|
||||
@ -67,6 +66,7 @@ const pdfSinglePageViewer = new pdfjsViewer.PDFSinglePageViewer({
|
||||
linkService: pdfLinkService,
|
||||
findController: pdfFindController,
|
||||
scriptingManager: pdfScriptingManager,
|
||||
enableScripting: true, // Only necessary in PDF.js version 2.10.377 and below.
|
||||
});
|
||||
pdfLinkService.setViewer(pdfSinglePageViewer);
|
||||
pdfScriptingManager.setViewer(pdfSinglePageViewer);
|
||||
@ -77,7 +77,11 @@ eventBus.on("pagesinit", function () {
|
||||
|
||||
// We can try searching for things.
|
||||
if (SEARCH_FOR) {
|
||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
||||
if (!pdfFindController._onFind) {
|
||||
pdfFindController.executeCommand("find", { query: SEARCH_FOR });
|
||||
} else {
|
||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -88,10 +92,10 @@ const loadingTask = pdfjsLib.getDocument({
|
||||
cMapPacked: CMAP_PACKED,
|
||||
enableXfa: ENABLE_XFA,
|
||||
});
|
||||
loadingTask.promise.then(function (pdfDocument) {
|
||||
// Document loaded, specifying document for the viewer and
|
||||
// the (optional) linkService.
|
||||
pdfSinglePageViewer.setDocument(pdfDocument);
|
||||
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Document loaded, specifying document for the viewer and
|
||||
// the (optional) linkService.
|
||||
pdfSinglePageViewer.setDocument(pdfDocument);
|
||||
|
||||
pdfLinkService.setDocument(pdfDocument, null);
|
||||
pdfLinkService.setDocument(pdfDocument, null);
|
||||
});
|
@ -29,12 +29,12 @@ limitations under the License.
|
||||
}
|
||||
</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>
|
||||
|
||||
<body tabindex="1">
|
||||
<canvas id="jpegCanvas" width="0" height="0"></canvas>
|
||||
|
||||
<script src="jpeg_viewer.mjs" type="module"></script>
|
||||
<script src="jpeg_viewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
63
examples/image_decoders/jpeg_viewer.js
Normal file
63
examples/image_decoders/jpeg_viewer.js
Normal file
@ -0,0 +1,63 @@
|
||||
/* Copyright 2018 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 (!pdfjsImageDecoders.JpegImage) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert("Please build the pdfjs-dist library using `gulp dist-install`");
|
||||
}
|
||||
|
||||
const JPEG_IMAGE = "fish.jpg";
|
||||
|
||||
const jpegCanvas = document.getElementById("jpegCanvas");
|
||||
const jpegCtx = jpegCanvas.getContext("2d");
|
||||
|
||||
(async function () {
|
||||
// Load the image data, and convert it to a Uint8Array.
|
||||
//
|
||||
const response = await fetch(JPEG_IMAGE);
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
const typedArrayImage = new Uint8Array(await response.arrayBuffer());
|
||||
|
||||
// Parse the image data using `JpegImage`.
|
||||
//
|
||||
const jpegImage = new pdfjsImageDecoders.JpegImage();
|
||||
jpegImage.parse(typedArrayImage);
|
||||
|
||||
const width = jpegImage.width,
|
||||
height = jpegImage.height;
|
||||
const jpegData = jpegImage.getData({
|
||||
width,
|
||||
height,
|
||||
forceRGB: true,
|
||||
});
|
||||
|
||||
// Render the JPEG image on a <canvas>.
|
||||
//
|
||||
const imageData = jpegCtx.createImageData(width, height);
|
||||
const imageBytes = imageData.data;
|
||||
for (let j = 0, k = 0, jj = width * height * 4; j < jj; ) {
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = 255;
|
||||
}
|
||||
jpegCanvas.width = width;
|
||||
jpegCanvas.height = height;
|
||||
jpegCtx.putImageData(imageData, 0, 0);
|
||||
})();
|
@ -1,59 +0,0 @@
|
||||
/* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
if (!pdfjsImageDecoders.JpegImage) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert("Please build the pdfjs-dist library using `gulp dist-install`");
|
||||
}
|
||||
|
||||
const JPEG_IMAGE = "fish.jpg";
|
||||
|
||||
const jpegCanvas = document.getElementById("jpegCanvas");
|
||||
const jpegCtx = jpegCanvas.getContext("2d");
|
||||
|
||||
// Load the image data, and convert it to a Uint8Array.
|
||||
//
|
||||
const response = await fetch(JPEG_IMAGE);
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
const typedArrayImage = new Uint8Array(await response.arrayBuffer());
|
||||
|
||||
// Parse the image data using `JpegImage`.
|
||||
//
|
||||
const jpegImage = new pdfjsImageDecoders.JpegImage();
|
||||
jpegImage.parse(typedArrayImage);
|
||||
|
||||
const width = jpegImage.width,
|
||||
height = jpegImage.height;
|
||||
const jpegData = jpegImage.getData({
|
||||
width,
|
||||
height,
|
||||
forceRGB: true,
|
||||
});
|
||||
|
||||
// Render the JPEG image on a <canvas>.
|
||||
//
|
||||
const imageData = jpegCtx.createImageData(width, height);
|
||||
const imageBytes = imageData.data;
|
||||
for (let j = 0, k = 0, jj = width * height * 4; j < jj; ) {
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = jpegData[k++];
|
||||
imageBytes[j++] = 255;
|
||||
}
|
||||
jpegCanvas.width = width;
|
||||
jpegCanvas.height = height;
|
||||
jpegCtx.putImageData(imageData, 0, 0);
|
@ -10,9 +10,9 @@
|
||||
|
||||
<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
|
||||
// header on that server.
|
||||
@ -23,46 +23,48 @@
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
|
||||
//
|
||||
// Asynchronous download PDF
|
||||
//
|
||||
const loadingTask = pdfjsLib.getDocument(url);
|
||||
const pdf = await loadingTask.promise;
|
||||
//
|
||||
// Fetch the first page
|
||||
//
|
||||
const page = await pdf.getPage(1);
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({ scale });
|
||||
// Support HiDPI-screens.
|
||||
const outputScale = window.devicePixelRatio || 1;
|
||||
(async () => {
|
||||
const pdf = await loadingTask.promise;
|
||||
//
|
||||
// Fetch the first page
|
||||
//
|
||||
const page = await pdf.getPage(1);
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({ scale });
|
||||
// Support HiDPI-screens.
|
||||
const outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
//
|
||||
// Prepare canvas using PDF page dimensions
|
||||
//
|
||||
const canvas = document.getElementById("the-canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
//
|
||||
// Prepare canvas using PDF page dimensions
|
||||
//
|
||||
const canvas = document.getElementById("the-canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
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";
|
||||
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";
|
||||
|
||||
const transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
const transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
|
@ -10,9 +10,9 @@
|
||||
|
||||
<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.
|
||||
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
|
||||
// Base64_encoding_and_decoding.)
|
||||
@ -35,39 +35,41 @@
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
|
||||
// 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.
|
||||
var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
|
||||
var pdf = await loadingTask.promise;
|
||||
// Fetch the first page.
|
||||
var page = await pdf.getPage(1);
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
(async function() {
|
||||
var pdf = await loadingTask.promise;
|
||||
// Fetch the first page.
|
||||
var page = await pdf.getPage(1);
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
// Prepare canvas using PDF page dimensions.
|
||||
var canvas = document.getElementById('the-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
// Prepare canvas using PDF page dimensions.
|
||||
var canvas = document.getElementById('the-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
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";
|
||||
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;
|
||||
var transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
|
||||
// Render PDF page into canvas context.
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
// Render PDF page into canvas context.
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
|
@ -19,9 +19,9 @@
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
||||
</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
|
||||
// header on that server.
|
||||
@ -34,7 +34,7 @@
|
||||
// shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||
|
||||
var pdfDoc = null,
|
||||
pageNum = 1,
|
||||
@ -90,7 +90,7 @@
|
||||
|
||||
/**
|
||||
* If another page rendering in progress, waits until the rendering is
|
||||
* finished. Otherwise, executes rendering immediately.
|
||||
* finised. Otherwise, executes rendering immediately.
|
||||
*/
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
@ -128,11 +128,13 @@
|
||||
* Asynchronously downloads PDF.
|
||||
*/
|
||||
var loadingTask = pdfjsLib.getDocument(url);
|
||||
pdfDoc = await loadingTask.promise;
|
||||
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
||||
loadingTask.promise.then(function(pdfDoc_) {
|
||||
pdfDoc = pdfDoc_;
|
||||
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
||||
|
||||
// Initial/first page rendering
|
||||
renderPage(pageNum);
|
||||
// Initial/first page rendering
|
||||
renderPage(pageNum);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -26,12 +26,12 @@ html {
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: rgb(244 244 244 / 1);
|
||||
background-color: rgba(244, 244, 244, 1);
|
||||
}
|
||||
|
||||
header h1 {
|
||||
border-bottom: 1px solid rgb(216 216 216 / 1);
|
||||
color: rgb(133 133 133 / 1);
|
||||
border-bottom: 1px solid rgba(216, 216, 216, 1);
|
||||
color: rgba(133, 133, 133, 1);
|
||||
font-size: 23px;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
@ -44,7 +44,7 @@ header h1 {
|
||||
|
||||
body {
|
||||
background: url(images/document_bg.png);
|
||||
color: rgb(255 255 255 / 1);
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-family: sans-serif;
|
||||
font-size: 10px;
|
||||
height: 100%;
|
||||
@ -71,7 +71,7 @@ footer {
|
||||
left: 0;
|
||||
right: 0;
|
||||
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 {
|
||||
@ -81,7 +81,7 @@ footer {
|
||||
border-width: 0;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: rgb(0 0 0 / 0);
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.toolbarButton.pageUp {
|
||||
@ -110,9 +110,9 @@ footer {
|
||||
left: 36%;
|
||||
text-align: center;
|
||||
border: 0;
|
||||
background-color: rgb(0 0 0 / 0);
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
font-size: 1.2rem;
|
||||
color: rgb(255 255 255 / 1);
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: url(images/div_line_left.png),
|
||||
url(images/div_line_right.png);
|
||||
background-repeat: no-repeat;
|
||||
@ -153,7 +153,10 @@ footer {
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
inset: 5rem 0 4rem;
|
||||
top: 5rem;
|
||||
bottom: 4rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
@ -184,47 +187,41 @@ canvas {
|
||||
}
|
||||
|
||||
#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;
|
||||
height: 0.6rem;
|
||||
background-color: rgb(51 51 51 / 1);
|
||||
border-bottom: 1px solid rgb(51 51 51 / 1);
|
||||
background-color: rgba(51, 51, 51, 1);
|
||||
border-bottom: 1px solid rgba(51, 51, 51, 1);
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
#loadingBar .progress {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: scaleX(var(--progressBar-percent));
|
||||
transform-origin: 0 0;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background-color: rgb(221 221 221 / 1);
|
||||
background-color: rgba(221, 221, 221, 1);
|
||||
overflow: hidden;
|
||||
transition: transform 200ms;
|
||||
transition: width 200ms;
|
||||
}
|
||||
|
||||
@keyframes progressIndeterminate {
|
||||
0% {
|
||||
transform: translateX(0%);
|
||||
left: 0;
|
||||
}
|
||||
50% {
|
||||
transform: translateX(100%);
|
||||
left: 100%;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#loadingBar.indeterminate .progress {
|
||||
transform: none;
|
||||
background-color: rgb(153 153 153 / 1);
|
||||
#loadingBar .progress.indeterminate {
|
||||
background-color: rgba(153, 153, 153, 1);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#loadingBar.indeterminate .progress .glimmer {
|
||||
#loadingBar .indeterminate .glimmer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -232,11 +229,39 @@ canvas {
|
||||
width: 5rem;
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
rgb(153 153 153 / 1) 0%,
|
||||
rgb(255 255 255 / 1) 50%,
|
||||
rgb(153 153 153 / 1) 100%
|
||||
rgba(153, 153, 153, 1) 0%,
|
||||
rgba(255, 255, 255, 1) 50%,
|
||||
rgba(153, 153, 153, 1) 100%
|
||||
);
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
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%;
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ limitations under the License.
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_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/web/pdf_viewer.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -42,6 +42,25 @@ limitations under the License.
|
||||
<div class="glimmer"></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>
|
||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous"></button>
|
||||
<button class="toolbarButton pageDown" title="Next Page" id="next"></button>
|
||||
@ -52,6 +71,6 @@ limitations under the License.
|
||||
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
|
||||
</footer>
|
||||
|
||||
<script src="viewer.mjs" type="module"></script>
|
||||
<script src="viewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,19 +13,21 @@
|
||||
* 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`");
|
||||
}
|
||||
|
||||
const MAX_CANVAS_PIXELS = 0; // CSS-only zooming.
|
||||
const USE_ONLY_CSS_ZOOM = true;
|
||||
const TEXT_LAYER_MODE = 0; // DISABLE
|
||||
const MAX_IMAGE_SIZE = 1024 * 1024;
|
||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
const CMAP_PACKED = true;
|
||||
|
||||
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_SCALE_DELTA = 1.1;
|
||||
@ -80,24 +82,46 @@ const PDFViewerApplication = {
|
||||
self.pdfDocument = pdfDocument;
|
||||
self.pdfViewer.setDocument(pdfDocument);
|
||||
self.pdfLinkService.setDocument(pdfDocument);
|
||||
self.pdfHistory.initialize({
|
||||
fingerprint: pdfDocument.fingerprints[0],
|
||||
});
|
||||
self.pdfHistory.initialize({ fingerprint: pdfDocument.fingerprint });
|
||||
|
||||
self.loadingBar.hide();
|
||||
self.setTitleUsingMetadata(pdfDocument);
|
||||
},
|
||||
function (reason) {
|
||||
let key = "pdfjs-loading-error";
|
||||
if (reason instanceof pdfjsLib.InvalidPDFException) {
|
||||
key = "pdfjs-invalid-file-error";
|
||||
} else if (reason instanceof pdfjsLib.MissingPDFException) {
|
||||
key = "pdfjs-missing-file-error";
|
||||
} else if (reason instanceof pdfjsLib.UnexpectedResponseException) {
|
||||
key = "pdfjs-unexpected-response-error";
|
||||
function (exception) {
|
||||
const message = exception && exception.message;
|
||||
const l10n = self.l10n;
|
||||
let loadingErrorMessage;
|
||||
|
||||
if (exception instanceof pdfjsLib.InvalidPDFException) {
|
||||
// change error message also for other builds
|
||||
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();
|
||||
}
|
||||
@ -110,6 +134,9 @@ const PDFViewerApplication = {
|
||||
* destruction is completed.
|
||||
*/
|
||||
close() {
|
||||
const errorWrapper = document.getElementById("errorWrapper");
|
||||
errorWrapper.hidden = true;
|
||||
|
||||
if (!this.pdfLoadingTask) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@ -132,12 +159,9 @@ const PDFViewerApplication = {
|
||||
},
|
||||
|
||||
get loadingBar() {
|
||||
const bar = document.getElementById("loadingBar");
|
||||
return pdfjsLib.shadow(
|
||||
this,
|
||||
"loadingBar",
|
||||
new pdfjsViewer.ProgressBar(bar)
|
||||
);
|
||||
const bar = new pdfjsViewer.ProgressBar("#loadingBar", {});
|
||||
|
||||
return pdfjsLib.shadow(this, "loadingBar", bar);
|
||||
},
|
||||
|
||||
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
||||
@ -145,7 +169,7 @@ const PDFViewerApplication = {
|
||||
let title = pdfjsLib.getFilenameFromUrl(url) || url;
|
||||
try {
|
||||
title = decodeURIComponent(title);
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// decodeURIComponent may throw URIError,
|
||||
// fall back to using the unprocessed url in that case
|
||||
}
|
||||
@ -163,7 +187,7 @@ const PDFViewerApplication = {
|
||||
// Provides some basic debug information
|
||||
console.log(
|
||||
"PDF " +
|
||||
pdfDocument.fingerprints[0] +
|
||||
pdfDocument.fingerprint +
|
||||
" [" +
|
||||
info.PDFFormatVersion +
|
||||
" " +
|
||||
@ -202,25 +226,79 @@ const PDFViewerApplication = {
|
||||
},
|
||||
|
||||
error: function pdfViewError(message, moreInfo) {
|
||||
const l10n = this.l10n;
|
||||
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) {
|
||||
moreInfoText.push(`Stack: ${moreInfo.stack}`);
|
||||
moreInfoText.push(
|
||||
l10n.get("error_stack", { stack: moreInfo.stack }, "Stack: {{stack}}")
|
||||
);
|
||||
} else {
|
||||
if (moreInfo.filename) {
|
||||
moreInfoText.push(`File: ${moreInfo.filename}`);
|
||||
moreInfoText.push(
|
||||
l10n.get(
|
||||
"error_file",
|
||||
{ file: moreInfo.filename },
|
||||
"File: {{file}}"
|
||||
)
|
||||
);
|
||||
}
|
||||
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) {
|
||||
@ -272,7 +350,7 @@ const PDFViewerApplication = {
|
||||
});
|
||||
this.pdfLinkService = linkService;
|
||||
|
||||
this.l10n = new pdfjsViewer.GenericL10n();
|
||||
this.l10n = pdfjsViewer.NullL10n;
|
||||
|
||||
const container = document.getElementById("viewerContainer");
|
||||
const pdfViewer = new pdfjsViewer.PDFViewer({
|
||||
@ -280,7 +358,7 @@ const PDFViewerApplication = {
|
||||
eventBus,
|
||||
linkService,
|
||||
l10n: this.l10n,
|
||||
maxCanvasPixels: MAX_CANVAS_PIXELS,
|
||||
useOnlyCssZoom: USE_ONLY_CSS_ZOOM,
|
||||
textLayerMode: TEXT_LAYER_MODE,
|
||||
});
|
||||
this.pdfViewer = pdfViewer;
|
276
examples/node/domstubs.js
Normal file
276
examples/node/domstubs.js
Normal 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 += "&";
|
||||
break;
|
||||
case "<":
|
||||
buf += "<";
|
||||
break;
|
||||
case '"':
|
||||
buf += """;
|
||||
break;
|
||||
case "\n":
|
||||
buf += "
";
|
||||
break;
|
||||
case "\r":
|
||||
buf += "
";
|
||||
break;
|
||||
case "\t":
|
||||
buf += "	";
|
||||
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];
|
||||
});
|
||||
};
|
@ -3,10 +3,12 @@
|
||||
|
||||
//
|
||||
// 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.
|
||||
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
|
||||
const pdfPath =
|
||||
@ -14,7 +16,7 @@ const pdfPath =
|
||||
|
||||
// Will be using promises to load document, pages and misc data instead of
|
||||
// callback.
|
||||
const loadingTask = getDocument(pdfPath);
|
||||
const loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||
loadingTask.promise
|
||||
.then(function (doc) {
|
||||
const numPages = doc.numPages;
|
@ -13,13 +13,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { strict as assert } from "assert";
|
||||
import Canvas from "canvas";
|
||||
import fs from "fs";
|
||||
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
||||
const Canvas = require("canvas");
|
||||
const assert = require("assert").strict;
|
||||
const fs = require("fs");
|
||||
|
||||
class NodeCanvasFactory {
|
||||
create(width, height) {
|
||||
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");
|
||||
@ -27,16 +27,16 @@ class NodeCanvasFactory {
|
||||
canvas,
|
||||
context,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
reset(canvasAndContext, width, height) {
|
||||
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(canvasAndContext) {
|
||||
destroy: function NodeCanvasFactory_destroy(canvasAndContext) {
|
||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
||||
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
@ -45,8 +45,10 @@ class NodeCanvasFactory {
|
||||
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/";
|
||||
@ -56,51 +58,54 @@ const CMAP_PACKED = true;
|
||||
const STANDARD_FONT_DATA_URL =
|
||||
"../../../node_modules/pdfjs-dist/standard_fonts/";
|
||||
|
||||
const canvasFactory = new NodeCanvasFactory();
|
||||
|
||||
// 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({
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
data,
|
||||
cMapUrl: CMAP_URL,
|
||||
cMapPacked: CMAP_PACKED,
|
||||
standardFontDataUrl: STANDARD_FONT_DATA_URL,
|
||||
canvasFactory,
|
||||
});
|
||||
|
||||
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 viewport = page.getViewport({ scale: 1.0 });
|
||||
const canvasAndContext = canvasFactory.create(
|
||||
viewport.width,
|
||||
viewport.height
|
||||
);
|
||||
const renderContext = {
|
||||
canvasContext: canvasAndContext.context,
|
||||
viewport,
|
||||
};
|
||||
(async function () {
|
||||
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 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);
|
||||
await renderTask.promise;
|
||||
// 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.");
|
||||
}
|
||||
});
|
||||
// Release page resources.
|
||||
page.cleanup();
|
||||
} catch (reason) {
|
||||
console.log(reason);
|
||||
}
|
||||
const renderTask = page.render(renderContext);
|
||||
await renderTask.promise;
|
||||
// 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."
|
||||
);
|
||||
}
|
||||
});
|
||||
// Release page resources.
|
||||
page.cleanup();
|
||||
} catch (reason) {
|
||||
console.log(reason);
|
||||
}
|
||||
})();
|
128
examples/node/pdf2svg.js
Normal file
128
examples/node/pdf2svg.js
Normal file
@ -0,0 +1,128 @@
|
||||
/* 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 async/await to load document, pages and misc data.
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
data,
|
||||
cMapUrl: CMAP_URL,
|
||||
cMapPacked: CMAP_PACKED,
|
||||
fontExtraProperties: true,
|
||||
});
|
||||
(async function () {
|
||||
const doc = await loadingTask.promise;
|
||||
const numPages = doc.numPages;
|
||||
console.log("# Document Loaded");
|
||||
console.log(`Number of Pages: ${numPages}`);
|
||||
console.log();
|
||||
|
||||
for (let pageNum = 1; pageNum <= numPages; pageNum++) {
|
||||
try {
|
||||
const page = await doc.getPage(pageNum);
|
||||
console.log(`# Page ${pageNum}`);
|
||||
const viewport = page.getViewport({ scale: 1.0 });
|
||||
console.log(`Size: ${viewport.width}x${viewport.height}`);
|
||||
console.log();
|
||||
|
||||
const opList = await page.getOperatorList();
|
||||
const svgGfx = new pdfjsLib.SVGGraphics(
|
||||
page.commonObjs,
|
||||
page.objs,
|
||||
/* forceDataSchema = */ true
|
||||
);
|
||||
svgGfx.embedFonts = true;
|
||||
const svg = await svgGfx.getSVG(opList, viewport);
|
||||
await writeSvgToFile(svg, getFilePathForPage(pageNum));
|
||||
// Release page resources.
|
||||
page.cleanup();
|
||||
} catch (err) {
|
||||
console.log(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
console.log("# End of Document");
|
||||
})();
|
8
examples/svgviewer/README.md
Normal file
8
examples/svgviewer/README.md
Normal 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.
|
51
examples/svgviewer/index.html
Normal file
51
examples/svgviewer/index.html
Normal 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>
|
@ -13,7 +13,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
|
||||
"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`");
|
||||
}
|
||||
@ -21,7 +23,7 @@ if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
//
|
||||
@ -29,35 +31,40 @@ const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
const CMAP_PACKED = true;
|
||||
|
||||
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
const PAGE_TO_VIEW = 1;
|
||||
const SCALE = 1.0;
|
||||
|
||||
const ENABLE_XFA = true;
|
||||
|
||||
const container = document.getElementById("pageContainer");
|
||||
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,
|
||||
enableXfa: ENABLE_XFA,
|
||||
});
|
||||
loadingTask.promise.then(function (pdfDocument) {
|
||||
// Document loaded, specifying document for the viewer and
|
||||
// the (optional) linkService.
|
||||
pdfViewer.setDocument(pdfDocument);
|
||||
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Document loaded, retrieving the page.
|
||||
const pdfPage = await pdfDocument.getPage(PAGE_TO_VIEW);
|
||||
|
||||
// Creating the page view with default parameters.
|
||||
const pdfPageView = new pdfjsViewer.PDFPageView({
|
||||
container,
|
||||
id: PAGE_TO_VIEW,
|
||||
scale: SCALE,
|
||||
defaultViewport: pdfPage.getViewport({ scale: SCALE }),
|
||||
eventBus,
|
||||
pdfLinkService.setDocument(pdfDocument, null);
|
||||
});
|
||||
// Associate the actual page with the view, and draw it.
|
||||
pdfPageView.setPdfPage(pdfPage);
|
||||
pdfPageView.draw();
|
@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Text-only PDF.js example</title>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="pdf2svg.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||
<script src="pdf2svg.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Text-only PDF.js example</p>
|
||||
|
@ -19,7 +19,7 @@ const PAGE_SCALE = 1.5;
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
|
||||
|
||||
function buildSVG(viewport, textContent) {
|
||||
// Building SVG with size of the viewport (for simplicity)
|
||||
@ -43,7 +43,7 @@ function buildSVG(viewport, textContent) {
|
||||
text.setAttribute("transform", "matrix(" + tx.join(" ") + ")");
|
||||
text.setAttribute("font-family", style.fontFamily);
|
||||
text.textContent = textItem.str;
|
||||
svg.append(text);
|
||||
svg.appendChild(text);
|
||||
});
|
||||
return svg;
|
||||
}
|
||||
@ -57,7 +57,7 @@ async function pageLoaded() {
|
||||
const textContent = await page.getTextContent();
|
||||
// building SVG and adding that to the DOM
|
||||
const svg = buildSVG(viewport, textContent);
|
||||
document.getElementById("pageContainer").append(svg);
|
||||
document.getElementById("pageContainer").appendChild(svg);
|
||||
// Release page resources.
|
||||
page.cleanup();
|
||||
}
|
@ -27,7 +27,12 @@ otherwise the build is not guaranteed to work correctly.
|
||||
## Worker loading
|
||||
|
||||
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
|
||||
Webpack users. Installing `worker-loader` is no longer necessary.
|
||||
importing `pdfjs-dist/webpack` which is the zero-configuration method for
|
||||
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).
|
||||
|
35
examples/webpack/main.js
Normal file
35
examples/webpack/main.js
Normal 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);
|
||||
});
|
@ -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;
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "webpack-pdf.js-example",
|
||||
"version": "0.2.0",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"build": "webpack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack": "^5.11.1",
|
||||
"webpack-cli": "^4.3.1",
|
||||
"pdfjs-dist": "../../node_modules/pdfjs-dist"
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
|
||||
const webpack = require("webpack"); // eslint-disable-line no-unused-vars
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
entry: {
|
||||
main: "./main.mjs",
|
||||
"pdf.worker": "pdfjs-dist/build/pdf.worker.mjs",
|
||||
main: "./main.js",
|
||||
"pdf.worker": "pdfjs-dist/build/pdf.worker.entry",
|
||||
},
|
||||
mode: "none",
|
||||
output: {
|
||||
|
@ -22,7 +22,11 @@ function getViewerURL(pdf_url) {
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
||||
}
|
||||
|
||||
document.addEventListener("animationstart", onAnimationStart, true);
|
||||
if (CSS.supports("animation", "0s")) {
|
||||
document.addEventListener("animationstart", onAnimationStart, true);
|
||||
} else {
|
||||
document.addEventListener("webkitAnimationStart", onAnimationStart, true);
|
||||
}
|
||||
|
||||
function onAnimationStart(event) {
|
||||
if (event.animationName === "pdfjs-detected-object-or-embed") {
|
||||
@ -128,11 +132,7 @@ function updateEmbedElement(elem) {
|
||||
}
|
||||
elem.type = "text/html";
|
||||
elem.src = getEmbeddedViewerURL(elem.src);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ function updateObjectElement(elem) {
|
||||
if (!iframe || !iframe.__inserted_by_pdfjs) {
|
||||
iframe = createFullSizeIframe();
|
||||
elem.textContent = "";
|
||||
elem.append(iframe);
|
||||
elem.appendChild(iframe);
|
||||
iframe.__inserted_by_pdfjs = true;
|
||||
}
|
||||
iframe.src = getEmbeddedViewerURL(elem.data);
|
||||
|
@ -1,6 +1,11 @@
|
||||
/**
|
||||
* Detect creation of <embed> and <object> tags.
|
||||
*/
|
||||
@-webkit-keyframes pdfjs-detected-object-or-embed {
|
||||
from {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
@keyframes pdfjs-detected-object-or-embed {
|
||||
from {
|
||||
/* empty */
|
||||
@ -8,6 +13,9 @@
|
||||
}
|
||||
object,
|
||||
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-name: pdfjs-detected-object-or-embed !important;
|
||||
animation-play-state: running !important;
|
||||
|
@ -47,7 +47,7 @@ limitations under the License.
|
||||
}
|
||||
var scheme = url.slice(0, schemeIndex).toLowerCase();
|
||||
if (schemes.includes(scheme)) {
|
||||
url = url.split("#", 1)[0];
|
||||
url = url.split("#")[0];
|
||||
if (url.charAt(schemeIndex) === ":") {
|
||||
url = encodeURIComponent(url);
|
||||
}
|
||||
@ -95,8 +95,8 @@ limitations under the License.
|
||||
url: CRX_BASE_URL + "*:*",
|
||||
},
|
||||
function (tabsFromLastSession) {
|
||||
for (const { id } of tabsFromLastSession) {
|
||||
chrome.tabs.reload(id);
|
||||
for (var i = 0; i < tabsFromLastSession.length; ++i) {
|
||||
chrome.tabs.reload(tabsFromLastSession[i].id);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"minimum_chrome_version": "88",
|
||||
"manifest_version": 2,
|
||||
"name": "PDF Viewer",
|
||||
"version": "PDFJSSCRIPT_VERSION",
|
||||
@ -11,30 +10,32 @@
|
||||
},
|
||||
"permissions": [
|
||||
"fileBrowserHandler",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"webRequest", "webRequestBlocking",
|
||||
"<all_urls>",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"storage"
|
||||
],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*", "ftp://*/*", "file://*/*"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true,
|
||||
"css": ["contentstyle.css"],
|
||||
"js": ["contentscript.js"]
|
||||
}
|
||||
],
|
||||
"content_scripts": [{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"ftp://*/*",
|
||||
"file://*/*"
|
||||
],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true,
|
||||
"css": ["contentstyle.css"],
|
||||
"js": ["contentscript.js"]
|
||||
}],
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"file_browser_handlers": [
|
||||
{
|
||||
"id": "open-as-pdf",
|
||||
"default_title": "Open with PDF Viewer",
|
||||
"file_filters": ["filesystem:*.pdf"]
|
||||
}
|
||||
],
|
||||
"file_browser_handlers": [{
|
||||
"id": "open-as-pdf",
|
||||
"default_title": "Open with PDF Viewer",
|
||||
"file_filters": [
|
||||
"filesystem:*.pdf"
|
||||
]
|
||||
}],
|
||||
"storage": {
|
||||
"managed_schema": "preferences_schema.json"
|
||||
},
|
||||
|
@ -109,10 +109,17 @@ limitations under the License.
|
||||
}
|
||||
// Migration code for https://github.com/mozilla/pdf.js/pull/9479.
|
||||
if (typeof items.disableTextLayer === "boolean") {
|
||||
var textLayerMode = 1;
|
||||
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(
|
||||
{
|
||||
textLayerMode: 0,
|
||||
textLayerMode,
|
||||
},
|
||||
function () {
|
||||
if (!chrome.runtime.lastError) {
|
||||
|
@ -126,6 +126,7 @@ body {
|
||||
<select>
|
||||
<option value="0">Disable text selection</option>
|
||||
<option value="1">Enable text selection</option>
|
||||
<option value="2">Enable enhanced mode (experimental)</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -155,7 +155,7 @@ function renderBooleanPref(shortDescription, description, prefName) {
|
||||
storageArea.set(pref);
|
||||
};
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").append(wrapper);
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
checkbox.checked = value;
|
||||
@ -172,7 +172,7 @@ function renderEnumPref(shortDescription, prefName) {
|
||||
storageArea.set(pref);
|
||||
};
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").append(wrapper);
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
select.value = value;
|
||||
@ -189,7 +189,7 @@ function renderDefaultZoomValue(shortDescription) {
|
||||
});
|
||||
};
|
||||
wrapper.querySelector("span").textContent = shortDescription;
|
||||
document.getElementById("settings-boxes").append(wrapper);
|
||||
document.getElementById("settings-boxes").appendChild(wrapper);
|
||||
|
||||
function renderPreference(value) {
|
||||
value = value || "auto";
|
||||
|
@ -20,15 +20,7 @@ limitations under the License.
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
|
||||
function getViewerURL(pdf_url) {
|
||||
// |pdf_url| may contain a fragment such as "#page=2". That should be passed
|
||||
// as a fragment to the viewer, not encoded in pdf_url.
|
||||
var hash = "";
|
||||
var i = pdf_url.indexOf("#");
|
||||
if (i > 0) {
|
||||
hash = pdf_url.slice(i);
|
||||
pdf_url = pdf_url.slice(0, i);
|
||||
}
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url) + hash;
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +54,8 @@ function isPdfDownloadable(details) {
|
||||
* @returns {undefined|{name: string, value: string}} The header, if found.
|
||||
*/
|
||||
function getHeaderFromHeaders(headers, headerName) {
|
||||
for (const header of headers) {
|
||||
for (var i = 0; i < headers.length; ++i) {
|
||||
var header = headers[i];
|
||||
if (header.name.toLowerCase() === headerName) {
|
||||
return header;
|
||||
}
|
||||
@ -162,7 +155,19 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
return { redirectUrl: viewerUrl };
|
||||
},
|
||||
{
|
||||
urls: ["file://*/*.pdf", "file://*/*.PDF"],
|
||||
urls: [
|
||||
"file://*/*.pdf",
|
||||
"file://*/*.PDF",
|
||||
...// Duck-typing: MediaError.prototype.message was added in Chrome 59.
|
||||
(MediaError.prototype.hasOwnProperty("message")
|
||||
? []
|
||||
: [
|
||||
// Note: Chrome 59 has disabled ftp resource loading by default:
|
||||
// https://www.chromestatus.com/feature/5709390967472128
|
||||
"ftp://*/*.pdf",
|
||||
"ftp://*/*.PDF",
|
||||
]),
|
||||
],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
},
|
||||
["blocking"]
|
||||
@ -248,3 +253,10 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Remove keys from storage that were once part of the deleted feature-detect.js
|
||||
chrome.storage.local.remove([
|
||||
"featureDetectLastUA",
|
||||
"webRequestRedirectUrl",
|
||||
"extensionSupportsFTP",
|
||||
]);
|
||||
|
@ -5,7 +5,11 @@
|
||||
"title": "Theme",
|
||||
"description": "The theme to use.\n0 = Use system theme.\n1 = Light theme.\n2 = Dark theme.",
|
||||
"type": "integer",
|
||||
"enum": [0, 1, 2],
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"default": 2
|
||||
},
|
||||
"showPreviousViewOnLoad": {
|
||||
@ -17,15 +21,13 @@
|
||||
"title": "View position on load",
|
||||
"description": "The position in the document upon load.\n -1 = Default (uses OpenAction if available, otherwise equal to `viewOnLoad = 0`).\n 0 = The last viewed page/position.\n 1 = The initial page/position.",
|
||||
"type": "integer",
|
||||
"enum": [-1, 0, 1],
|
||||
"enum": [
|
||||
-1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"defaultZoomDelay": {
|
||||
"title": "Default zoom delay",
|
||||
"description": "Delay (in ms) to wait before redrawing the canvas.",
|
||||
"type": "integer",
|
||||
"default": 400
|
||||
},
|
||||
"defaultZoomValue": {
|
||||
"title": "Default zoom level",
|
||||
"description": "Default zoom level of the viewer. Accepted values: 'auto', 'page-actual', 'page-width', 'page-height', 'page-fit', or a zoom level in percents.",
|
||||
@ -37,7 +39,13 @@
|
||||
"title": "Sidebar state on load",
|
||||
"description": "Controls the state of the sidebar upon load.\n -1 = Default (uses PageMode if available, otherwise the last position if available/enabled).\n 0 = Do not show sidebar.\n 1 = Show thumbnails in sidebar.\n 2 = Show document outline in sidebar.\n 3 = Show attachments in sidebar.",
|
||||
"type": "integer",
|
||||
"enum": [-1, 0, 1, 2, 3],
|
||||
"enum": [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"default": -1
|
||||
},
|
||||
"enableHandToolOnLoad": {
|
||||
@ -45,15 +53,14 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableML": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"cursorToolOnLoad": {
|
||||
"title": "Cursor tool on load",
|
||||
"description": "The cursor tool that is enabled upon load.\n 0 = Text selection tool.\n 1 = Hand tool.",
|
||||
"type": "integer",
|
||||
"enum": [0, 1],
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"pdfBugEnabled": {
|
||||
@ -68,22 +75,6 @@
|
||||
"description": "Whether to allow execution of active content (JavaScript) by PDF files.",
|
||||
"default": false
|
||||
},
|
||||
"enableHighlightEditor": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableHighlightFloatingButton": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"highlightEditorColors": {
|
||||
"type": "string",
|
||||
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
|
||||
},
|
||||
"enableStampEditor": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"disableRange": {
|
||||
"title": "Disable range requests",
|
||||
"description": "Whether to disable range requests (not recommended).",
|
||||
@ -111,18 +102,37 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enhanceTextSelection": {
|
||||
"description": "DEPRECATED. Set textLayerMode to 2 to use the enhanced text selection layer by default.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"textLayerMode": {
|
||||
"title": "Text layer mode",
|
||||
"description": "Controls if the text layer is enabled, and the selection mode that is used.\n 0 = Disabled.\n 1 = Enabled.",
|
||||
"description": "Controls if the text layer is enabled, and the selection mode that is used.\n 0 = Disabled.\n 1 = Enabled.\n 2 = (Experimental) Enabled, with enhanced text selection.",
|
||||
"type": "integer",
|
||||
"enum": [0, 1],
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"default": 1
|
||||
},
|
||||
"useOnlyCssZoom": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"externalLinkTarget": {
|
||||
"title": "External links target window",
|
||||
"description": "Controls how external links will be opened.\n 0 = default.\n 1 = replaces current window.\n 2 = new window/tab.\n 3 = parent.\n 4 = in top window.",
|
||||
"type": "integer",
|
||||
"enum": [0, 1, 2, 3, 4],
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"disablePageLabels": {
|
||||
@ -142,14 +152,14 @@
|
||||
},
|
||||
"annotationMode": {
|
||||
"type": "integer",
|
||||
"enum": [0, 1, 2, 3],
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"default": 2
|
||||
},
|
||||
"annotationEditorMode": {
|
||||
"type": "integer",
|
||||
"enum": [-1, 0, 3, 15],
|
||||
"default": 0
|
||||
},
|
||||
"enablePermissions": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
@ -178,30 +188,26 @@
|
||||
"title": "Scroll mode on load",
|
||||
"description": "Controls how the viewer scrolls upon load.\n -1 = Default (uses the last position if available/enabled).\n 3 = Page scrolling.\n 0 = Vertical scrolling.\n 1 = Horizontal scrolling.\n 2 = Wrapped scrolling.",
|
||||
"type": "integer",
|
||||
"enum": [-1, 0, 1, 2, 3],
|
||||
"enum": [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"default": -1
|
||||
},
|
||||
"spreadModeOnLoad": {
|
||||
"title": "Spread mode on load",
|
||||
"description": "Whether the viewer should join pages into spreads upon load.\n -1 = Default (uses the last position if available/enabled).\n 0 = No spreads.\n 1 = Odd spreads.\n 2 = Even spreads.",
|
||||
"type": "integer",
|
||||
"enum": [-1, 0, 1, 2],
|
||||
"enum": [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"default": -1
|
||||
},
|
||||
"forcePageColors": {
|
||||
"description": "When enabled, the pdf rendering will use the high contrast mode colors",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"pageColorsBackground": {
|
||||
"description": "The color is a string as defined in CSS. Its goal is to help improve readability in high contrast mode",
|
||||
"type": "string",
|
||||
"default": "Canvas"
|
||||
},
|
||||
"pageColorsForeground": {
|
||||
"description": "The color is a string as defined in CSS. Its goal is to help improve readability in high contrast mode",
|
||||
"type": "string",
|
||||
"default": "CanvasText"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/* import-globals-from pdfHandler.js */
|
||||
/* exported saveReferer */
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
@ -42,18 +41,30 @@ var g_requestHeaders = {};
|
||||
// g_referrers[tabId][frameId] = referrer of PDF frame.
|
||||
var g_referrers = {};
|
||||
|
||||
var extraInfoSpecWithHeaders; // = ['requestHeaders', 'extraHeaders']
|
||||
|
||||
(function () {
|
||||
var requestFilter = {
|
||||
urls: ["*://*/*"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
};
|
||||
chrome.webRequest.onSendHeaders.addListener(
|
||||
function (details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
},
|
||||
requestFilter,
|
||||
["requestHeaders", "extraHeaders"]
|
||||
);
|
||||
function registerListener(extraInfoSpec) {
|
||||
extraInfoSpecWithHeaders = extraInfoSpec;
|
||||
// May throw if the given extraInfoSpec is unsupported.
|
||||
chrome.webRequest.onSendHeaders.addListener(
|
||||
function (details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
},
|
||||
requestFilter,
|
||||
extraInfoSpec
|
||||
);
|
||||
}
|
||||
try {
|
||||
registerListener(["requestHeaders", "extraHeaders"]);
|
||||
} catch (e) {
|
||||
// "extraHeaders" is not supported in Chrome 71 and earlier.
|
||||
registerListener(["requestHeaders"]);
|
||||
}
|
||||
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onErrorOccurred.addListener(forgetHeaders, requestFilter);
|
||||
@ -114,7 +125,7 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
types: ["xmlhttprequest"],
|
||||
tabId,
|
||||
},
|
||||
["blocking", "requestHeaders", "extraHeaders"]
|
||||
["blocking", ...extraInfoSpecWithHeaders]
|
||||
);
|
||||
}
|
||||
// Acknowledge the message, and include the latest referer for this frame.
|
||||
|
@ -70,20 +70,29 @@ limitations under the License.
|
||||
|
||||
var deduplication_id = getDeduplicationId(wasUpdated);
|
||||
var extension_version = chrome.runtime.getManifest().version;
|
||||
fetch(LOG_URL, {
|
||||
method: "POST",
|
||||
headers: new Headers({
|
||||
"Deduplication-Id": deduplication_id,
|
||||
"Extension-Version": extension_version,
|
||||
}),
|
||||
// Set mode=cors so that the above custom headers are included in the
|
||||
// request.
|
||||
mode: "cors",
|
||||
// Omits credentials such as cookies in the requests, which guarantees
|
||||
// that the server cannot track the client via HTTP cookies.
|
||||
credentials: "omit",
|
||||
cache: "no-store",
|
||||
});
|
||||
if (window.Request && "mode" in Request.prototype) {
|
||||
// fetch is supported in extensions since Chrome 42 (though the above
|
||||
// feature-detection method detects Chrome 43+).
|
||||
// Unlike XMLHttpRequest, fetch omits credentials such as cookies in the
|
||||
// requests, which guarantees that the server cannot track the client
|
||||
// via HTTP cookies.
|
||||
fetch(LOG_URL, {
|
||||
method: "POST",
|
||||
headers: new Headers({
|
||||
"Deduplication-Id": deduplication_id,
|
||||
"Extension-Version": extension_version,
|
||||
}),
|
||||
// Set mode=cors so that the above custom headers are included in the
|
||||
// request.
|
||||
mode: "cors",
|
||||
});
|
||||
return;
|
||||
}
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("POST", LOG_URL);
|
||||
x.setRequestHeader("Deduplication-Id", deduplication_id);
|
||||
x.setRequestHeader("Extension-Version", extension_version);
|
||||
x.send();
|
||||
});
|
||||
}
|
||||
|
||||
@ -101,7 +110,8 @@ limitations under the License.
|
||||
id = "";
|
||||
var buf = new Uint8Array(5);
|
||||
crypto.getRandomValues(buf);
|
||||
for (const c of buf) {
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
var c = buf[i];
|
||||
id += (c >>> 4).toString(16) + (c & 0xf).toString(16);
|
||||
}
|
||||
localStorage.telemetryDeduplicationId = id;
|
||||
|
@ -6,11 +6,18 @@
|
||||
"plugin:mozilla/recommended",
|
||||
],
|
||||
|
||||
"parserOptions": {
|
||||
"sourceType": "script",
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"mozilla"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
// Items different from the mozilla/recommended configuration.
|
||||
"no-var": "off",
|
||||
|
||||
// Other rules mozilla/recommended hasn't enabled yet.
|
||||
"no-shadow": "error",
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
|
5
extensions/firefox/README.mozilla
Normal file
5
extensions/firefox/README.mozilla
Normal file
@ -0,0 +1,5 @@
|
||||
This is the PDF.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: PDFJSSCRIPT_VERSION
|
||||
|
||||
Taken from upstream commit: PDFJSSCRIPT_COMMIT
|
@ -13,6 +13,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const PdfJsDefaultPreferences = Object.freeze(
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PdfJsDefaultPreferences"];
|
||||
|
||||
var PdfJsDefaultPreferences = Object.freeze(
|
||||
PDFJSDev.eval("DEFAULT_PREFERENCES")
|
||||
);
|
131
extensions/firefox/tools/l10n.js
Normal file
131
extensions/firefox/tools/l10n.js
Normal file
@ -0,0 +1,131 @@
|
||||
"use strict";
|
||||
|
||||
// Small subset of the webL10n API by Fabien Cazenave for PDF.js extension.
|
||||
(function (window) {
|
||||
var gLanguage = "";
|
||||
var gExternalLocalizerServices = null;
|
||||
var gReadyState = "loading";
|
||||
|
||||
// fetch an l10n objects
|
||||
function getL10nData(key) {
|
||||
var response = gExternalLocalizerServices.getStrings(key);
|
||||
var data = JSON.parse(response);
|
||||
if (!data) {
|
||||
console.warn("[l10n] #" + key + " missing for [" + gLanguage + "]");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// replace {{arguments}} with their values
|
||||
function substArguments(text, args) {
|
||||
if (!args) {
|
||||
return text;
|
||||
}
|
||||
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function (all, name) {
|
||||
return name in args ? args[name] : "{{" + name + "}}";
|
||||
});
|
||||
}
|
||||
|
||||
// translate a string
|
||||
function translateString(key, args, fallback) {
|
||||
var i = key.lastIndexOf(".");
|
||||
var name, property;
|
||||
if (i >= 0) {
|
||||
name = key.substring(0, i);
|
||||
property = key.substring(i + 1);
|
||||
} else {
|
||||
name = key;
|
||||
property = "textContent";
|
||||
}
|
||||
var data = getL10nData(name);
|
||||
var value = (data && data[property]) || fallback;
|
||||
if (!value) {
|
||||
return "{{" + key + "}}";
|
||||
}
|
||||
return substArguments(value, args);
|
||||
}
|
||||
|
||||
// translate an HTML element
|
||||
function translateElement(element) {
|
||||
if (!element || !element.dataset) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the related l10n object
|
||||
var key = element.dataset.l10nId;
|
||||
var data = getL10nData(key);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get arguments (if any)
|
||||
// TODO: more flexible parser?
|
||||
var args;
|
||||
if (element.dataset.l10nArgs) {
|
||||
try {
|
||||
args = JSON.parse(element.dataset.l10nArgs);
|
||||
} catch (e) {
|
||||
console.warn("[l10n] could not parse arguments for #" + key + "");
|
||||
}
|
||||
}
|
||||
|
||||
// translate element
|
||||
// TODO: security check?
|
||||
for (var k in data) {
|
||||
element[k] = substArguments(data[k], args);
|
||||
}
|
||||
}
|
||||
|
||||
// translate an HTML subtree
|
||||
function translateFragment(element) {
|
||||
element = element || document.querySelector("html");
|
||||
|
||||
// check all translatable children (= w/ a `data-l10n-id' attribute)
|
||||
var children = element.querySelectorAll("*[data-l10n-id]");
|
||||
var elementCount = children.length;
|
||||
for (var i = 0; i < elementCount; i++) {
|
||||
translateElement(children[i]);
|
||||
}
|
||||
|
||||
// translate element itself if necessary
|
||||
if (element.dataset.l10nId) {
|
||||
translateElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
// Public API
|
||||
document.mozL10n = {
|
||||
// get a localized string
|
||||
get: translateString,
|
||||
|
||||
// get the document language
|
||||
getLanguage() {
|
||||
return gLanguage;
|
||||
},
|
||||
|
||||
// get the direction (ltr|rtl) of the current language
|
||||
getDirection() {
|
||||
// http://www.w3.org/International/questions/qa-scripts
|
||||
// Arabic, Hebrew, Farsi, Pashto, Urdu
|
||||
var rtlList = ["ar", "he", "fa", "ps", "ur"];
|
||||
|
||||
// use the short language code for "full" codes like 'ar-sa' (issue 5440)
|
||||
var shortCode = gLanguage.split("-")[0];
|
||||
|
||||
return rtlList.includes(shortCode) ? "rtl" : "ltr";
|
||||
},
|
||||
|
||||
getReadyState() {
|
||||
return gReadyState;
|
||||
},
|
||||
|
||||
setExternalLocalizerServices(externalLocalizerServices) {
|
||||
gExternalLocalizerServices = externalLocalizerServices;
|
||||
gLanguage = gExternalLocalizerServices.getLocale();
|
||||
gReadyState = "complete";
|
||||
},
|
||||
|
||||
// translate an element or document fragment
|
||||
translate: translateFragment,
|
||||
};
|
||||
})(this);
|
253
external/builder/babel-plugin-pdfjs-preprocessor.mjs
vendored
253
external/builder/babel-plugin-pdfjs-preprocessor.mjs
vendored
@ -1,253 +0,0 @@
|
||||
import { types as t, transformSync } from "@babel/core";
|
||||
import fs from "fs";
|
||||
import { join as joinPaths } from "path";
|
||||
import vm from "vm";
|
||||
|
||||
const PDFJS_PREPROCESSOR_NAME = "PDFJSDev";
|
||||
const ROOT_PREFIX = "$ROOT/";
|
||||
|
||||
function isPDFJSPreprocessor(obj) {
|
||||
return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;
|
||||
}
|
||||
|
||||
function evalWithDefines(code, defines) {
|
||||
if (!code || !code.trim()) {
|
||||
throw new Error("No JavaScript expression given");
|
||||
}
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false });
|
||||
}
|
||||
|
||||
function handlePreprocessorAction(ctx, actionName, args, path) {
|
||||
try {
|
||||
const arg = args[0];
|
||||
switch (actionName) {
|
||||
case "test":
|
||||
if (!t.isStringLiteral(arg)) {
|
||||
throw new Error("No code for testing is given");
|
||||
}
|
||||
return !!evalWithDefines(arg.value, ctx.defines);
|
||||
case "eval":
|
||||
if (!t.isStringLiteral(arg)) {
|
||||
throw new Error("No code for eval is given");
|
||||
}
|
||||
const result = evalWithDefines(arg.value, ctx.defines);
|
||||
if (
|
||||
typeof result === "boolean" ||
|
||||
typeof result === "string" ||
|
||||
typeof result === "number" ||
|
||||
typeof result === "object"
|
||||
) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case "json":
|
||||
if (!t.isStringLiteral(arg)) {
|
||||
throw new Error("Path to JSON is not provided");
|
||||
}
|
||||
let jsonPath = arg.value;
|
||||
if (jsonPath.startsWith(ROOT_PREFIX)) {
|
||||
jsonPath = joinPaths(
|
||||
ctx.rootPath,
|
||||
jsonPath.substring(ROOT_PREFIX.length)
|
||||
);
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
}
|
||||
throw new Error("Unsupported action");
|
||||
} catch (e) {
|
||||
throw path.buildCodeFrameError(
|
||||
"Could not process " +
|
||||
PDFJS_PREPROCESSOR_NAME +
|
||||
"." +
|
||||
actionName +
|
||||
": " +
|
||||
e.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
return {
|
||||
name: "babel-plugin-pdfjs-preprocessor",
|
||||
manipulateOptions({ parserOpts }) {
|
||||
parserOpts.attachComment = false;
|
||||
},
|
||||
visitor: {
|
||||
"ExportNamedDeclaration|ImportDeclaration": ({ node }) => {
|
||||
if (node.source && ctx.map?.[node.source.value]) {
|
||||
node.source.value = ctx.map[node.source.value];
|
||||
}
|
||||
},
|
||||
"IfStatement|ConditionalExpression": {
|
||||
exit(path) {
|
||||
const { node } = path;
|
||||
if (t.isBooleanLiteral(node.test)) {
|
||||
// if (true) stmt1; => stmt1
|
||||
// if (false) stmt1; else stmt2; => stmt2
|
||||
if (node.test.value === true) {
|
||||
path.replaceWith(node.consequent);
|
||||
} else if (node.alternate) {
|
||||
path.replaceWith(node.alternate);
|
||||
} else {
|
||||
path.remove(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
UnaryExpression: {
|
||||
exit(path) {
|
||||
const { node } = path;
|
||||
if (
|
||||
node.operator === "typeof" &&
|
||||
isPDFJSPreprocessor(node.argument)
|
||||
) {
|
||||
// typeof PDFJSDev => 'object'
|
||||
path.replaceWith(t.stringLiteral("object"));
|
||||
return;
|
||||
}
|
||||
if (node.operator === "!" && t.isBooleanLiteral(node.argument)) {
|
||||
// !true => false, !false => true
|
||||
path.replaceWith(t.booleanLiteral(!node.argument.value));
|
||||
}
|
||||
},
|
||||
},
|
||||
LogicalExpression: {
|
||||
exit(path) {
|
||||
const { node } = path;
|
||||
if (!t.isBooleanLiteral(node.left)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.operator) {
|
||||
case "&&":
|
||||
// true && expr => expr
|
||||
// false && expr => false
|
||||
path.replaceWith(
|
||||
node.left.value === true ? node.right : node.left
|
||||
);
|
||||
break;
|
||||
case "||":
|
||||
// true || expr => true
|
||||
// false || expr => expr
|
||||
path.replaceWith(
|
||||
node.left.value === true ? node.left : node.right
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
BinaryExpression: {
|
||||
exit(path) {
|
||||
const { node } = path;
|
||||
switch (node.operator) {
|
||||
case "==":
|
||||
case "===":
|
||||
case "!=":
|
||||
case "!==":
|
||||
if (t.isLiteral(node.left) && t.isLiteral(node.right)) {
|
||||
// folding == and != check that can be statically evaluated
|
||||
const { confident, value } = path.evaluate();
|
||||
if (confident) {
|
||||
path.replaceWith(t.booleanLiteral(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
CallExpression(path) {
|
||||
const { node } = path;
|
||||
if (
|
||||
t.isMemberExpression(node.callee) &&
|
||||
isPDFJSPreprocessor(node.callee.object) &&
|
||||
t.isIdentifier(node.callee.property) &&
|
||||
!node.callee.computed
|
||||
) {
|
||||
// PDFJSDev.xxxx(arg1, arg2, ...) => transform
|
||||
const action = node.callee.property.name;
|
||||
const result = handlePreprocessorAction(
|
||||
ctx,
|
||||
action,
|
||||
node.arguments,
|
||||
path
|
||||
);
|
||||
path.replaceWith(t.inherits(t.valueToNode(result), path.node));
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node.callee, { name: "__non_webpack_import__" })) {
|
||||
if (node.arguments.length !== 1) {
|
||||
throw new Error("Invalid `__non_webpack_import__` usage.");
|
||||
}
|
||||
// Replace it with a standard `import`-call and
|
||||
// ensure that Webpack will leave it alone.
|
||||
const source = node.arguments[0];
|
||||
source.leadingComments = [
|
||||
{
|
||||
type: "CommentBlock",
|
||||
value: "webpackIgnore: true",
|
||||
},
|
||||
];
|
||||
path.replaceWith(t.importExpression(source));
|
||||
}
|
||||
},
|
||||
BlockStatement: {
|
||||
// Visit node in post-order so that recursive flattening
|
||||
// of blocks works correctly.
|
||||
exit(path) {
|
||||
const { node } = path;
|
||||
|
||||
let subExpressionIndex = 0;
|
||||
while (subExpressionIndex < node.body.length) {
|
||||
switch (node.body[subExpressionIndex].type) {
|
||||
case "EmptyStatement":
|
||||
// Removing empty statements from the blocks.
|
||||
node.body.splice(subExpressionIndex, 1);
|
||||
continue;
|
||||
case "BlockStatement":
|
||||
// Block statements inside a block are flattened
|
||||
// into the parent one.
|
||||
const subChildren = node.body[subExpressionIndex].body;
|
||||
node.body.splice(subExpressionIndex, 1, ...subChildren);
|
||||
subExpressionIndex += Math.max(subChildren.length - 1, 0);
|
||||
continue;
|
||||
case "ReturnStatement":
|
||||
case "ThrowStatement":
|
||||
// Removing dead code after return or throw.
|
||||
node.body.splice(
|
||||
subExpressionIndex + 1,
|
||||
node.body.length - subExpressionIndex - 1
|
||||
);
|
||||
break;
|
||||
}
|
||||
subExpressionIndex++;
|
||||
}
|
||||
},
|
||||
},
|
||||
Function: {
|
||||
exit(path) {
|
||||
if (!t.isBlockStatement(path.node.body)) {
|
||||
// Arrow function with expression body
|
||||
return;
|
||||
}
|
||||
|
||||
const { body } = path.node.body;
|
||||
if (
|
||||
body.length > 0 &&
|
||||
t.isReturnStatement(body.at(-1), { argument: null })
|
||||
) {
|
||||
// Function body ends with return without arg -- removing it.
|
||||
body.pop();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function preprocessPDFJSCode(ctx, content) {
|
||||
return transformSync(content, {
|
||||
configFile: false,
|
||||
plugins: [[babelPluginPDFJSPreprocessor, ctx]],
|
||||
}).code;
|
||||
}
|
||||
|
||||
export { babelPluginPDFJSPreprocessor, preprocessPDFJSCode };
|
@ -1,8 +1,8 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import vm from "vm";
|
||||
"use strict";
|
||||
|
||||
const AllWhitespaceRegexp = /^\s+$/g;
|
||||
const fs = require("fs"),
|
||||
path = require("path"),
|
||||
vm = require("vm");
|
||||
|
||||
/**
|
||||
* A simple preprocessor that is based on the Firefox preprocessor
|
||||
@ -38,32 +38,10 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
return fs.realpathSync(inFilename) + ":" + lineNumber;
|
||||
}
|
||||
|
||||
function expandCssImports(content, baseUrl) {
|
||||
return content.replaceAll(
|
||||
/^\s*@import\s+url\(([^)]+)\);\s*$/gm,
|
||||
function (all, url) {
|
||||
if (defines.GECKOVIEW) {
|
||||
switch (url) {
|
||||
case "annotation_editor_layer_builder.css":
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const file = path.join(path.dirname(baseUrl), url);
|
||||
const imported = fs.readFileSync(file, "utf8").toString();
|
||||
return expandCssImports(imported, file);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// TODO make this really read line by line.
|
||||
let content = fs.readFileSync(inFilename, "utf8").toString();
|
||||
// Handle CSS-imports first, when necessary.
|
||||
if (/\.css$/i.test(inFilename)) {
|
||||
content = expandCssImports(content, inFilename);
|
||||
}
|
||||
const lines = content.split("\n"),
|
||||
totalLines = lines.length;
|
||||
const out = [];
|
||||
const lines = fs.readFileSync(inFilename).toString().split("\n");
|
||||
const totalLines = lines.length;
|
||||
let out = "";
|
||||
let i = 0;
|
||||
function readLine() {
|
||||
if (i < totalLines) {
|
||||
@ -75,13 +53,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
typeof outFilename === "function"
|
||||
? outFilename
|
||||
: function (line) {
|
||||
if (!line || AllWhitespaceRegexp.test(line)) {
|
||||
const prevLine = out.at(-1);
|
||||
if (!prevLine || AllWhitespaceRegexp.test(prevLine)) {
|
||||
return; // Avoid adding consecutive blank lines.
|
||||
}
|
||||
}
|
||||
out.push(line);
|
||||
out += line + "\n";
|
||||
};
|
||||
function evaluateCondition(code) {
|
||||
if (!code || !code.trim()) {
|
||||
@ -125,7 +97,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
}
|
||||
}
|
||||
function expand(line) {
|
||||
line = line.replaceAll(/__[\w]+__/g, function (variable) {
|
||||
line = line.replace(/__[\w]+__/g, function (variable) {
|
||||
variable = variable.substring(2, variable.length - 2);
|
||||
if (variable in defines) {
|
||||
return defines[variable];
|
||||
@ -151,7 +123,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
let state = STATE_NONE;
|
||||
const stack = [];
|
||||
const control =
|
||||
/^(?:\/\/|\s*\/\*|<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:\*\/|-->)?$)?/;
|
||||
/^(?:\/\/|<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:-->)?$)?/;
|
||||
|
||||
while ((line = readLine()) !== null) {
|
||||
++lineNumber;
|
||||
@ -204,19 +176,16 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (state === STATE_NONE) {
|
||||
writeLine(line);
|
||||
} else if (
|
||||
(state === STATE_IF_TRUE || state === STATE_ELSE_TRUE) &&
|
||||
!stack.includes(STATE_IF_FALSE) &&
|
||||
!stack.includes(STATE_ELSE_FALSE)
|
||||
) {
|
||||
writeLine(
|
||||
line
|
||||
.replaceAll(/^\/\/|^<!--/g, " ")
|
||||
.replaceAll(/(^\s*)\/\*/g, "$1 ")
|
||||
.replaceAll(/\*\/$|-->$/g, "")
|
||||
);
|
||||
} else {
|
||||
if (state === STATE_NONE) {
|
||||
writeLine(line);
|
||||
} else if (
|
||||
(state === STATE_IF_TRUE || state === STATE_ELSE_TRUE) &&
|
||||
!stack.includes(STATE_IF_FALSE) &&
|
||||
!stack.includes(STATE_ELSE_FALSE)
|
||||
) {
|
||||
writeLine(line.replace(/^\/\/|^<!--/g, " ").replace(/-->$/g, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state !== STATE_NONE || stack.length !== 0) {
|
||||
@ -225,8 +194,99 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
);
|
||||
}
|
||||
if (typeof outFilename !== "function") {
|
||||
fs.writeFileSync(outFilename, out.join("\n"));
|
||||
fs.writeFileSync(outFilename, out);
|
||||
}
|
||||
}
|
||||
exports.preprocess = preprocess;
|
||||
|
||||
export { preprocess };
|
||||
function preprocessCSS(mode, source, destination) {
|
||||
function hasPrefixedMozcentral(line) {
|
||||
return /(^|\W)-(ms|o|webkit)-\w/.test(line);
|
||||
}
|
||||
|
||||
function expandImports(content, baseUrl) {
|
||||
return content.replace(
|
||||
/^\s*@import\s+url\(([^)]+)\);\s*$/gm,
|
||||
function (all, url) {
|
||||
const file = path.join(path.dirname(baseUrl), url);
|
||||
const imported = fs.readFileSync(file, "utf8").toString();
|
||||
return expandImports(imported, file);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function removePrefixed(content, hasPrefixedFilter) {
|
||||
const lines = content.split(/\r?\n/g);
|
||||
let i = 0;
|
||||
while (i < lines.length) {
|
||||
const line = lines[i];
|
||||
if (!hasPrefixedFilter(line)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (/\{\s*$/.test(line)) {
|
||||
let bracketLevel = 1;
|
||||
let j = i + 1;
|
||||
while (j < lines.length && bracketLevel > 0) {
|
||||
const checkBracket = /([{}])\s*$/.exec(lines[j]);
|
||||
if (checkBracket) {
|
||||
if (checkBracket[1] === "{") {
|
||||
bracketLevel++;
|
||||
} else if (!lines[j].includes("{")) {
|
||||
bracketLevel--;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
lines.splice(i, j - i);
|
||||
} else if (/[};]\s*$/.test(line)) {
|
||||
lines.splice(i, 1);
|
||||
} else {
|
||||
// multiline? skipping until next directive or bracket
|
||||
do {
|
||||
lines.splice(i, 1);
|
||||
} while (
|
||||
i < lines.length &&
|
||||
!/\}\s*$/.test(lines[i]) &&
|
||||
!lines[i].includes(":")
|
||||
);
|
||||
if (i < lines.length && /\S\s*}\s*$/.test(lines[i])) {
|
||||
lines[i] = lines[i].substring(lines[i].indexOf("}"));
|
||||
}
|
||||
}
|
||||
// collapse whitespaces
|
||||
while (lines[i] === "" && lines[i - 1] === "") {
|
||||
lines.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
throw new Error("Invalid CSS preprocessor mode");
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(source, "utf8").toString();
|
||||
content = expandImports(content, source);
|
||||
if (mode === "mozcentral") {
|
||||
content = removePrefixed(content, hasPrefixedMozcentral);
|
||||
}
|
||||
fs.writeFileSync(destination, content);
|
||||
}
|
||||
exports.preprocessCSS = preprocessCSS;
|
||||
|
||||
/**
|
||||
* Merge two defines arrays. Values in the second param will override values in
|
||||
* the first.
|
||||
*/
|
||||
function merge(defaults, defines) {
|
||||
const ret = Object.create(null);
|
||||
for (const key in defaults) {
|
||||
ret[key] = defaults[key];
|
||||
}
|
||||
for (const key in defines) {
|
||||
ret[key] = defines[key];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
exports.merge = merge;
|
@ -1,5 +0,0 @@
|
||||
/* Comment here... */
|
||||
div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
7
external/builder/fixtures/css-comment.css
vendored
7
external/builder/fixtures/css-comment.css
vendored
@ -1,7 +0,0 @@
|
||||
/* Comment here... */
|
||||
/*#if TRUE*/
|
||||
/*div {*/
|
||||
/* margin: 0;*/
|
||||
/*padding: 0;*/
|
||||
/*}*/
|
||||
/*#endif*/
|
@ -1,3 +0,0 @@
|
||||
div {
|
||||
margin: 0;
|
||||
}
|
14
external/builder/fixtures/if-nested.css
vendored
14
external/builder/fixtures/if-nested.css
vendored
@ -1,14 +0,0 @@
|
||||
/*#if TRUE*/
|
||||
div {
|
||||
margin: 0;
|
||||
/*#if FALSE*/
|
||||
padding: 0;
|
||||
/*#endif*/
|
||||
}
|
||||
/*#endif*/
|
||||
|
||||
/*#if FALSE*/
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
/*#endif*/
|
@ -1,10 +1,10 @@
|
||||
function test() {
|
||||
"test";
|
||||
"1";
|
||||
"2";
|
||||
"3";
|
||||
if ("test") {
|
||||
"5";
|
||||
}
|
||||
"4";
|
||||
"test";
|
||||
"1";
|
||||
"2";
|
||||
"3";
|
||||
if ("test") {
|
||||
"5";
|
||||
}
|
||||
"4";
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
function f1() {
|
||||
"1";
|
||||
"2";
|
||||
"1";
|
||||
"2";
|
||||
}
|
||||
function f2() {
|
||||
"1";
|
||||
"2";
|
||||
"1";
|
||||
"2";
|
||||
}
|
||||
function f3() {
|
||||
if ("1") {
|
||||
"1";
|
||||
}
|
||||
"2";
|
||||
if ("3") {
|
||||
"4";
|
||||
}
|
||||
if ("1") {
|
||||
"1";
|
||||
}
|
||||
"2";
|
||||
if ("3") {
|
||||
"4";
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,6 @@ var i = true;
|
||||
var j = false;
|
||||
var k = false;
|
||||
var l = true;
|
||||
var m = false;
|
||||
var m = '1' === true;
|
||||
var n = false;
|
||||
var o = true;
|
||||
|
@ -1,21 +1,13 @@
|
||||
function f1() {}
|
||||
function f1() {
|
||||
}
|
||||
function f2() {
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
function f3() {
|
||||
var i = 0;
|
||||
throw "test";
|
||||
var i = 0;
|
||||
throw "test";
|
||||
}
|
||||
function f4() {
|
||||
var i = 0;
|
||||
var i = 0;
|
||||
}
|
||||
var obj = {
|
||||
method1() {},
|
||||
method2() {}
|
||||
};
|
||||
class C {
|
||||
method1() {}
|
||||
method2() {}
|
||||
}
|
||||
var arrow1 = () => {};
|
||||
var arrow2 = () => {};
|
||||
|
||||
|
12
external/builder/fixtures_esprima/deadcode.js
vendored
12
external/builder/fixtures_esprima/deadcode.js
vendored
@ -23,15 +23,3 @@ function f4() {
|
||||
var j = 0;
|
||||
}
|
||||
|
||||
var obj = {
|
||||
method1() { return; var i = 0; },
|
||||
method2() { return; },
|
||||
};
|
||||
|
||||
class C {
|
||||
method1() { return; var i = 0; }
|
||||
method2() { return; }
|
||||
}
|
||||
|
||||
var arrow1 = () => { return; var i = 0; };
|
||||
var arrow2 = () => { return; };
|
||||
|
@ -3,19 +3,11 @@ var b = true;
|
||||
var c = true;
|
||||
var d = false;
|
||||
var e = true;
|
||||
var f = "text";
|
||||
var f = 'text';
|
||||
var g = {
|
||||
obj: {
|
||||
i: 1
|
||||
},
|
||||
j: 2
|
||||
};
|
||||
var h = {
|
||||
test: "test"
|
||||
"obj": { "i": 1 },
|
||||
"j": 2
|
||||
};
|
||||
var h = { 'test': 'test' };
|
||||
var i = '0';
|
||||
var j = {
|
||||
i: 1
|
||||
};
|
||||
var k = false;
|
||||
var l = true;
|
||||
var j = { "i": 1 };
|
||||
|
2
external/builder/fixtures_esprima/evals.js
vendored
2
external/builder/fixtures_esprima/evals.js
vendored
@ -8,5 +8,3 @@ var g = PDFJSDev.eval('OBJ');
|
||||
var h = PDFJSDev.json('$ROOT/external/builder/fixtures_esprima/evals.json');
|
||||
var i = typeof PDFJSDev === 'undefined' ? PDFJSDev.eval('FALSE') : '0';
|
||||
var j = typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('OBJ.obj') : '0';
|
||||
var k = !PDFJSDev.test('TRUE');
|
||||
var l = !PDFJSDev.test('FALSE');
|
||||
|
2
external/builder/fixtures_esprima/evals.json
vendored
2
external/builder/fixtures_esprima/evals.json
vendored
@ -1 +1 @@
|
||||
{ "test": "test" }
|
||||
{ 'test': 'test' }
|
@ -1,18 +1,17 @@
|
||||
if ('test') {
|
||||
"1";
|
||||
"1";
|
||||
}
|
||||
{
|
||||
"1";
|
||||
"1";
|
||||
}
|
||||
{
|
||||
"1";
|
||||
"1";
|
||||
}
|
||||
;
|
||||
{
|
||||
"2";
|
||||
"2";
|
||||
}
|
||||
;
|
||||
if ('1') {
|
||||
"1";
|
||||
}
|
||||
function f1() {
|
||||
"1";
|
||||
"1";
|
||||
}
|
||||
|
9
external/builder/fixtures_esprima/ifs.js
vendored
9
external/builder/fixtures_esprima/ifs.js
vendored
@ -23,12 +23,3 @@ if (true && false) {
|
||||
if (true && false || '1') {
|
||||
"1";
|
||||
}
|
||||
|
||||
function f1() {
|
||||
if (true) {
|
||||
"1";
|
||||
}
|
||||
if (false) {
|
||||
"2";
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { Test } from "import-name";
|
||||
import { Test } from 'import-name';
|
||||
import { Test2 } from './non-alias';
|
||||
export { Test3 } from "import-name";
|
||||
await import( /*webpackIgnore: true*/"./non-alias");
|
||||
export {
|
||||
Test3
|
||||
} from 'import-name';
|
||||
var Imp = require('import-name');
|
||||
var Imp2 = require('./non-alias');
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Test } from 'import-alias';
|
||||
import { Test2 } from './non-alias';
|
||||
export { Test3 } from 'import-alias';
|
||||
await __non_webpack_import__("./non-alias");
|
||||
var Imp = require('import-alias');
|
||||
var Imp2 = require('./non-alias');
|
||||
|
348
external/builder/preprocessor2.js
vendored
Normal file
348
external/builder/preprocessor2.js
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
"use strict";
|
||||
|
||||
const acorn = require("acorn");
|
||||
const escodegen = require("@javascript-obfuscator/escodegen");
|
||||
const vm = require("vm");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const PDFJS_PREPROCESSOR_NAME = "PDFJSDev";
|
||||
const ROOT_PREFIX = "$ROOT/";
|
||||
const ACORN_ECMA_VERSION = 2022;
|
||||
|
||||
function isLiteral(obj, value) {
|
||||
return obj.type === "Literal" && obj.value === value;
|
||||
}
|
||||
|
||||
function isPDFJSPreprocessor(obj) {
|
||||
return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;
|
||||
}
|
||||
|
||||
function evalWithDefines(code, defines, loc) {
|
||||
if (!code || !code.trim()) {
|
||||
throw new Error("No JavaScript expression given");
|
||||
}
|
||||
return vm.runInNewContext(code, defines, { displayErrors: false });
|
||||
}
|
||||
|
||||
function handlePreprocessorAction(ctx, actionName, args, loc) {
|
||||
try {
|
||||
let arg;
|
||||
switch (actionName) {
|
||||
case "test":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("No code for testing is given");
|
||||
}
|
||||
const isTrue = !!evalWithDefines(arg.value, ctx.defines);
|
||||
return { type: "Literal", value: isTrue, loc };
|
||||
case "eval":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("No code for eval is given");
|
||||
}
|
||||
const result = evalWithDefines(arg.value, ctx.defines);
|
||||
if (
|
||||
typeof result === "boolean" ||
|
||||
typeof result === "string" ||
|
||||
typeof result === "number"
|
||||
) {
|
||||
return { type: "Literal", value: result, loc };
|
||||
}
|
||||
if (typeof result === "object") {
|
||||
const parsedObj = acorn.parse("(" + JSON.stringify(result) + ")", {
|
||||
ecmaVersion: ACORN_ECMA_VERSION,
|
||||
});
|
||||
parsedObj.body[0].expression.loc = loc;
|
||||
return parsedObj.body[0].expression;
|
||||
}
|
||||
break;
|
||||
case "json":
|
||||
arg = args[0];
|
||||
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {
|
||||
throw new Error("Path to JSON is not provided");
|
||||
}
|
||||
let jsonPath = arg.value;
|
||||
if (jsonPath.indexOf(ROOT_PREFIX) === 0) {
|
||||
jsonPath = path.join(
|
||||
ctx.rootPath,
|
||||
jsonPath.substring(ROOT_PREFIX.length)
|
||||
);
|
||||
}
|
||||
const jsonContent = fs.readFileSync(jsonPath).toString();
|
||||
const parsedJSON = acorn.parse("(" + jsonContent + ")", {
|
||||
ecmaVersion: ACORN_ECMA_VERSION,
|
||||
});
|
||||
parsedJSON.body[0].expression.loc = loc;
|
||||
return parsedJSON.body[0].expression;
|
||||
}
|
||||
throw new Error("Unsupported action");
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
"Could not process " +
|
||||
PDFJS_PREPROCESSOR_NAME +
|
||||
"." +
|
||||
actionName +
|
||||
" at " +
|
||||
JSON.stringify(loc) +
|
||||
"\n" +
|
||||
e.name +
|
||||
": " +
|
||||
e.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function postprocessNode(ctx, node) {
|
||||
switch (node.type) {
|
||||
case "ExportNamedDeclaration":
|
||||
case "ImportDeclaration":
|
||||
if (
|
||||
node.source &&
|
||||
node.source.type === "Literal" &&
|
||||
ctx.map &&
|
||||
ctx.map[node.source.value]
|
||||
) {
|
||||
const newValue = ctx.map[node.source.value];
|
||||
node.source.value = node.source.raw = newValue;
|
||||
}
|
||||
break;
|
||||
case "IfStatement":
|
||||
if (isLiteral(node.test, true)) {
|
||||
// if (true) stmt1; => stmt1
|
||||
return node.consequent;
|
||||
} else if (isLiteral(node.test, false)) {
|
||||
// if (false) stmt1; else stmt2; => stmt2
|
||||
return node.alternate || { type: "EmptyStatement", loc: node.loc };
|
||||
}
|
||||
break;
|
||||
case "ConditionalExpression":
|
||||
if (isLiteral(node.test, true)) {
|
||||
// true ? stmt1 : stmt2 => stmt1
|
||||
return node.consequent;
|
||||
} else if (isLiteral(node.test, false)) {
|
||||
// false ? stmt1 : stmt2 => stmt2
|
||||
return node.alternate;
|
||||
}
|
||||
break;
|
||||
case "UnaryExpression":
|
||||
if (node.operator === "typeof" && isPDFJSPreprocessor(node.argument)) {
|
||||
// typeof PDFJSDev => 'object'
|
||||
return { type: "Literal", value: "object", loc: node.loc };
|
||||
}
|
||||
if (
|
||||
node.operator === "!" &&
|
||||
node.argument.type === "Literal" &&
|
||||
typeof node.argument.value === "boolean"
|
||||
) {
|
||||
// !true => false, !false => true
|
||||
return { type: "Literal", value: !node.argument.value, loc: node.loc };
|
||||
}
|
||||
break;
|
||||
case "LogicalExpression":
|
||||
switch (node.operator) {
|
||||
case "&&":
|
||||
if (isLiteral(node.left, true)) {
|
||||
return node.right;
|
||||
}
|
||||
if (isLiteral(node.left, false)) {
|
||||
return node.left;
|
||||
}
|
||||
break;
|
||||
case "||":
|
||||
if (isLiteral(node.left, true)) {
|
||||
return node.left;
|
||||
}
|
||||
if (isLiteral(node.left, false)) {
|
||||
return node.right;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "BinaryExpression":
|
||||
switch (node.operator) {
|
||||
case "==":
|
||||
case "===":
|
||||
case "!=":
|
||||
case "!==":
|
||||
if (
|
||||
node.left.type === "Literal" &&
|
||||
node.right.type === "Literal" &&
|
||||
typeof node.left.value === typeof node.right.value
|
||||
) {
|
||||
// folding two literals == and != check
|
||||
switch (typeof node.left.value) {
|
||||
case "string":
|
||||
case "boolean":
|
||||
case "number":
|
||||
const equal = node.left.value === node.right.value;
|
||||
return {
|
||||
type: "Literal",
|
||||
value: (node.operator[0] === "=") === equal,
|
||||
loc: node.loc,
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "CallExpression":
|
||||
if (
|
||||
node.callee.type === "MemberExpression" &&
|
||||
isPDFJSPreprocessor(node.callee.object) &&
|
||||
node.callee.property.type === "Identifier"
|
||||
) {
|
||||
// PDFJSDev.xxxx(arg1, arg2, ...) => transform
|
||||
const action = node.callee.property.name;
|
||||
return handlePreprocessorAction(ctx, action, node.arguments, node.loc);
|
||||
}
|
||||
// require('string')
|
||||
if (
|
||||
node.callee.type === "Identifier" &&
|
||||
node.callee.name === "require" &&
|
||||
node.arguments.length === 1 &&
|
||||
node.arguments[0].type === "Literal" &&
|
||||
ctx.map &&
|
||||
ctx.map[node.arguments[0].value]
|
||||
) {
|
||||
const requireName = node.arguments[0];
|
||||
requireName.value = requireName.raw = ctx.map[requireName.value];
|
||||
}
|
||||
break;
|
||||
case "BlockStatement":
|
||||
let subExpressionIndex = 0;
|
||||
while (subExpressionIndex < node.body.length) {
|
||||
switch (node.body[subExpressionIndex].type) {
|
||||
case "EmptyStatement":
|
||||
// Removing empty statements from the blocks.
|
||||
node.body.splice(subExpressionIndex, 1);
|
||||
continue;
|
||||
case "BlockStatement":
|
||||
// Block statements inside a block are moved to the parent one.
|
||||
const subChildren = node.body[subExpressionIndex].body;
|
||||
Array.prototype.splice.apply(
|
||||
node.body,
|
||||
[subExpressionIndex, 1].concat(subChildren)
|
||||
);
|
||||
subExpressionIndex += Math.max(subChildren.length - 1, 0);
|
||||
continue;
|
||||
case "ReturnStatement":
|
||||
case "ThrowStatement":
|
||||
// Removing dead code after return or throw.
|
||||
node.body.splice(
|
||||
subExpressionIndex + 1,
|
||||
node.body.length - subExpressionIndex - 1
|
||||
);
|
||||
break;
|
||||
}
|
||||
subExpressionIndex++;
|
||||
}
|
||||
break;
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
const block = node.body;
|
||||
if (
|
||||
block.body.length > 0 &&
|
||||
block.body[block.body.length - 1].type === "ReturnStatement" &&
|
||||
!block.body[block.body.length - 1].argument
|
||||
) {
|
||||
// Function body ends with return without arg -- removing it.
|
||||
block.body.pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function fixComments(ctx, node) {
|
||||
if (!ctx.saveComments) {
|
||||
return;
|
||||
}
|
||||
// Fixes double comments in the escodegen output.
|
||||
delete node.trailingComments;
|
||||
// Removes ESLint and other service comments.
|
||||
if (node.leadingComments) {
|
||||
const CopyrightRegExp = /\bcopyright\b/i;
|
||||
const BlockCommentRegExp = /^\s*(globals|eslint|falls through)\b/;
|
||||
const LineCommentRegExp = /^\s*eslint\b/;
|
||||
|
||||
let i = 0;
|
||||
while (i < node.leadingComments.length) {
|
||||
const type = node.leadingComments[i].type;
|
||||
const value = node.leadingComments[i].value;
|
||||
|
||||
if (ctx.saveComments === "copyright") {
|
||||
// Remove all comments, except Copyright notices and License headers.
|
||||
if (!(type === "Block" && CopyrightRegExp.test(value))) {
|
||||
node.leadingComments.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
} else if (
|
||||
(type === "Block" && BlockCommentRegExp.test(value)) ||
|
||||
(type === "Line" && LineCommentRegExp.test(value))
|
||||
) {
|
||||
node.leadingComments.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function traverseTree(ctx, node) {
|
||||
// generic node processing
|
||||
for (const i in node) {
|
||||
const child = node[i];
|
||||
if (typeof child === "object" && child !== null && child.type) {
|
||||
const result = traverseTree(ctx, child);
|
||||
if (result !== child) {
|
||||
node[i] = result;
|
||||
}
|
||||
} else if (Array.isArray(child)) {
|
||||
child.forEach(function (childItem, index) {
|
||||
if (
|
||||
typeof childItem === "object" &&
|
||||
childItem !== null &&
|
||||
childItem.type
|
||||
) {
|
||||
const result = traverseTree(ctx, childItem);
|
||||
if (result !== childItem) {
|
||||
child[index] = result;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
node = postprocessNode(ctx, node) || node;
|
||||
|
||||
fixComments(ctx, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
function preprocessPDFJSCode(ctx, code) {
|
||||
const format = ctx.format || {
|
||||
indent: {
|
||||
style: " ",
|
||||
},
|
||||
};
|
||||
const parseOptions = {
|
||||
ecmaVersion: ACORN_ECMA_VERSION,
|
||||
locations: true,
|
||||
sourceFile: ctx.sourceFile,
|
||||
sourceType: "module",
|
||||
};
|
||||
const codegenOptions = {
|
||||
format,
|
||||
parse(input) {
|
||||
return acorn.parse(input, { ecmaVersion: ACORN_ECMA_VERSION });
|
||||
},
|
||||
sourceMap: ctx.sourceMap,
|
||||
sourceMapWithCode: ctx.sourceMap,
|
||||
};
|
||||
const syntax = acorn.parse(code, parseOptions);
|
||||
traverseTree(ctx, syntax);
|
||||
return escodegen.generate(syntax, codegenOptions);
|
||||
}
|
||||
|
||||
exports.preprocessPDFJSCode = preprocessPDFJSCode;
|
@ -1,9 +1,8 @@
|
||||
import * as builder from "./builder.mjs";
|
||||
import { fileURLToPath } from "url";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
"use strict";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const builder = require("./builder.js");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
let errors = 0;
|
||||
|
||||
@ -22,7 +21,7 @@ files.forEach(function (expectationFilename) {
|
||||
.readFileSync(expectationFilename)
|
||||
.toString()
|
||||
.trim()
|
||||
.replaceAll("__filename", fs.realpathSync(inFilename));
|
||||
.replace(/__filename/g, fs.realpathSync(inFilename));
|
||||
const outLines = [];
|
||||
|
||||
const outFilename = function (line) {
|
||||
@ -37,17 +36,11 @@ files.forEach(function (expectationFilename) {
|
||||
builder.preprocess(inFilename, outFilename, defines);
|
||||
out = outLines.join("\n").trim();
|
||||
} catch (e) {
|
||||
out = ("Error: " + e.message).replaceAll(/^/gm, "//");
|
||||
out = ("Error: " + e.message).replace(/^/gm, "//");
|
||||
}
|
||||
if (out !== expectation) {
|
||||
errors++;
|
||||
|
||||
// Allow regenerating the expected output using
|
||||
// OVERWRITE=true node ./external/builder/test-fixtures.mjs
|
||||
if (process.env.OVERWRITE) {
|
||||
fs.writeFileSync(expectationFilename, out + "\n");
|
||||
}
|
||||
|
||||
console.log("Assertion failed for " + inFilename);
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("EXPECTED:");
|
@ -1,9 +1,8 @@
|
||||
import { fileURLToPath } from "url";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { preprocessPDFJSCode } from "./babel-plugin-pdfjs-preprocessor.mjs";
|
||||
"use strict";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const p2 = require("./preprocessor2.js");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
let errors = 0;
|
||||
|
||||
@ -22,7 +21,7 @@ files.forEach(function (expectationFilename) {
|
||||
.readFileSync(expectationFilename)
|
||||
.toString()
|
||||
.trim()
|
||||
.replaceAll("__filename", fs.realpathSync(inFilename));
|
||||
.replace(/__filename/g, fs.realpathSync(inFilename));
|
||||
const input = fs.readFileSync(inFilename).toString();
|
||||
|
||||
const defines = {
|
||||
@ -41,19 +40,13 @@ files.forEach(function (expectationFilename) {
|
||||
};
|
||||
let out;
|
||||
try {
|
||||
out = preprocessPDFJSCode(ctx, input);
|
||||
out = p2.preprocessPDFJSCode(ctx, input);
|
||||
} catch (e) {
|
||||
out = ("Error: " + e.message).replaceAll(/^/gm, "//");
|
||||
out = ("Error: " + e.message).replace(/^/gm, "//");
|
||||
}
|
||||
if (out !== expectation) {
|
||||
errors++;
|
||||
|
||||
// Allow regenerating the expected output using
|
||||
// OVERWRITE=true node ./external/builder/test-fixtures_esprima.mjs
|
||||
if (process.env.OVERWRITE) {
|
||||
fs.writeFileSync(expectationFilename, out + "\n");
|
||||
}
|
||||
|
||||
console.log("Assertion failed for " + inFilename);
|
||||
console.log("--------------------------------------------------");
|
||||
console.log("EXPECTED:");
|
@ -13,10 +13,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import { optimizeCMap } from "./optimize.mjs";
|
||||
import { parseAdobeCMap } from "./parse.mjs";
|
||||
import path from "path";
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const parseAdobeCMap = require("./parse.js").parseAdobeCMap;
|
||||
const optimizeCMap = require("./optimize.js").optimizeCMap;
|
||||
|
||||
function compressCmap(srcPath, destPath, verify) {
|
||||
const content = fs.readFileSync(srcPath).toString();
|
||||
@ -215,11 +215,11 @@ function parseCMap(binaryData) {
|
||||
},
|
||||
readHexSigned(size) {
|
||||
const num = this.readHexNumber(size);
|
||||
const sign = fromHexDigit(num.at(-1)) & 1 ? 15 : 0;
|
||||
const sign = fromHexDigit(num[num.length - 1]) & 1 ? 15 : 0;
|
||||
let c = 0;
|
||||
let result = "";
|
||||
for (const digit of num) {
|
||||
c = (c << 4) | fromHexDigit(digit);
|
||||
for (let i = 0; i < num.length; i++) {
|
||||
c = (c << 4) | fromHexDigit(num[i]);
|
||||
result += toHexDigit(sign ? (c >> 1) ^ sign : c >> 1);
|
||||
c &= 1;
|
||||
}
|
||||
@ -469,7 +469,7 @@ function incHex(a) {
|
||||
return s;
|
||||
}
|
||||
|
||||
function compressCmaps(src, dest, verify) {
|
||||
exports.compressCmaps = function (src, dest, verify) {
|
||||
const files = fs.readdirSync(src).filter(function (fn) {
|
||||
return !fn.includes("."); // skipping files with the extension
|
||||
});
|
||||
@ -489,6 +489,4 @@ function compressCmaps(src, dest, verify) {
|
||||
"%"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export { compressCmaps };
|
||||
};
|
@ -13,7 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function optimizeCMap(data) {
|
||||
exports.optimizeCMap = function (data) {
|
||||
let i = 1;
|
||||
while (i < data.body.length) {
|
||||
if (data.body[i - 1].type === data.body[i].type) {
|
||||
@ -151,7 +151,10 @@ function optimizeCMap(data) {
|
||||
const maxDistance = 100,
|
||||
minItems = 10,
|
||||
itemsPerBucket = 50;
|
||||
if (subitems.length > minItems && codes.at(-1) - codes[0] > maxDistance) {
|
||||
if (
|
||||
subitems.length > minItems &&
|
||||
codes[codes.length - 1] - codes[0] > maxDistance
|
||||
) {
|
||||
const gapsCount = Math.max(2, (subitems.length / itemsPerBucket) | 0);
|
||||
const gaps = [];
|
||||
for (let q = 0; q < gapsCount; q++) {
|
||||
@ -193,20 +196,20 @@ function optimizeCMap(data) {
|
||||
i++;
|
||||
data.body.splice(i, 0, newItem);
|
||||
}
|
||||
for (const subitem of subitems) {
|
||||
const { code } = subitem;
|
||||
for (let j = 0; j < subitems.length; j++) {
|
||||
const code = subitems[j].code;
|
||||
let q = 0;
|
||||
while (q < groups.length && groups[q] <= code) {
|
||||
q++;
|
||||
}
|
||||
buckets[q].push(subitem);
|
||||
buckets[q].push(subitems[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function incHex(a) {
|
||||
let c = 1,
|
||||
@ -223,5 +226,3 @@ function incHex(a) {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
export { optimizeCMap };
|
@ -13,13 +13,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function parseAdobeCMap(content) {
|
||||
exports.parseAdobeCMap = function (content) {
|
||||
let m = /(\bbegincmap\b[\s\S]*?)\bendcmap\b/.exec(content);
|
||||
if (!m) {
|
||||
throw new Error("cmap was not found");
|
||||
}
|
||||
|
||||
const body = m[1].replaceAll(/\r\n?/g, "\n");
|
||||
const body = m[1].replace(/\r\n?/g, "\n");
|
||||
const result = {
|
||||
type: 1,
|
||||
wmode: 0,
|
||||
@ -100,6 +100,4 @@ function parseAdobeCMap(content) {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export { parseAdobeCMap };
|
||||
};
|
6
external/dist/README.md
vendored
6
external/dist/README.md
vendored
@ -7,8 +7,8 @@ parsing and rendering PDFs.
|
||||
This is a pre-built version of the PDF.js source code. It is automatically
|
||||
generated by the build scripts.
|
||||
|
||||
For usage with older browsers/environments, without native support for the
|
||||
latest JavaScript features, please see the `legacy/` folder.
|
||||
Please see [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support) for information about supported browsers/environments.
|
||||
For usage with older browsers or environments, without support for modern
|
||||
features such as `async`/`await`, optional chaining, nullish coalescing,
|
||||
and private `class` fields/methods; please see the `legacy/` folder.
|
||||
|
||||
See https://github.com/mozilla/pdf.js for learning and contributing.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user