├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── bin └── processImage ├── lib └── processImage.js ├── package.json ├── reallyaico.gif ├── reallyawebp.png ├── test ├── browsersync-compat.js ├── mocha.opts └── processImage.js └── testdata ├── Landscape_8.jpg ├── addBogusElement.js ├── ancillaryChunks.png ├── animated.gif ├── bulb.gif ├── bulbCropped.gifsicle.gif ├── bulbCropped.im.gif ├── bulbInterlaced.gifsicle.gif ├── bulbInterlaced.im.gif ├── bulbRotated.gifsicle.gif ├── bulbRotated.im.gif ├── cat-resized-then-cropped.gif ├── cat.gif ├── certainlynotanimage.jpg ├── dialog-information.svg ├── empty.jpg ├── exifOriented.jpg ├── favicon.ico ├── hugearea.png ├── invalidImage.png ├── notajpeg.jpg ├── purplealpha24bit.png ├── reallyabmp.gif ├── reallyagif.jpeg ├── reallyaico.gif ├── reallyajpeg.gif ├── reallyapng.gif ├── reallyawebp.png ├── rotatedBulb.gif ├── rotatedBulb.png ├── something.txt ├── testImage.png ├── the-villa-facade.png ├── transparentbw.gif ├── turtle.jpg ├── turtleCropped300x200FromTopLeft.jpg ├── turtleCroppedAttention100x200.jpg ├── turtleCroppedCenter.jpg ├── turtleCroppedCenterGm.jpg ├── turtleCroppedEntropy100x200.jpg ├── turtleCroppedNorth.jpg ├── turtleCroppedNorthEastGm.jpg └── turtleExtract.jpg /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | /.nyc_output/ 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard", "prettier"], 3 | "plugins": ["import", "mocha"], 4 | "env": { 5 | "mocha": true 6 | }, 7 | "rules": { 8 | "prefer-template": "error", 9 | "mocha/no-exclusive-tests": "error", 10 | "mocha/no-nested-tests": "error", 11 | "mocha/no-identical-title": "error", 12 | "mocha/consistent-spacing-between-blocks": "error", 13 | "prefer-const": [ 14 | "error", 15 | { 16 | "destructuring": "all", 17 | "ignoreReadBeforeAssign": false 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 'on': 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-20.04 9 | name: Node ${{ matrix.node }} 10 | strategy: 11 | matrix: 12 | node: 13 | - '16' 14 | - '18' 15 | - '20' 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Setup node 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: ${{ matrix.node }} 22 | - name: Install dependencies 23 | run: sudo add-apt-repository -y ppa:inkscape.dev/stable && sudo apt-get install -y optipng pngcrush pngquant graphicsmagick imagemagick libjpeg-turbo-progs inkscape libcairo2-dev libgif-dev libjpeg8-dev zlib1g-dev 24 | - run: npm install 25 | - run: npm test 26 | 27 | test-targets: 28 | runs-on: ubuntu-20.04 29 | name: ${{ matrix.targets.name }} 30 | strategy: 31 | matrix: 32 | targets: 33 | - name: 'Lint' 34 | target: 'lint' 35 | - name: 'Coverage' 36 | target: 'coverage' 37 | steps: 38 | - uses: actions/checkout@v2 39 | - name: Setup node 40 | uses: actions/setup-node@v1 41 | with: 42 | node-version: '16' 43 | - name: Install dependencies 44 | run: sudo add-apt-repository -y ppa:inkscape.dev/stable && sudo apt-get install -y optipng pngcrush pngquant graphicsmagick imagemagick libjpeg-turbo-progs inkscape libcairo2-dev libgif-dev libjpeg8-dev zlib1g-dev 45 | - run: npm install 46 | - run: npm run ${{ matrix.targets.target }} 47 | - name: Upload coverage 48 | uses: coverallsapp/github-action@master 49 | with: 50 | github-token: ${{ secrets.GITHUB_TOKEN }} 51 | if: ${{ matrix.targets.target == 'coverage' }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | /.vscode/settings.json 4 | /.nyc_output/ 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = false 2 | save-exact = false 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.20.2 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | /.nyc_output/ 4 | 5 | # Don't battle offline-github-changelog 6 | /CHANGELOG.md 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5" 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### v11.1.0 (2024-06-02) 2 | 3 | #### Pull requests 4 | 5 | - [#205](https://github.com/papandreou/express-processimage/pull/205) Add icon and webp to secondGuessSourceContentType check ([alexander soriano](mailto:radica_dude@yahoo.com), [alexander](mailto:alexander@one.com)) 6 | 7 | #### Commits to master 8 | 9 | - [eslint --fix .](https://github.com/papandreou/express-processimage/commit/67b30e4e5173e83f0db776683ee67d62dcef4c95) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 10 | - [Enable the mocha\/consistent-spacing-between-blocks rule](https://github.com/papandreou/express-processimage/commit/a41e38b9762d335c60a495ad264e9afabd1ff121) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 11 | - [npm i --save-dev eslint-plugin-mocha@latest](https://github.com/papandreou/express-processimage/commit/5c1a5981219337737e7cf92642abe543f45a3993) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 12 | - [Refresh development dependencies and use prettier 3 for formatting \(\#202\)](https://github.com/papandreou/express-processimage/commit/4d637020b0b8efd9bf675ecac95ce9ad510d536c) ([Priyank Parashar](mailto:paras20xx@users.noreply.github.com)) 13 | 14 | ### v11.0.0 (2023-12-18) 15 | 16 | - [Call time on testing images by asserting on their resemblance.](https://github.com/papandreou/express-processimage/commit/5c4550d844654a05c66abc2c7dee0ec1669e5c51) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 17 | - [Remove unused bluebird dependency.](https://github.com/papandreou/express-processimage/commit/b1af310e000f89ab864f5f947351fdd4f1ff1b5d) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 18 | - [Remove error definitions unused since the introduction of impro.](https://github.com/papandreou/express-processimage/commit/2f80f462f78b1a698d17f78fa0075a34b050cb98) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 19 | - [Update impro to version 0.14.0.](https://github.com/papandreou/express-processimage/commit/76ab7b07b9105210f8ed0bacd6b65b6eb22c4f82) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 20 | - [Cover an OutputDimensionsExceeded error being passed to next.](https://github.com/papandreou/express-processimage/commit/ef89ce56858c1705f750e97fd41620e4ec9107c7) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 21 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v10.3.0...v11.0.0) 22 | 23 | ### v10.3.0 (2023-10-27) 24 | 25 | #### Pull requests 26 | 27 | - [#180](https://github.com/papandreou/express-processimage/pull/180) Upgrade optipng to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 28 | 29 | #### Commits to master 30 | 31 | - [Use the version hook to generate a changelog.](https://github.com/papandreou/express-processimage/commit/813eca110b099e9640c625d2efc172e0568b4dfb) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 32 | - [Upgrade impro to its latest version 0.13.1.](https://github.com/papandreou/express-processimage/commit/588b1cf7ae2f0b4496d4feeeb617fbdc25190cd9) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 33 | - [Use a supported Ubuntu version on CI thus restoring it to working.](https://github.com/papandreou/express-processimage/commit/bcb84660d38f27d4b4f70be999da2bb5ad41e49f) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 34 | - [Also lint with node.js 14 as it's the npm install step that's failing](https://github.com/papandreou/express-processimage/commit/582e1718d97275e9ea5bd4c11664fcddb0769d7b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 35 | - [Don't test with 16 for now \(trying to fix CI\)](https://github.com/papandreou/express-processimage/commit/f086ae8141b34294353f8ab1a6ddc5f6850a0d37) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 36 | - [+4 more](https://github.com/papandreou/express-processimage/compare/v10.2.3...v10.3.0) 37 | 38 | ### v10.2.3 (2022-01-24) 39 | 40 | #### Pull requests 41 | 42 | - [#171](https://github.com/papandreou/express-processimage/pull/171) Upgrade eslint-plugin-mocha to version 10.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 43 | - [#170](https://github.com/papandreou/express-processimage/pull/170) Upgrade prettier to version 2.5.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 44 | - [#168](https://github.com/papandreou/express-processimage/pull/168) Upgrade sinon to version 12.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 45 | - [#167](https://github.com/papandreou/express-processimage/pull/167) Upgrade mime to version 3.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 46 | - [#166](https://github.com/papandreou/express-processimage/pull/166) Upgrade eslint to version 8.1.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 47 | - [#159](https://github.com/papandreou/express-processimage/pull/159) Upgrade prettier to version 2.4.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 48 | - [#164](https://github.com/papandreou/express-processimage/pull/164) Upgrade eslint-plugin-promise to version 5.1.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 49 | 50 | #### Commits to master 51 | 52 | - [Run prettier on test\/processImage.js](https://github.com/papandreou/express-processimage/commit/b6a78cbe4da1f4a70bda97e78b8e34780b38d044) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 53 | - [Update processImage.js](https://github.com/papandreou/express-processimage/commit/9799d3d6955e525b485ceb3324750b895a60da7a) ([alexander soriano](mailto:radica_dude@yahoo.com)) 54 | - [Update processImage.js](https://github.com/papandreou/express-processimage/commit/12d8b75acd72fed0a02fbf71f8337d193eb90e64) ([alexander soriano](mailto:radica_dude@yahoo.com)) 55 | - [Fix typo in .eslintignore](https://github.com/papandreou/express-processimage/commit/5222f0380c583ae44cd25ec5c7c93bfdb0e4799c) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 56 | - [Add .nyc\_output to .prettierignore](https://github.com/papandreou/express-processimage/commit/c0ee73804042d4cf7634500a78ac1438e25a3593) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 57 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v10.2.2...v10.2.3) 58 | 59 | ### v10.2.2 (2021-09-22) 60 | 61 | #### Pull requests 62 | 63 | - [#161](https://github.com/papandreou/express-processimage/pull/161) Added support for configuring 'failOnError' for Sharp engine via 'impro' ([Priyank Parashar](mailto:paras20xx@gmail.com)) 64 | 65 | #### Commits to master 66 | 67 | - [Now using impro@~0.11.0 to enable configuring 'failOnError' for Sharp engine via 'impro'](https://github.com/papandreou/express-processimage/commit/134e08caf918abe903f13cde9365b3faef7f8d50) ([Priyank Parashar](mailto:paras20xx@gmail.com)) 68 | 69 | ### v10.2.1 (2021-09-21) 70 | 71 | #### Pull requests 72 | 73 | - [#160](https://github.com/papandreou/express-processimage/pull/160) Requests were getting hanged with 'secondGuessSourceContentType' for empty images ([Priyank Parashar](mailto:paras20xx@gmail.com)) 74 | - [#155](https://github.com/papandreou/express-processimage/pull/155) Upgrade mocha to version 9.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 75 | - [#152](https://github.com/papandreou/express-processimage/pull/152) Upgrade sinon to version 11.1.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 76 | - [#153](https://github.com/papandreou/express-processimage/pull/153) Upgrade eslint-plugin-mocha to version 9.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 77 | - [#151](https://github.com/papandreou/express-processimage/pull/151) Upgrade impro to version 0.10.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 78 | - [#150](https://github.com/papandreou/express-processimage/pull/150) Upgrade sharp to version 0.28.2 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 79 | 80 | #### Commits to master 81 | 82 | - [prettier --write '\*\*\/\*.{js,json,md}'](https://github.com/papandreou/express-processimage/commit/f4e44440d28904067be35a8388465d9903c70d5f) ([Andreas Lind](mailto:andreas.lind@workday.com)) 83 | - [Update prettier to version 2.3.0](https://github.com/papandreou/express-processimage/commit/2c3419d6a0eff118831394735d034b255f8de47e) ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 84 | 85 | ### v10.2.0 (2021-05-05) 86 | 87 | #### Pull requests 88 | 89 | - [#145](https://github.com/papandreou/express-processimage/pull/145) Upgrade sharp to version 0.28.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 90 | - [#144](https://github.com/papandreou/express-processimage/pull/144) Upgrade sinon to version 10.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 91 | - [#140](https://github.com/papandreou/express-processimage/pull/140) Upgrade magicpen-prism to version 5.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 92 | - [#141](https://github.com/papandreou/express-processimage/pull/141) Upgrade pngquant to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 93 | - [#139](https://github.com/papandreou/express-processimage/pull/139) Upgrade mocha to version 8.3.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 94 | - [#138](https://github.com/papandreou/express-processimage/pull/138) Upgrade impro to version 0.9.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 95 | - [#137](https://github.com/papandreou/express-processimage/pull/137) Upgrade sharp to version 0.27.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 96 | - [#136](https://github.com/papandreou/express-processimage/pull/136) Upgrade eslint-config-prettier to version 7.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 97 | - [#133](https://github.com/papandreou/express-processimage/pull/133) Upgrade jpegtran to version 2.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 98 | - [#135](https://github.com/papandreou/express-processimage/pull/135) Upgrade eslint-plugin-standard to version 5.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 99 | - [#134](https://github.com/papandreou/express-processimage/pull/134) Upgrade svgfilter to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 100 | - [#131](https://github.com/papandreou/express-processimage/pull/131) Upgrade optipng to version 3.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 101 | - [#132](https://github.com/papandreou/express-processimage/pull/132) Upgrade pngcrush to version 3.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 102 | - [#129](https://github.com/papandreou/express-processimage/pull/129) Upgrade unexpected-image to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 103 | - [#128](https://github.com/papandreou/express-processimage/pull/128) Upgrade unexpected-express to version 13.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 104 | - [#124](https://github.com/papandreou/express-processimage/pull/124) Upgrade unexpected to version 12.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 105 | - [#125](https://github.com/papandreou/express-processimage/pull/125) Upgrade unexpected-resemble to version 5.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 106 | - [#126](https://github.com/papandreou/express-processimage/pull/126) Upgrade unexpected-sinon to version 11.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 107 | - [#127](https://github.com/papandreou/express-processimage/pull/127) Upgrade prettier to version 2.2.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 108 | - [#123](https://github.com/papandreou/express-processimage/pull/123) Upgrade eslint-config-standard to version 16.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 109 | - [#121](https://github.com/papandreou/express-processimage/pull/121) Upgrade eslint-config-standard to version 15.0.0 ([Andreas Lind](mailto:andreas.lind@peakon.com), [depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 110 | 111 | #### Commits to master 112 | 113 | - [Reduce size by packaging only bin and lib directories.](https://github.com/papandreou/express-processimage/commit/e07247e47940fade911b4ff9f2f68b165f3d5612) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 114 | - [Sync the second package installation list after 61a68bc.](https://github.com/papandreou/express-processimage/commit/679e9f745be8df651aa603e8ceafab2691c7a48d) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 115 | - [Switch to GitHub Actions](https://github.com/papandreou/express-processimage/commit/61a68bc8806aa1e7f87f71f348a2a3952b8db016) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 116 | - [Revert "Update sharp to version 0.28.0"](https://github.com/papandreou/express-processimage/commit/13a7d5914bae79ed7cd7ec0280e0a9fde840bd0d) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 117 | - [Fix eslint-plugin-prettier usage](https://github.com/papandreou/express-processimage/commit/80e65403d85b99c03d1a65036fc6c501ef949876) ([Andreas Lind](mailto:andreas.lind@workday.com)) 118 | - [+3 more](https://github.com/papandreou/express-processimage/compare/v10.1.0...v10.2.0) 119 | 120 | ### v10.1.0 (2020-09-28) 121 | 122 | - [#120](https://github.com/papandreou/express-processimage/pull/120) Upgrade to hijackresponse 5 ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 123 | - [#118](https://github.com/papandreou/express-processimage/pull/118) Sharp 0.26.0 ([Alex J Burke](mailto:alex@alexjeffburke.com)) 124 | - [#116](https://github.com/papandreou/express-processimage/pull/116) Upgrade prettier to version 2.1.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 125 | 126 | ### v10.0.0 (2020-08-15) 127 | 128 | #### Pull requests 129 | 130 | - [#115](https://github.com/papandreou/express-processimage/pull/115) Upgrade inkscape to version 3.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 131 | - [#114](https://github.com/papandreou/express-processimage/pull/114) Upgrade eslint-plugin-mocha to version 8.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 132 | - [#113](https://github.com/papandreou/express-processimage/pull/113) Upgrade icc to version 2.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 133 | 134 | #### Commits to master 135 | 136 | - [Travis: Add node.js 14](https://github.com/papandreou/express-processimage/commit/60fa227be79f727124ca9084edf0390aea315cfa) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 137 | - [Remove node.js 8 support \(semver-major\)](https://github.com/papandreou/express-processimage/commit/0f7ced7edf49179aa68db7b43589882c1cb954e0) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 138 | - [npm uninstall icc](https://github.com/papandreou/express-processimage/commit/d0c0ec5f9808f4b5c1555f1bcfbe4e231bc7365f) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 139 | 140 | ### v9.0.3 (2020-05-22) 141 | 142 | #### Pull requests 143 | 144 | - [#110](https://github.com/papandreou/express-processimage/pull/110) Update impro to v0.7.1 ([Peter Müller](mailto:munter@fumle.dk)) 145 | - [#108](https://github.com/papandreou/express-processimage/pull/108) Upgrade eslint-plugin-mocha to version 7.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 146 | - [#107](https://github.com/papandreou/express-processimage/pull/107) Upgrade eslint to version 7.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 147 | - [#101](https://github.com/papandreou/express-processimage/pull/101) Upgrade sinon to version 9.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 148 | 149 | #### Commits to master 150 | 151 | - [Fix typo](https://github.com/papandreou/express-processimage/commit/2a1db92763c97c6b7cdba32bf84e2acfa2aded68) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 152 | - [Only lint on node.js 12](https://github.com/papandreou/express-processimage/commit/2f434d7c743504260573c44bab6a9d7eca206c73) ([Andreas Lind](mailto:andreas.lind@peakon.com)) 153 | - [Also use prettier for .md](https://github.com/papandreou/express-processimage/commit/f2c3a2e36034e95c1305981ace50267d00863862) ([Andreas Lind](mailto:andreas.lind@peakon.com)) 154 | - [prettier --write '\*\*\/\*.js'](https://github.com/papandreou/express-processimage/commit/7e3f7574c7202c450f3acc8b079693577a732d55) ([Andreas Lind](mailto:andreas.lind@peakon.com)) 155 | - [Update prettier to version 2.0.2](https://github.com/papandreou/express-processimage/commit/448af85c9ac2a904cc435038e6382ce0588a10e8) ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 156 | 157 | ### v9.0.2 (2020-02-18) 158 | 159 | - [Support an engine query string parameter without arguments.](https://github.com/papandreou/express-processimage/commit/0eafbf0f214a13f55753c205ab9f9362e90b6f36) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 160 | 161 | ### v9.0.1 (2020-02-16) 162 | 163 | #### Pull requests 164 | 165 | - [#97](https://github.com/papandreou/express-processimage/pull/97) Upgrade mocha to version 7.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 166 | - [#96](https://github.com/papandreou/express-processimage/pull/96) Upgrade magicpen-prism to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 167 | - [#95](https://github.com/papandreou/express-processimage/pull/95) Upgrade eslint-plugin-node to version 11.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 168 | - [#93](https://github.com/papandreou/express-processimage/pull/93) Upgrade nyc to version 15.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 169 | - [#94](https://github.com/papandreou/express-processimage/pull/94) Upgrade sinon to version 8.0.1 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 170 | 171 | #### Commits to master 172 | 173 | - [Test on node 12 in CI.](https://github.com/papandreou/express-processimage/commit/8c20c358c9d76dd8108abcf1766fb58aac67dd68) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 174 | - [Bump impro to ~0.6.0.](https://github.com/papandreou/express-processimage/commit/dda137dc18f4078d6d9b1a5943e833b68ec95a10) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 175 | - [Support "+" as a separator in query string for engine operation args.](https://github.com/papandreou/express-processimage/commit/6bdedf8b4a687dff6f1c3a8cadbd3e6c0f1f85f5) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 176 | - [Convert resize when it is specified using a plus operator.](https://github.com/papandreou/express-processimage/commit/46e49a18d08fbe9e50ad9b21cfe181de265ec8ef) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 177 | - [Further tweak README.](https://github.com/papandreou/express-processimage/commit/49081ef431f1855264666e2810509ef61cdb3cf5) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 178 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v9.0.0...v9.0.1) 179 | 180 | ### v9.0.0 (2019-11-23) 181 | 182 | #### Pull requests 183 | 184 | - [#92](https://github.com/papandreou/express-processimage/pull/92) impro port ([Alex J Burke](mailto:alex@alexjeffburke.com)) 185 | - [#91](https://github.com/papandreou/express-processimage/pull/91) Upgrade prettier to version 1.19.1 ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 186 | - [#90](https://github.com/papandreou/express-processimage/pull/90) Upgrade eslint-plugin-node to version 10.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 187 | - [#89](https://github.com/papandreou/express-processimage/pull/89) Upgrade eslint-config-standard to version 14.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 188 | - [#88](https://github.com/papandreou/express-processimage/pull/88) Upgrade gifsicle-stream to version 1.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 189 | - [#87](https://github.com/papandreou/express-processimage/pull/87) Upgrade sharp to version 0.23.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 190 | - [#84](https://github.com/papandreou/express-processimage/pull/84) Upgrade unexpected-resemble to version 4.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 191 | - [#85](https://github.com/papandreou/express-processimage/pull/85) Upgrade unexpected-express to version 12.0.0 ([depfu[bot]](mailto:23717796+depfu[bot]@users.noreply.github.com)) 192 | - [#82](https://github.com/papandreou/express-processimage/pull/82) Upgrade prettier to version 1.18.2 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 193 | - [#81](https://github.com/papandreou/express-processimage/pull/81) Upgrade unexpected-image to version 3.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 194 | - [#80](https://github.com/papandreou/express-processimage/pull/80) Upgrade pngquant to version 3.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 195 | - [#79](https://github.com/papandreou/express-processimage/pull/79) Upgrade unexpected-http to version 7.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 196 | - [#78](https://github.com/papandreou/express-processimage/pull/78) Upgrade nyc to version 14.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 197 | - [#77](https://github.com/papandreou/express-processimage/pull/77) Upgrade prettier to version 1.17.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 198 | - [#76](https://github.com/papandreou/express-processimage/pull/76) Upgrade mocha to version 6.1.2 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 199 | - [#73](https://github.com/papandreou/express-processimage/pull/73) Upgrade magicpen to version 6.0.2 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 200 | 201 | #### Commits to master 202 | 203 | - [Update the README after the introduction of impro.](https://github.com/papandreou/express-processimage/commit/38547e4e0298432a2a8eb7c99262a65538838c8a) ([Alex J Burke](mailto:alex@alexjeffburke.com)) 204 | - [Switch back to the official exif-reader now that devongovett\/exif-reader\#5 got merged](https://github.com/papandreou/express-processimage/commit/5333cb0231fd7dbcc7ab3bae31641dbb101a7d02) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 205 | - [Restructure tests a bit to avoid upsetting mocha\/no-identical-title](https://github.com/papandreou/express-processimage/commit/092ad8016da27f5f72948aea1a43059d35c5b5a1) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 206 | - [Fix lint](https://github.com/papandreou/express-processimage/commit/1885e9d3020105c52226fd0e523d58e526a9c9e0) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 207 | - [eslint --fix . && prettier --write '\*\*\/\*.js'](https://github.com/papandreou/express-processimage/commit/5f548a0c96903015472bfcd071c66294b56787a4) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 208 | - [+15 more](https://github.com/papandreou/express-processimage/compare/v8.1.0...v9.0.0) 209 | 210 | ### v8.1.0 (2019-03-05) 211 | 212 | #### Pull requests 213 | 214 | - [#72](https://github.com/papandreou/express-processimage/pull/72) Upgrade hijackresponse to version 4.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 215 | - [#71](https://github.com/papandreou/express-processimage/pull/71) Fix failing test on node 10 ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 216 | - [#69](https://github.com/papandreou/express-processimage/pull/69) Add docker development container based on Travis CI setup ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 217 | - [#68](https://github.com/papandreou/express-processimage/pull/68) Replace eslint-plugin-prettier with prettier --check ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [Gustav Nikolaj Olsen](mailto:gno@one.com)) 218 | - [#67](https://github.com/papandreou/express-processimage/pull/67) Delete leftover files from jshint ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 219 | - [#61](https://github.com/papandreou/express-processimage/pull/61) Upgrade optipng to version 2.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 220 | - [#59](https://github.com/papandreou/express-processimage/pull/59) Upgrade sinon to version 7.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 221 | - [#57](https://github.com/papandreou/express-processimage/pull/57) Upgrade sharp to version 0.21.0 ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 222 | - [#56](https://github.com/papandreou/express-processimage/pull/56) Upgrade eslint-plugin-prettier to version 3.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 223 | 224 | #### Commits to master 225 | 226 | - [Ignore vs code settings files](https://github.com/papandreou/express-processimage/commit/7f401752668305b7fb8e532ef81a5d2ff27f951e) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 227 | - [Update jpegtran to ^1.0.6](https://github.com/papandreou/express-processimage/commit/e722f05b06db587507d9610087a6cb05a7aaf131) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 228 | - [Update pngcrush to ^2.0.1](https://github.com/papandreou/express-processimage/commit/3c1e3e3e4fb60b9731eca7f69655870e0d435d7a) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 229 | - [Update pngquant to ^2.0.1](https://github.com/papandreou/express-processimage/commit/e8d1747832ca9c3173557ccd6473e51679d04f2d) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 230 | - [Update prettier to version 1.16.0](https://github.com/papandreou/express-processimage/commit/05dc03ac78c1c0c2041c48a7ad0f6dcf2f6c46a5) ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 231 | - [+17 more](https://github.com/papandreou/express-processimage/compare/v8.0.2...v8.1.0) 232 | 233 | ### v8.0.2 (2018-08-26) 234 | 235 | - [Flush the operations pipeline when switching to a different engine, fixes \#54](https://github.com/papandreou/express-processimage/commit/74195affdf872f5a6f7774a5987866d45359b132) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 236 | - [Switch back to eslint-config-pretty-standard](https://github.com/papandreou/express-processimage/commit/4df3ff54b028767eada7db630ee7e03f921872b1) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 237 | 238 | ### v8.0.1 (2018-08-01) 239 | 240 | - [#53](https://github.com/papandreou/express-processimage/pull/53) Fixed .ICO resize throwing 500 ([Ashish Soni](mailto:ashish@one.com)) 241 | - [#51](https://github.com/papandreou/express-processimage/pull/51) Upgrade pngcrush to version 2.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 242 | 243 | ### v8.0.0 (2018-06-25) 244 | 245 | #### Pull requests 246 | 247 | - [#46](https://github.com/papandreou/express-processimage/pull/46) Upgrade sinon to version 6.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 248 | - [#38](https://github.com/papandreou/express-processimage/pull/38) Upgrade magicpen to version 5.12.0 ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 249 | - [#42](https://github.com/papandreou/express-processimage/pull/42) Upgrade coveralls to version 3.0.1 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 250 | - [#44](https://github.com/papandreou/express-processimage/pull/44) Upgrade icc to version 1.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 251 | - [#45](https://github.com/papandreou/express-processimage/pull/45) Upgrade hijackresponse to version 3.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 252 | - [#36](https://github.com/papandreou/express-processimage/pull/36) Upgrade mocha to version 5.2.0 ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 253 | - [#37](https://github.com/papandreou/express-processimage/pull/37) Upgrade magicpen-prism to version 2.4.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 254 | - [#39](https://github.com/papandreou/express-processimage/pull/39) Upgrade istanbul to version 0.4.5 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 255 | - [#33](https://github.com/papandreou/express-processimage/pull/33) Upgrade unexpected-express to version 10.1.0 ([Andreas Lind](mailto:andreaslindpetersen@gmail.com), [depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 256 | - [#35](https://github.com/papandreou/express-processimage/pull/35) Upgrade sinon to version 5.0.10 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 257 | - [#32](https://github.com/papandreou/express-processimage/pull/32) Upgrade unexpected-http to version 6.0.0 ([depfu[bot]](mailto:depfu[bot]@users.noreply.github.com)) 258 | 259 | #### Commits to master 260 | 261 | - [Drop node.js 4 support \(semver-major\)](https://github.com/papandreou/express-processimage/commit/654e14b8a853d31f0bf4c1ee3828bba8a52acf6a) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 262 | - [Update eslint-config-pretty-standard to ^2.0.0](https://github.com/papandreou/express-processimage/commit/2ef50b442dc1ce7e1fd66c86793e1b569d107cab) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 263 | - [Switch to eslint-config-pretty-standard-papandreou](https://github.com/papandreou/express-processimage/commit/8173aa11803f20a1f4f94a7c727ba721a4640c01) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 264 | - [eslint --fix .](https://github.com/papandreou/express-processimage/commit/5d219469ee2e2a555da82e23659c2e5661234314) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 265 | - [Fix unnecessary escape in regexp](https://github.com/papandreou/express-processimage/commit/fe6d148406d1ad1d9aa343ed38283d276768fe55) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 266 | - [+11 more](https://github.com/papandreou/express-processimage/compare/v7.9.1...v8.0.0) 267 | 268 | ### v7.9.1 (2018-04-29) 269 | 270 | - [Update sharp to 0.20.2](https://github.com/papandreou/express-processimage/commit/70ba9a85cdfbd2497e67ab13e2935d581f659554) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 271 | - [Update author's email](https://github.com/papandreou/express-processimage/commit/c81b69b4d621a3ad91fb381336ed770305ab500c) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 272 | 273 | ### v7.9.0 (2018-03-20) 274 | 275 | - [#31](https://github.com/papandreou/express-processimage/pull/31) Support setFormat across both sharp and gm. ([Alex J Burke](mailto:alex@alexjeffburke.com)) 276 | 277 | ### v7.8.1 (2018-03-17) 278 | 279 | - [Update sharp to 0.20.1](https://github.com/papandreou/express-processimage/commit/38368e878b6ce3a075c3218ee6b975beecc090de) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 280 | 281 | ### v7.8.0 (2018-03-05) 282 | 283 | - [#30](https://github.com/papandreou/express-processimage/pull/30) ?metadata: Populate orientedWidth and orientedHeight based on the image.Orientation EXIF tag ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 284 | 285 | ### v7.7.0 (2018-03-05) 286 | 287 | - [Update sharp to 0.20.0](https://github.com/papandreou/express-processimage/commit/fe8b860a2a8ae5e0e8bf71307d2bbb360ef7d73b) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 288 | 289 | ### v7.6.1 (2018-03-04) 290 | 291 | - [Update sharp to 0.19.1](https://github.com/papandreou/express-processimage/commit/82d6927d4ef977b1ed9ec4983342b03a00a8b60e) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 292 | - [Travis: Build with node.js 8 and 9 instead of 5 and 7](https://github.com/papandreou/express-processimage/commit/cf9501a2cd452792e683b04681eb0045d7d0726e) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 293 | 294 | ### v7.6.0 (2018-01-13) 295 | 296 | #### Pull requests 297 | 298 | - [#27](https://github.com/papandreou/express-processimage/pull/27) Permit omitting either the width or the height when resizing again ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 299 | 300 | #### Commits to master 301 | 302 | - [Update sharp to 0.19.0, update fixtures to match the new output](https://github.com/papandreou/express-processimage/commit/519d5558db9a06a4961174c6e92885132ca80801) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com)) 303 | 304 | ### v7.5.0 (2017-09-18) 305 | 306 | - [Update sharp to 0.18.4 + update attention\/entropy crop fixtures](https://github.com/papandreou/express-processimage/commit/280f5a4b9386d7ebc8afd796f37b642ef95d2a91) ([Andreas Lind](mailto:andreas@one.com)) 307 | - [Travis: Don't attempt to upgrade npm in before\_install script](https://github.com/papandreou/express-processimage/commit/a843121ff5b7dd3cebe0e2b4e12dfd235e80ba83) ([Andreas Lind](mailto:andreas@one.com)) 308 | 309 | ### v7.4.0 (2017-05-15) 310 | 311 | - [#26](https://github.com/papandreou/express-processimage/pull/26) Extend gm background operation to match a wider set of hex patterns t… ([Peter Müller](mailto:munter@fumle.dk)) 312 | 313 | ### v7.3.1 (2017-04-27) 314 | 315 | - [Update inkscape to 1.1.1](https://github.com/papandreou/express-processimage/commit/1f4e2ba8003ee6ecaee654ebafca23407c7d7a15) ([Andreas Lind](mailto:andreas@one.com)) 316 | - [Remove sharp workaround now that https:\/\/github.com\/lovell\/sharp\/pull\/735 was merged](https://github.com/papandreou/express-processimage/commit/b5e9cb147268bcacad8f6796f728569afa74e0ea) ([Andreas Lind](mailto:andreas@one.com)) 317 | - [Update sharp to 0.17.3.](https://github.com/papandreou/express-processimage/commit/6c03ce36539c15c8da4cccec5584ffe62ba9a3e6) ([Andreas Lind](mailto:andreas@one.com)) 318 | - [Test: Tolerate differences in the 'gm identify' output.](https://github.com/papandreou/express-processimage/commit/207677eab4ab3b8098267a4ecd43e2b711a44dc0) ([Andreas Lind](mailto:andreas@one.com)) 319 | - [Add missing \/\* global \*\/ declaration to test.](https://github.com/papandreou/express-processimage/commit/24c4c7269eb6be35c37a66db1efcb844d2a19e52) ([Andreas Lind](mailto:andreas@one.com)) 320 | 321 | ### v7.3.0 (2017-03-16) 322 | 323 | - [Update sharp to 0.17.2.](https://github.com/papandreou/express-processimage/commit/365965a3467b3c095231916f36eb36465f75a5d0) ([Andreas Lind](mailto:andreas@one.com)) 324 | - [Add support for crop=attention and crop=entropy when using the sharp engine](https://github.com/papandreou/express-processimage/commit/85fcfe2e118dbe4d90720e3f71f0c40b67d79d6e) ([Andreas Lind](mailto:andreas@one.com)) 325 | 326 | ### v7.2.1 (2017-03-13) 327 | 328 | - [Fix: quality option deprecation warning \(\#23\)](https://github.com/papandreou/express-processimage/commit/78285ec7fa3fdc6a230184f40996014e7f290330) ([Andreas Lind](mailto:andreas@one.com)) 329 | - [Remove gm parameter in a test that's supposed to utilize sharp.](https://github.com/papandreou/express-processimage/commit/865c7765438173738d46ae3ff3659460ef48ab6f) ([Andreas Lind](mailto:andreas@one.com)) 330 | - [Tests: Use a sinon sandbox.](https://github.com/papandreou/express-processimage/commit/87f65295e608c9262cae529ac3bbdc3b5e3f32c1) ([Andreas Lind](mailto:andreas@one.com)) 331 | - [Update unexpected-sinon to ^10.7.1.](https://github.com/papandreou/express-processimage/commit/6bfc0c50e3d09a316f7c057b75c45bef824dde12) ([Andreas Lind](mailto:andreas@one.com)) 332 | 333 | ### v7.2.0 (2017-02-08) 334 | 335 | - [Update inkscape to 1.1.0, jpegtran to 1.0.5, and pngquant to 1.2.0.](https://github.com/papandreou/express-processimage/commit/d4d978a9cd5980c4a0df52418c5c66e51bc1f6eb) ([Andreas Lind](mailto:andreas@one.com)) 336 | 337 | ### v7.1.1 (2017-01-12) 338 | 339 | - [#20](https://github.com/papandreou/express-processimage/pull/20) Browsersync second round ([Peter Müller](mailto:munter@fumle.dk)) 340 | 341 | ### v7.1.0 (2017-01-11) 342 | 343 | - [Fix lint etc.](https://github.com/papandreou/express-processimage/commit/638ef9cb950322110ceff34e85218db7c4a6d07e) ([Andreas Lind](mailto:andreas@one.com)) 344 | - [Replace jshint with eslint.](https://github.com/papandreou/express-processimage/commit/3339d57b415b8bd4cd6975f5968ef1f0d9774a1c) ([Andreas Lind](mailto:andreas@one.com)) 345 | 346 | ### v7.0.0 (2016-12-20) 347 | 348 | - [Make svgfilter a dev dep. It's very slow to require, and probably not used widely.](https://github.com/papandreou/express-processimage/commit/85c9de83f061d63dd622eb39364224061d847a91) ([Andreas Lind](mailto:andreas@one.com)) 349 | - [Travis: Build with node.js 6 and 7 as well.](https://github.com/papandreou/express-processimage/commit/c40d10508e6a60a9a9f5d763b28b3f117223f300) ([Andreas Lind](mailto:andreas@one.com)) 350 | - [Travis: Drop node.js 0.10 and 0.12 support \(breaks with sharp 0.17.0\).](https://github.com/papandreou/express-processimage/commit/4210121857654bc48b57b8f9e38af2347a8a7eeb) ([Andreas Lind](mailto:andreas@one.com)) 351 | 352 | ### v6.3.0 (2016-12-16) 353 | 354 | - [Update sharp to 0.17.0.](https://github.com/papandreou/express-processimage/commit/37c25d1b450b1f5aa3edd9a89f7fb79bae7a26ac) ([Andreas Lind](mailto:andreas@one.com)) 355 | - [Update express-hijackresponse to 2.0.1.](https://github.com/papandreou/express-processimage/commit/f429a260f1ff03997c6a2da397fef15cba49dac2) ([Andreas Lind](mailto:andreas@one.com)) 356 | 357 | ### v6.2.2 (2016-11-11) 358 | 359 | - [Make secondGuessContentType a bit less fragile when the downstream middleware ends before the first data event.](https://github.com/papandreou/express-processimage/commit/309801ba7e693c4a69a801063a26658a866c4794) ([Andreas Lind](mailto:andreas@one.com)) 360 | - [Fix ?metadata when a 304 is served and secondGuessContentType is enabled.](https://github.com/papandreou/express-processimage/commit/711cb2e058161b9b7abad8812a808d01fc03cf04) ([Andreas Lind](mailto:andreas@one.com)) 361 | - [Test conditional GET support for ?metadata](https://github.com/papandreou/express-processimage/commit/d15f15f74c8fc8c17f676d94b5f775eb7ece7725) ([Andreas Lind](mailto:andreas@one.com)) 362 | 363 | ### v6.2.1 (2016-11-11) 364 | 365 | - [Update pngcrush to 1.1.1.](https://github.com/papandreou/express-processimage/commit/912f97e6d534c826b833d8052660eaf52a59015d) ([Andreas Lind](mailto:andreas@one.com)) 366 | 367 | ### v6.2.0 (2016-11-09) 368 | 369 | - [Allow ?metadata even when the C-T is unlisted in allowedImageSourceContentTypes.](https://github.com/papandreou/express-processimage/commit/8e27f0e6ba7fbe63db7a1fc62864f974f6d88313) ([Andreas Lind](mailto:andreas@one.com)) 370 | - [Update unexpected et al., use liberal version ranges.](https://github.com/papandreou/express-processimage/commit/33fab6f52d1d28daaaca22fb352b17e879a77084) ([Andreas Lind](mailto:andreas@one.com)) 371 | 372 | ### v6.1.0 (2016-09-29) 373 | 374 | - [Add support for an 'allowedImageSourceContentTypes' option.](https://github.com/papandreou/express-processimage/commit/6f48997571f36585a4fa485b8993eac6e3689a01) ([Andreas Lind](mailto:andreas@one.com)) 375 | 376 | ### v6.0.0 (2016-09-14) 377 | 378 | #### Pull requests 379 | 380 | - [#18](https://github.com/papandreou/express-processimage/pull/18) Call sharp.max\(\) when resizing so the semantics of resize=w,h are the same as for GraphicsMagick. ([Andreas Lind](mailto:andreas@one.com)) 381 | 382 | #### Commits to master 383 | 384 | - [Switch to gm-papandreou 1.23.0-patch1 \(no longer causes a stray 'error' event when the gm binary isn't found\).](https://github.com/papandreou/express-processimage/commit/60c14e64569a26e49ad2ef739b40679d9ac97615) ([Andreas Lind](mailto:andreas@one.com)) 385 | - [getMockFileNameForContentType: Consistenly pass a dot before the extension.](https://github.com/papandreou/express-processimage/commit/447c03d1e83d71c1a0c4e8d1ac4362171e7bbd02) ([Andreas Lind](mailto:andreas@one.com)) 386 | 387 | ### v5.12.0 (2016-08-18) 388 | 389 | - [Update sharp to 0.16.0, update test fixture due to a minor change in the resize or crop algorithm.](https://github.com/papandreou/express-processimage/commit/16f5b66d07d16f4e045815c3db2f751993d86030) ([Andreas Lind](mailto:andreas@one.com)) 390 | 391 | ### v5.11.0 (2016-08-18) 392 | 393 | - [Update exif-reader-paras20xx to 1.1.1. Adds resilience against corrupt exif data.](https://github.com/papandreou/express-processimage/commit/84e9cdc5de551d3ff9163e0069bb4dc226763dad) ([Andreas Lind](mailto:andreas@one.com)) 394 | - [Seems like the canvas module used doesn't support GIF files on a stock Ubuntu 16.04. Avoid using it with GIF files for now.](https://github.com/papandreou/express-processimage/commit/1929d3949cf92b6793e230e5a7c88eaa51aa8515) ([Andreas Lind](mailto:andreas@one.com)) 395 | - [Update sharp to 0.15.1.](https://github.com/papandreou/express-processimage/commit/2f7c288f6eefd16fb911d18189933e186b8a7e28) ([Andreas Lind](mailto:andreas@one.com)) 396 | 397 | ### v5.10.2 (2016-06-30) 398 | 399 | - [Updated animated-gif-detector to 1.2.0](https://github.com/papandreou/express-processimage/commit/a7d8988833e2098e8d991157e8242bab454fd3fb) ([Priyank Parashar](mailto:paras20xx@users.noreply.github.com)) 400 | 401 | ### v5.10.1 (2016-05-31) 402 | 403 | - [Don't break when there is only a "modifier" filter left after the invalid operations have been trimmed.](https://github.com/papandreou/express-processimage/commit/2692a535a32cc0d81eccce571e64722f00444d12) ([Andreas Lind](mailto:andreas@one.com)) 404 | 405 | ### v5.10.0 (2016-05-24) 406 | 407 | - [Update sharp to 0.15.0, and switch back to the official release.](https://github.com/papandreou/express-processimage/commit/273fe37c15fc513d07df6fa6004e42410d1af91d) ([Andreas Lind](mailto:andreas@one.com)) 408 | 409 | ### v5.9.0 (2016-05-10) 410 | 411 | - [Update svgfilter to 1.2.0.](https://github.com/papandreou/express-processimage/commit/8489b2f9db4d522c25318a69e345ddf16bcd1f99) ([Andreas Lind](mailto:andreas@one.com)) 412 | - [Update unexpected to 10.13.2.](https://github.com/papandreou/express-processimage/commit/8b5ab3aa271a323005cb5eeeaf050aa7e4f43eab) ([Andreas Lind](mailto:andreas@one.com)) 413 | 414 | ### v5.8.4 (2016-05-03) 415 | 416 | - [Now using gifsicle-stream@0.3.1](https://github.com/papandreou/express-processimage/commit/16e26cce7e45ee1280fc408330b59d7ddaf34ee9) ([Priyank Parashar](mailto:priyank@one.com)) 417 | 418 | ### v5.8.3 (2016-05-02) 419 | 420 | - [Using gifsicle-stream-paras20xx@0.3.2 now \(will change back to gifsicle-stream when https:\/\/github.com\/oohnoitz\/node-gifsicle-stream\/pull\/4 gets accepted\)](https://github.com/papandreou/express-processimage/commit/0a8dccd55fa9b139441c3bf911c3f959a6926066) ([Priyank Parashar](mailto:priyank@one.com)) 421 | 422 | ### v5.8.2 (2016-04-29) 423 | 424 | - [?metadata: Don't include -metadata in the etag property of the returned JSON.](https://github.com/papandreou/express-processimage/commit/c5d61a47b696ed49f5117eb4d15006a57f349424) ([Andreas Lind](mailto:andreas@one.com)) 425 | 426 | ### v5.8.1 (2016-04-28) 427 | 428 | - [Now using exif-reader-paras20xx: 1.0.0-patch2](https://github.com/papandreou/express-processimage/commit/a9c618c413507cade499ba9b04a20502cf80ff8c) ([Priyank Parashar](mailto:priyank@one.com)) 429 | 430 | ### v5.8.0 (2016-04-27) 431 | 432 | - [Only process GET and HEAD requests.](https://github.com/papandreou/express-processimage/commit/88abdcc79b217c02731ba8930ade3ebe61d51b5c) ([Andreas Lind](mailto:andreas@one.com)) 433 | - [Fix mangling of the If-None-Match header so that the downstream middleware has a shot at generating a 304.](https://github.com/papandreou/express-processimage/commit/3997d691e86eeeea8576bb9c42d86269964c94ad) ([Andreas Lind](mailto:andreas@one.com)) 434 | - [Fix another test with node.js 0.12+.](https://github.com/papandreou/express-processimage/commit/d601048ebfa4e83ab4cf12f786d95e826840fd98) ([Andreas Lind](mailto:andreas@one.com)) 435 | - [Try to fix setImmediate vs. setTimeout race in test.](https://github.com/papandreou/express-processimage/commit/2d9b2948cab9e87456f36f4e099ee4873f934635) ([Andreas Lind](mailto:andreas@one.com)) 436 | - [Fix lint.](https://github.com/papandreou/express-processimage/commit/0c12f382b87c0c87e1be520d8a5fc12b37152ba5) ([Andreas Lind](mailto:andreas@one.com)) 437 | - [+4 more](https://github.com/papandreou/express-processimage/compare/v5.7.0...v5.8.0) 438 | 439 | ### v5.7.0 (2016-04-25) 440 | 441 | - [Make sure to close the connection properly when an invalid operation is attempted.](https://github.com/papandreou/express-processimage/commit/053869ca79479a1c5e8a384a6999a5863e1735f5) ([Andreas Lind](mailto:andreas@one.com)) 442 | - [Test suite: Drop the skipIf construct now that sharp is always available.](https://github.com/papandreou/express-processimage/commit/6fc268d4249eacdeccbd27f03209f7532e695cb8) ([Andreas Lind](mailto:andreas@one.com)) 443 | - [Minor version bump for sharp library](https://github.com/papandreou/express-processimage/commit/162f51d1951eed31554d8d49c3fdb2e700887fbe) ([Priyank Parashar](mailto:priyank@one.com)) 444 | 445 | ### v5.6.0 446 | 447 | - [Now using sharp library v0.14.0 \(patched version\)](https://github.com/papandreou/express-processimage/commit/d48e48d3ee255ac426b822e96f7140bc3bd28fe5) ([Priyank Parashar](mailto:priyank@one.com)) 448 | - [Revert "Now using sharp library v0.14.0 \(patched version\)"](https://github.com/papandreou/express-processimage/commit/1d4b374f35e3effa4ef5925cdda0c4181071e9ec) ([Priyank Parashar](mailto:priyank@one.com)) 449 | - [Now using sharp library v0.14.0 \(patched version\)](https://github.com/papandreou/express-processimage/commit/0360c7dbdc2598e21757031ab3247b484b77b2a7) ([Priyank Parashar](mailto:priyank@one.com)) 450 | 451 | ### v5.5.0 (2016-04-15) 452 | 453 | - [Added comment about a sharp.metadata caveat.](https://github.com/papandreou/express-processimage/commit/c35e1b2316afcd80832df3b121d55dabe5a1f5ef) ([Andreas Lind](mailto:andreas@one.com)) 454 | - [Destroy the underlying hijacked response when cleaning up to avoid leaks.](https://github.com/papandreou/express-processimage/commit/46e55971b2905748f06e3b3d76c4d71665c908ce) ([Andreas Lind](mailto:andreas@one.com)) 455 | - [Switch back to hijackresponse and use { disableBackpressure: true }.](https://github.com/papandreou/express-processimage/commit/29d07337cf56a8a75ca73293ffdc0a525e483855) ([Andreas Lind](mailto:andreas@one.com)) 456 | 457 | ### v5.4.1 (2016-04-14) 458 | 459 | - [Be more aggressive about cleaning up internally buffered chunks in readable streams.](https://github.com/papandreou/express-processimage/commit/a3e36cdd499e6fb4baefe96fa1f37422f0c7a682) ([Andreas Lind](mailto:andreas@one.com)) 460 | 461 | ### v5.4.0 (2016-04-14) 462 | 463 | - [Add secondGuessSourceContentType mode.](https://github.com/papandreou/express-processimage/commit/62685077f6aa2ee671f74c1bb1319d76da4d795a) ([Andreas Lind](mailto:andreas@one.com)) 464 | 465 | ### v5.3.2 (2016-04-14) 466 | 467 | - [Remove incomplete etagFragments housekeeping.](https://github.com/papandreou/express-processimage/commit/79e33af8bdb54010e084b9e8230b5aec82ba2fb9) ([Andreas Lind](mailto:andreas@one.com)) 468 | - [Try to prevent more memory leaks by using .once and cleaning up event listeners on error and premature close.](https://github.com/papandreou/express-processimage/commit/bb578dd04644ae2711e411acf1a0d3d74f012722) ([Andreas Lind](mailto:andreas@one.com)) 469 | - [Fix test.](https://github.com/papandreou/express-processimage/commit/7e57280d4972a842518f5deee33a725d16c67d95) ([Andreas Lind](mailto:andreas@one.com)) 470 | 471 | ### v5.3.1 (2016-04-13) 472 | 473 | - [Try to avoid a memory leak in the ?metadata code.](https://github.com/papandreou/express-processimage/commit/14a4db1dc4454c9743ff10cbd083a43fc4656d6d) ([Andreas Lind](mailto:andreas@one.com)) 474 | - [Switch to sharp-papandreou \(attempts to fix potential memory leaks\).](https://github.com/papandreou/express-processimage/commit/71c218490631a492accee44c0b2f5b93ede85cf1) ([Andreas Lind](mailto:andreas@one.com)) 475 | - [Use EventEmitter.once where possible.](https://github.com/papandreou/express-processimage/commit/f047ca7b4c53ec2d5ee215ce81701479736a59fe) ([Andreas Lind](mailto:andreas@one.com)) 476 | 477 | ### v5.3.0 (2016-03-31) 478 | 479 | - [Update jpegtran to 1.0.4.](https://github.com/papandreou/express-processimage/commit/b731576f0e91e3c18ea5de900bc7b9821d16a917) ([Andreas Lind](mailto:andreas@one.com)) 480 | - [cleanUp: Call .end\(\) on all filters to free up resources.](https://github.com/papandreou/express-processimage/commit/ae1628e396e2bec1a3833297d101b9d1d23abe17) ([Andreas Lind](mailto:andreas@one.com)) 481 | - [Update pngquant to 1.0.0.](https://github.com/papandreou/express-processimage/commit/81e5b876bdcb895ac469506c7d803ec4414e3273) ([Andreas Lind](mailto:andreas@one.com)) 482 | - [Re-refixed test with newer node.js versions.](https://github.com/papandreou/express-processimage/commit/0b58d41d755c8a35d4ac84635fa26d2bec9bdb7a) ([Andreas Lind](mailto:andreas@one.com)) 483 | - [Revert "Update gm to 1.21.1."](https://github.com/papandreou/express-processimage/commit/6a532fe6bd10a1fdf6254acc3783feb5cb767334) ([Andreas Lind](mailto:andreas@one.com)) 484 | - [+13 more](https://github.com/papandreou/express-processimage/compare/v5.2.0...v5.3.0) 485 | 486 | ### v5.2.0 (2016-03-30) 487 | 488 | - [Fix test with unpatched Unexpected.](https://github.com/papandreou/express-processimage/commit/9b0be7dc0695a2f73cb955f9901eeca58b0fde38) ([Andreas Lind](mailto:andreas@one.com)) 489 | - [Clean up when the client closes the connection prematurely.](https://github.com/papandreou/express-processimage/commit/d5939a7a541d34dbc89dfb224f6675fde0c2f801) ([Andreas Lind](mailto:andreas@one.com)) 490 | - [Update hijackresponse-nobackpressure to 1.0.2-patch1](https://github.com/papandreou/express-processimage/commit/690dacba62805c1d53f6bd234f4456ef4417911f) ([Andreas Lind](mailto:andreas@one.com)) 491 | - [Whoops, fix the gifsicle-stream-papandreou version number.](https://github.com/papandreou/express-processimage/commit/4646dcf8a20bd464c634f02fa734ea77adac19bf) ([Andreas Lind](mailto:andreas@one.com)) 492 | - [Switch to gifsicle-stream-papandreou to get the destroy method.](https://github.com/papandreou/express-processimage/commit/c72d7ff0b133b56ecb71af1eaf903d54377fe049) ([Andreas Lind](mailto:andreas@one.com)) 493 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v5.1.0...v5.2.0) 494 | 495 | ### v5.1.0 (2016-03-23) 496 | 497 | - [?metadata: Set animated: <boolean> for gifs.](https://github.com/papandreou/express-processimage/commit/9ae5db1b275643e80044d47c5461c80963bcb14d) ([Andreas Lind](mailto:andreas@one.com)) 498 | 499 | ### v5.0.0 (2016-03-23) 500 | 501 | - [Gifsicle always processes --crop before --resize, so execute two gifsicle commands if the two need to come in the opposite order.](https://github.com/papandreou/express-processimage/commit/5d25e58272c0ee2c06fe31647e59a7f8cea04348) ([Andreas Lind](mailto:andreas@one.com)) 502 | 503 | ### v4.9.1 (2016-03-23) 504 | 505 | - [Fix retrieval of metadata for non-images with or without an image extension.](https://github.com/papandreou/express-processimage/commit/6d85b2c450928ddd6f5c24d7483cf107e82ef1d8) ([Andreas Lind](mailto:andreas@one.com)) 506 | 507 | ### v4.9.0 (2016-03-22) 508 | 509 | - [Expose the sharp cache option via options.sharpCache.](https://github.com/papandreou/express-processimage/commit/83d5bfd7eba54c09f0f014212256da2b69ad587d) ([Andreas Lind](mailto:andreas@one.com)) 510 | - [Remove es3:true from .jshintrc.](https://github.com/papandreou/express-processimage/commit/bc0ec74e011d84ee0677027d16c46bc01d001eb7) ([Andreas Lind](mailto:andreas@one.com)) 511 | - [Update dev deps.](https://github.com/papandreou/express-processimage/commit/a47a4e40048a1c4afdd1d8d58c56c602b26045be) ([Andreas Lind](mailto:andreas@one.com)) 512 | - [Don't fail the build if the coveralls.io submission fails.](https://github.com/papandreou/express-processimage/commit/1a56281eb629428050423a9d36c40e0d8ceefb5f) ([Andreas Lind](mailto:andreas@one.com)) 513 | 514 | ### v4.8.4 (2016-03-22) 515 | 516 | - [Reintroduce support for ?metadata=true](https://github.com/papandreou/express-processimage/commit/89c869cf8938d4015f0f426b66bc094c5fe4d25d) ([Andreas Lind](mailto:andreas@one.com)) 517 | 518 | ### v4.8.3 (2016-03-15) 519 | 520 | - [Fixed a bug related to cropping images from top=0 & left=0](https://github.com/papandreou/express-processimage/commit/c794befdcd835441080ae3e55f3ff5083369eb78) ([Priyank Parashar](mailto:priyank@one.com)) 521 | 522 | ### v4.8.2 (2016-03-15) 523 | 524 | - [Fix jshint complaint.](https://github.com/papandreou/express-processimage/commit/cd5d19e5f13aab0146efadabcde4a606dfc81e34) ([Andreas Lind](mailto:andreas@one.com)) 525 | 526 | ### v4.8.1 (2016-03-14) 527 | 528 | - [metadata: Try to derive metadata.format and metadata.contentType from sourceMetadata when sharp reports a format of 'magick'.](https://github.com/papandreou/express-processimage/commit/d9425453d961de500d737872e47bd06f1e330664) ([Andreas Lind](mailto:andreas@one.com)) 529 | 530 | ### v4.8.0 (2016-03-14) 531 | 532 | - [Add parameter validation for all the operations supported by sharp. Part of \#4.](https://github.com/papandreou/express-processimage/commit/04fefde3775af702a667e5204668e8d46a5eb71d) ([Andreas Lind](mailto:andreas@one.com)) 533 | 534 | ### v4.7.0 (2016-03-14) 535 | 536 | - [Support &ignoreAspectRatio for both gm and gifsicle.](https://github.com/papandreou/express-processimage/commit/528372414da93d1df86b4a6dd9e4e7b3686d1a43) ([Andreas Lind](mailto:andreas@one.com)) 537 | - [Use gifsicle even if there is a &crop, but ignore it.](https://github.com/papandreou/express-processimage/commit/58fe9228f081f39710cf60e55d6dc6916aaced33) ([Andreas Lind](mailto:andreas@one.com)) 538 | - [Support &withoutEnlargement with gm, be more resilient to unsupported operations popping up.](https://github.com/papandreou/express-processimage/commit/174a5f844e31862a676caaf9459b3a2dd5615bab) ([Andreas Lind](mailto:andreas@one.com)) 539 | - [Use the same tests for processing gifs with gm and gifsicle.](https://github.com/papandreou/express-processimage/commit/72559f2be17526f3b9b0503e21e6bcba4206d792) ([Andreas Lind](mailto:andreas@one.com)) 540 | - [gm engine: Map &progressive to .interlace\('line'\)](https://github.com/papandreou/express-processimage/commit/3aac4db8e44151b6aecbaa2a031a0bf92b87b454) ([Andreas Lind](mailto:andreas@one.com)) 541 | - [+4 more](https://github.com/papandreou/express-processimage/compare/v4.6.1...v4.7.0) 542 | 543 | ### v4.6.1 (2016-03-10) 544 | 545 | - [Make sure that more of the filterInfo properties come out correctly when the source metadata is not available immediately.](https://github.com/papandreou/express-processimage/commit/8ec2b65d16844c1a6bad1d6a5f4f978ff0347e9d) ([Andreas Lind](mailto:andreas@one.com)) 546 | 547 | ### v4.6.0 (2016-03-10) 548 | 549 | - [Delay the decision about whether to use sharp or gm to when filterInfo.create\(\) is called.](https://github.com/papandreou/express-processimage/commit/8ae402a5d2614addfc18891939c636c92140d421) ([Andreas Lind](mailto:andreas@one.com)) 550 | 551 | ### v4.5.4 (2016-03-07) 552 | 553 | - [Ensure filters are destroyed if a filter error occurs](https://github.com/papandreou/express-processimage/commit/522cd0f9ddd62798aa59a89ab03412b00de65b56) ([Joel Mukuthu](mailto:jmu@one.com)) 554 | 555 | ### v4.5.3 556 | 557 | - [Changes to support resize + crop=center for gm](https://github.com/papandreou/express-processimage/commit/03a588622d5763d9ce79f4eef0a017e4bba1240f) ([Priyank Parashar](mailto:priyank@one.com)) 558 | 559 | ### v4.5.2 (2016-02-29) 560 | 561 | - [Update sharp to 0.13.1.](https://github.com/papandreou/express-processimage/commit/4538e785165c7dbb1e8d11613190341b5caee8e5) ([Andreas Lind](mailto:andreas@one.com)) 562 | 563 | ### v4.5.1 (2016-02-29) 564 | 565 | - [Added pending test for the gravity option when falling back to gm.](https://github.com/papandreou/express-processimage/commit/7dac204e65b2ecbd9cae88739a387b45cefa0611) ([Andreas Lind](mailto:andreas@one.com)) 566 | - [Don't break when sharp throws synchronously.](https://github.com/papandreou/express-processimage/commit/32cfadc43b7fb82a719f0138ce47fab33d673f4d) ([Andreas Lind](mailto:andreas@one.com)) 567 | 568 | ### v4.5.0 (2016-02-16) 569 | 570 | - [Updated dependencies: sharp, createerror, httperrors and passerror](https://github.com/papandreou/express-processimage/commit/9954587ca778724e50de6aef69e52e48f1796ad0) ([Joel Mukuthu](mailto:jmu@one.com)) 571 | - [Fix: Correctly populate the usedQueryStringFragments array for the 'metadata' operation](https://github.com/papandreou/express-processimage/commit/51fbe80e17d0f843b1b65c19e5d4483dda126d54) ([Joel Mukuthu](mailto:jmu@one.com)) 572 | - [Add progressive jpeg test.](https://github.com/papandreou/express-processimage/commit/2f16d754bbe48b0f4ac36a921cb65660b618192b) ([Andreas Lind](mailto:andreas@one.com)) 573 | 574 | ### v4.4.0 (2016-02-09) 575 | 576 | - [Switch to hijackresponse-nobackpressure.](https://github.com/papandreou/express-processimage/commit/4f07a1e28aaff47151a484584f3ff7e76020c62f) ([Andreas Lind](mailto:andreas@one.com)) 577 | - [Add failing test \[ci skip\].](https://github.com/papandreou/express-processimage/commit/526fdd3f4f3f4665bd9a1e91182f58699b824de1) ([Andreas Lind](mailto:andreas@one.com)) 578 | 579 | ### v4.3.1 (2016-02-05) 580 | 581 | #### Pull requests 582 | 583 | - [#15](https://github.com/papandreou/express-processimage/pull/15) Fixed unnecessary Promise usage ([Joel Mukuthu](mailto:jmu@one.com)) 584 | 585 | #### Commits to master 586 | 587 | - [Update unexpected et al.](https://github.com/papandreou/express-processimage/commit/3d357abd6917f4b4f2549bca368b8aeb7fcc46de) ([Andreas Lind](mailto:andreas@one.com)) 588 | 589 | ### v4.3.0 (2015-12-02) 590 | 591 | - [gm: Support rotate=<deg> without a background color as the first arg.](https://github.com/papandreou/express-processimage/commit/cc368f57e2a7bd8bb22d9bd24431f0fde8ada65c) ([Andreas Lind](mailto:andreas@one.com)) 592 | - [Implement extract for the gm engine.](https://github.com/papandreou/express-processimage/commit/e090873f172b8abba292b5b88719a75999cd9d8f) ([Andreas Lind](mailto:andreas@one.com)) 593 | - [Attempt to fix test that fails on Travis, but not on my local machine \(?\).](https://github.com/papandreou/express-processimage/commit/232a7470f94af4e02d39795eb58f5f1cbad24b7e) ([Andreas Lind](mailto:andreas@one.com)) 594 | 595 | ### v4.2.0 (2015-12-01) 596 | 597 | - [Use gm when working with animated gifs, except when eventually converting to another format.](https://github.com/papandreou/express-processimage/commit/36c37bfc87f9a0c3506a1b883d24001a08965bc7) ([Andreas Lind](mailto:andreas@one.com)) 598 | 599 | ### v4.1.0 (2015-11-23) 600 | 601 | - [Add the user of express-processimage to veto individual operations.](https://github.com/papandreou/express-processimage/commit/2f86e3c2af2d7bf15f22631f15593a6545e76f53) ([Andreas Lind](mailto:andreas@one.com)) 602 | - [Don't break when options.sourceMetadata is not given.](https://github.com/papandreou/express-processimage/commit/72bd087a5acb1ba40503e2a375157b6228f929ce) ([Andreas Lind](mailto:andreas@one.com)) 603 | 604 | ### v4.0.0 (2015-11-23) 605 | 606 | - [Travis: Don't allow the node.js 4 and 5 builds to fail anymore.](https://github.com/papandreou/express-processimage/commit/eac05460216e0eb06d4951652a2255ab535963f6) ([Andreas Lind](mailto:andreas@one.com)) 607 | - [Revert "package.json: Temporarily switch to unexpectedjs\/unexpected-resemble\#update-canvas-via-resemble to see if that fixes the build with node.js 4 and 5."](https://github.com/papandreou/express-processimage/commit/e59e0a1dcd5d4226523832bc64650568913876e9) ([Andreas Lind](mailto:andreas@one.com)) 608 | - [Travis: Try to get the right version of g++ installed so NAN will work again.](https://github.com/papandreou/express-processimage/commit/c0fa0b74fef4529c2f3c1ef1a151f0a003260a85) ([Andreas Lind](mailto:andreas@one.com)) 609 | - [Update sharp to 0.12.0.](https://github.com/papandreou/express-processimage/commit/5dfff36550afb1862573d0023a04d3c4bc0e394f) ([Andreas Lind](mailto:andreas@one.com)) 610 | - [package.json: Temporarily switch to unexpectedjs\/unexpected-resemble\#update-canvas-via-resemble to see if that fixes the build with node.js 4 and 5.](https://github.com/papandreou/express-processimage/commit/487467d943f1b9345ecab1aacf94daebcde92a5e) ([Andreas Lind](mailto:andreas@one.com)) 611 | - [+9 more](https://github.com/papandreou/express-processimage/compare/v3.1.0...v4.0.0) 612 | 613 | ### v3.1.0 (2015-09-29) 614 | 615 | - [Include the original file size and ETag in the ?metadata JSON.](https://github.com/papandreou/express-processimage/commit/a7cf4412a5b5823b101c0c412986ee23012d8221) ([Andreas Lind](mailto:andreas@one.com)) 616 | - [?metadata: Include contentType property in the JSON blob.](https://github.com/papandreou/express-processimage/commit/1994e6d255bfd16799ed36e101dc387eaec52abb) ([Andreas Lind](mailto:andreas@one.com)) 617 | - [allow node.js 4.1 builds failing on travis \(cannot npm install properly - works locally\)](https://github.com/papandreou/express-processimage/commit/a644ff18c3219c368c19386a36f5dd78b72fbb6e) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 618 | 619 | ### v3.0.3 (2015-09-23) 620 | 621 | - [update hijackresponse to 1.0.1](https://github.com/papandreou/express-processimage/commit/c97e1659f67ebf7f5e7d958eff729e5b3d45f1df) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 622 | 623 | ### v3.0.2 (2015-09-23) 624 | 625 | - [package.json: remove tag next](https://github.com/papandreou/express-processimage/commit/2c1e24203a400e2859d89afa3f6fbbc97338fc90) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 626 | - [update hijackresponse to 1.0.0](https://github.com/papandreou/express-processimage/commit/e67eaf7b6d6529beade1355bdef049e0c3ff5c70) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 627 | - [add missing semicolon](https://github.com/papandreou/express-processimage/commit/e2630590974cb37b687161de6955f3a6f35296a0) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 628 | - [only unpipe on streams that have unpipe methods](https://github.com/papandreou/express-processimage/commit/ca1520914e1deb1f65fbb4f9ede7fe36f8358481) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 629 | - [Update unexpected etc.](https://github.com/papandreou/express-processimage/commit/9f13b9d793a47ab3cbde57da031c470d6fac2fc0) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 630 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v3.0.1...v3.0.2) 631 | 632 | ### v3.0.1 (2015-09-22) 633 | 634 | - [update hijackresponse to 0.0.0](https://github.com/papandreou/express-processimage/commit/9af6d486c7eb8e0438fa7d12ed208d8af6bf2ca5) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 635 | 636 | ### v3.0.0 (2015-09-22) 637 | 638 | - [package.json: tag next](https://github.com/papandreou/express-processimage/commit/35f78ad497de30b1b8377bb811f8e6b94ac88a69) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 639 | - [remove unused var](https://github.com/papandreou/express-processimage/commit/f8c7fe4ab30aac082f83bfc8fd9c7cd4afcaefda) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 640 | - [Travis: Add sharp's recommended preinstall script to the before\_install hook.](https://github.com/papandreou/express-processimage/commit/047bec7d4157de0e88d8f2b29ba57591260920f1) ([Andreas Lind](mailto:andreas@one.com)) 641 | - [Move the test favicon to the correct place \(d'oh\).](https://github.com/papandreou/express-processimage/commit/31d7ec26c3771268308bb58c32ba65e662c11573) ([Andreas Lind](mailto:andreas@one.com)) 642 | - [Travis: Install libgsf-1-dev and build on node.js 4.1 instead of 4.0.](https://github.com/papandreou/express-processimage/commit/aadf5fab318c5dc3426738256896cfd63ce2bbc1) ([Andreas Lind](mailto:andreas@one.com)) 643 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v2.6.1...v3.0.0) 644 | 645 | ### v2.6.1 (2015-09-20) 646 | 647 | - [Update pngquant to 0.6.0.](https://github.com/papandreou/express-processimage/commit/cefd6107a20252d93f223d97a9651e660b3d9134) ([Andreas Lind](mailto:andreas@one.com)) 648 | 649 | ### v2.6.0 (2015-09-20) 650 | 651 | - [Update pngcrush to 0.2.0.](https://github.com/papandreou/express-processimage/commit/7cbb2ac3355c7c4103a76e43be32f80660f179be) ([Andreas Lind](mailto:andreas@one.com)) 652 | 653 | ### v2.5.0 (2015-09-17) 654 | 655 | - [Avoid superfluous setFormat= in the icon test, straight up &png also works.](https://github.com/papandreou/express-processimage/commit/c7f04acb88e8612658963d4adaa184920b391215) ([Andreas Lind](mailto:andreas@one.com)) 656 | - [Update mime to 1.3.4.](https://github.com/papandreou/express-processimage/commit/bbb0ea586b1b29ae0fb0913c3b254ea94f20395e) ([Andreas Lind](mailto:andreas@one.com)) 657 | - [Add housekeeping to keep track of the Content-Type of the image before each step.](https://github.com/papandreou/express-processimage/commit/d19100e977a01f374b89e076898d5a1b3eec7293) ([Andreas Lind](mailto:andreas@one.com)) 658 | - [Update gm to 1.19.0.](https://github.com/papandreou/express-processimage/commit/5b9657e6d159ac2bf5c0ee795765e8e23dd29868) ([Andreas Lind](mailto:andreas@one.com)) 659 | - [Update unexpected-resemble to 2.4.3.](https://github.com/papandreou/express-processimage/commit/086b08ca8c83bc4e6d0129335cc8a3cbb4543a96) ([Andreas Lind](mailto:andreas@one.com)) 660 | - [+3 more](https://github.com/papandreou/express-processimage/compare/v2.4.0...v2.5.0) 661 | 662 | ### v2.4.0 (2015-09-14) 663 | 664 | - [Update sharp to 0.11.2, removed gravity argument workaround.](https://github.com/papandreou/express-processimage/commit/f7ca2d7f4b1ec8f15d926ee7a9ed9d1393bbdea4) ([Andreas Lind](mailto:andreas@one.com)) 665 | - [Update unexpected et al. to the latest versions, don't explicitly depend on their peerDependencies.](https://github.com/papandreou/express-processimage/commit/be514afcced76153d88d7a1a143726b0533e3738) ([Andreas Lind](mailto:andreas@one.com)) 666 | - [Sharp: Support crop with the gravity specified as a string.](https://github.com/papandreou/express-processimage/commit/f9ea8e0798ffd42935da78522776afbb0dbe209f) ([Andreas Lind](mailto:andreas@one.com)) 667 | - [Add 'ignoreAspectRatio' to the list of supported sharp operations.](https://github.com/papandreou/express-processimage/commit/1961be784b2b154cbc85d7f3f67c62a3ee5bae48) ([Andreas Lind](mailto:andreas@one.com)) 668 | 669 | ### v2.3.0 (2015-08-07) 670 | 671 | - [Refactored a bit, tweaked error status codes, map "Input image exceeds pixel limit" from sharp to a 413.](https://github.com/papandreou/express-processimage/commit/3df54b4fee7ad8688f1dd6d555f2602a0425dedf) ([Andreas Lind](mailto:andreas@one.com)) 672 | - [?metadata: Send back a 405 when the image is unsupported.](https://github.com/papandreou/express-processimage/commit/37e563486c3b5e62207255ae3dd5ba2dcde565a4) ([Andreas Lind](mailto:andreas@one.com)) 673 | - [?metadata duplex stream: Respect backpressure.](https://github.com/papandreou/express-processimage/commit/ac470b511d625c4d07951fc9111a2e458e2b1baa) ([Andreas Lind](mailto:andreas@one.com)) 674 | - [?metadata: Don't pass on an objectMode stream.](https://github.com/papandreou/express-processimage/commit/329a589fefd3092d9be681b14826fb85ac04dbd7) ([Andreas Lind](mailto:andreas@one.com)) 675 | - [?metadata: Parse ICC profile data if available.](https://github.com/papandreou/express-processimage/commit/c83f65987d37dba9d92d392a93cee781edfb8f37) ([Andreas Lind](mailto:andreas@one.com)) 676 | - [+3 more](https://github.com/papandreou/express-processimage/compare/v2.2.2...v2.3.0) 677 | 678 | ### v2.2.2 (2015-07-29) 679 | 680 | - [Update svgfilter to 1.1.0.](https://github.com/papandreou/express-processimage/commit/d0f7b32559e4fdb88b6aaf4fc05efff25f751ef2) ([Andreas Lind](mailto:andreas@one.com)) 681 | 682 | ### v2.2.1 (2015-07-29) 683 | 684 | - [Update optipng to 0.3.1.](https://github.com/papandreou/express-processimage/commit/67bfc013d4663a5c92a15876d1223e6894900405) ([Andreas Lind](mailto:andreas@one.com)) 685 | 686 | ### v2.2.0 (2015-07-29) 687 | 688 | - [Update pngquant to 0.5.0.](https://github.com/papandreou/express-processimage/commit/0ad5c7a58d130d7af92ccdc3587651813da787e5) ([Andreas Lind](mailto:andreas@one.com)) 689 | - [Update jpegtran to 0.2.0.](https://github.com/papandreou/express-processimage/commit/90288568c257ce5dc7fc38ef413b6c207a841d5a) ([Andreas Lind](mailto:andreas@one.com)) 690 | - [Update optipng to 0.3.0.](https://github.com/papandreou/express-processimage/commit/3e348e1ee824b493dbb109d228f19f0be85372ea) ([Andreas Lind](mailto:andreas@one.com)) 691 | - [package.json: Use a valid SPDX identifier for the license field.](https://github.com/papandreou/express-processimage/commit/ffaf96308d80df289f7375905fdeb9e82d23737a) ([Andreas Lind](mailto:andreas@one.com)) 692 | - [Travis: Build on iojs-v2.5.0.](https://github.com/papandreou/express-processimage/commit/2dfe9ee825488da873f205cdb4dbab2ccf538f52) ([Andreas Lind](mailto:andreas@one.com)) 693 | - [+20 more](https://github.com/papandreou/express-processimage/compare/v2.1.0...v2.2.0) 694 | 695 | ### v2.1.0 (2015-01-26) 696 | 697 | - [Update sharp to 0.9.0.](https://github.com/papandreou/express-processimage/commit/6ec923245a796c7dfc7c8b7b0de8333a0cd3858f) ([Andreas Lind](mailto:andreas@one.com)) 698 | 699 | ### v2.0.2 (2015-01-13) 700 | 701 | - [Also accept an If-None-Match token with additional suffixes from other hijacking middleware.](https://github.com/papandreou/express-processimage/commit/09bdf889d98f0a459bcc5e4d6081404f8fb3ba59) ([Andreas Lind](mailto:andreas@one.com)) 702 | 703 | ### v2.0.1 (2015-01-13) 704 | 705 | - [Only hijack the response if the url specifies an image extension according to the mime lib.](https://github.com/papandreou/express-processimage/commit/2190f19265a9cc3f11a73768e3588f099736b63f) ([Andreas Lind](mailto:andreas@one.com)) 706 | 707 | ### v2.0.0 (2014-11-24) 708 | 709 | - [Update express-hijackresponse to 0.2.1. Fixes Express 4 issues.](https://github.com/papandreou/express-processimage/commit/476fbb7a3f415cae060891e7cdfc981f935b98ac) ([Andreas Lind](mailto:andreas@one.com)) 710 | 711 | ### v1.4.0 (2014-11-05) 712 | 713 | - [Implement gmMaxPixels option.](https://github.com/papandreou/express-processimage/commit/45b7dfa30c9299be13e3cd84637f129a70d2d09b) ([Andreas Lind](mailto:andreas@one.com)) 714 | - [Use sharp as the default engine if available.](https://github.com/papandreou/express-processimage/commit/b614ceccb62c178dcfd70026b9d9940e35f2f850) ([Andreas Lind](mailto:andreas@one.com)) 715 | 716 | ### v1.3.1 (2014-10-23) 717 | 718 | - [Fixed sharp test.](https://github.com/papandreou/express-processimage/commit/767cfe94afac00cbee344c7d89dc4e448abd6e97) ([Andreas Lind](mailto:andreas@one.com)) 719 | - [Whoops, forgot sharp's png method.](https://github.com/papandreou/express-processimage/commit/f17344d32daaf4fbbe50c2b766dce5bce4388add) ([Andreas Lind](mailto:andreas@one.com)) 720 | - [Made sharp an optional dependency \(waiting for lovell\/sharp\#42\).](https://github.com/papandreou/express-processimage/commit/675619a02ee21eb5010c0dac944005789793d859) ([Andreas Lind](mailto:andreas@one.com)) 721 | 722 | ### v1.3.0 (2014-10-22) 723 | 724 | - [Add support for the operations exposed by the 'sharp' library. Fixes \#6.](https://github.com/papandreou/express-processimage/commit/b624be0da67a3d153e69da4db10466d1cb228a77) ([Andreas Lind](mailto:andreas@one.com)) 725 | 726 | ### v1.2.0 (2014-10-21) 727 | 728 | - [Update pngquant to 0.3.0.](https://github.com/papandreou/express-processimage/commit/c2a46b1e016bca2c4ef34b3e4741092c83b31648) ([Andreas Lind](mailto:andreas@one.com)) 729 | - [package.json: Removed equal signs for better compatibility with npm install --save \(npm config set save-exact true\).](https://github.com/papandreou/express-processimage/commit/52a61a9794a2311c13c88f36bae661ec78dabd15) ([Andreas Lind](mailto:andreas@one.com)) 730 | 731 | ### v1.1.0 (2014-10-10) 732 | 733 | - [getFilterInfosAndTargetContentTypeFromQueryString: Allow extending with custom filters as well as turning off the built in ones.](https://github.com/papandreou/express-processimage/commit/428764c7e122d4bffc27345feed84a1c410d1a88) ([Andreas Lind](mailto:andreas@one.com)) 734 | - [getFilterInfosAndTargetContentTypeFromQueryString: Take an options object.](https://github.com/papandreou/express-processimage/commit/863930f7bac45a7d133e0085170b0b730fe5cc87) ([Andreas Lind](mailto:andreas@one.com)) 735 | - [Fixed pngcrush test so it doesn't break with the pngcrush that came with my Ubuntu.](https://github.com/papandreou/express-processimage/commit/2272c47ba88fa733df73e1d065badf1664aa3e05) ([Andreas Lind](mailto:andreas@one.com)) 736 | 737 | ### v1.0.2 (2014-09-22) 738 | 739 | - [Unbreak targetContentType when inkscape is involved.](https://github.com/papandreou/express-processimage/commit/df10bec161af1623f55ef067564e2307e0a95daa) ([Andreas Lind](mailto:andreas@one.com)) 740 | - [Update pngquant to 0.2.0.](https://github.com/papandreou/express-processimage/commit/49039fec444d0a2b8760e5eb7c4e67e85cc5ff0a) ([Andreas Lind](mailto:andreas@one.com)) 741 | - [Update pngcrush to 0.1.0.](https://github.com/papandreou/express-processimage/commit/93a8c0cf2ea48fea0444c3eaab712c69405636e4) ([Andreas Lind](mailto:andreas@one.com)) 742 | - [Update optipng to 0.1.1.](https://github.com/papandreou/express-processimage/commit/086cbf31f017c88f12ff891f576c8ebf613c275c) ([Andreas Lind](mailto:andreas@one.com)) 743 | - [Update optipng to 0.1.0.](https://github.com/papandreou/express-processimage/commit/ea795d7f25f330e59d080b24ce3d7aed1dc49b7c) ([Andreas Lind](mailto:andreas@one.com)) 744 | 745 | ### v0.1.23 (2014-09-15) 746 | 747 | - [fix jshint errors resulting in a reference error when using inkscape](https://github.com/papandreou/express-processimage/commit/f6edba6b97a8b8410cce6013bad747ad2e1cbe44) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 748 | - [Renamed a var for consistence with the previous commit.](https://github.com/papandreou/express-processimage/commit/00477ff83344287dc709fed43aa978f3b35aaf7e) ([Andreas Lind](mailto:andreas@one.com)) 749 | - [Don't create the filter instances before checking whether a 304 can be returned.](https://github.com/papandreou/express-processimage/commit/2429db1e1d96ab740d6a200c2717062b00b44a86) ([Andreas Lind](mailto:andreas@one.com)) 750 | 751 | ### v0.1.22 (2014-08-28) 752 | 753 | #### Pull requests 754 | 755 | - [#11](https://github.com/papandreou/express-processimage/pull/11) If a filter errors, make sure to include its commandLine property in the... ([Jesper Birkestrøm](mailto:jbi@one.com)) 756 | 757 | #### Commits to master 758 | 759 | - [update svgfilter dependency to 0.4.0](https://github.com/papandreou/express-processimage/commit/a23d8401263ff5271130795fbce760edf318f78b) ([Gustav Nikolaj Olsen](mailto:gno@one.com)) 760 | - [processImage binary: Report the failing command line when a filter emits an error.](https://github.com/papandreou/express-processimage/commit/54c0074d1430c7f666ee55b0937253d75e26f527) ([Andreas Lind Petersen](mailto:andreas@one.com)) 761 | 762 | ### v0.1.20 (2014-06-02) 763 | 764 | - [Added 'npm run lint' task that runs jshint, and changed to code to make it pass.](https://github.com/papandreou/express-processimage/commit/524655a025dd44443c452f9cd37fefab774b1451) ([Andreas Lind Petersen](mailto:andreas@one.com)) 765 | - [Fixed tests by moving the test data out of the test directory.](https://github.com/papandreou/express-processimage/commit/e10be675cc828c279588d4928792eb029d39e906) ([Andreas Lind Petersen](mailto:andreas@one.com)) 766 | - [Added mocha.opts.](https://github.com/papandreou/express-processimage/commit/fd3170dfb01681c77ae00bfb08de601880158f0e) ([Andreas Lind Petersen](mailto:andreas@one.com)) 767 | 768 | ### v0.1.19 (2014-05-28) 769 | 770 | - [Update pngquant to 0.1.5.](https://github.com/papandreou/express-processimage/commit/4cafb59ed8c1ce6d9bbc610d2cc7cb1693e92340) ([Andreas Lind Petersen](mailto:andreas@one.com)) 771 | - [Update pngcrush to 0.0.5.](https://github.com/papandreou/express-processimage/commit/62c4544ed59aa3f36f224c85601fa042b23842e5) ([Andreas Lind Petersen](mailto:andreas@one.com)) 772 | - [Update svgfilter to 0.3.2.](https://github.com/papandreou/express-processimage/commit/75c557a10d950f1e5abde59f0e9a270cd46d9f12) ([Andreas Lind Petersen](mailto:andreas@one.com)) 773 | - [Update jpegtran to 0.0.6.](https://github.com/papandreou/express-processimage/commit/acc647fd99521e7a91dd4b84eaa64ed66024e6c2) ([Andreas Lind Petersen](mailto:andreas@one.com)) 774 | - [Update inkscape to 0.0.5.](https://github.com/papandreou/express-processimage/commit/0d6a0e2a3270907d882caad5fe663d8cb1575eb0) ([Andreas Lind Petersen](mailto:andreas@one.com)) 775 | - [+2 more](https://github.com/papandreou/express-processimage/compare/v0.1.18...v0.1.19) 776 | 777 | ### v0.1.17 (2014-03-26) 778 | 779 | - [package.json: Removed prepublish hook.](https://github.com/papandreou/express-processimage/commit/a62542a7999fefc4867bb60302570b44002d9fa8) ([Peter Müller](mailto:munter@fumle.dk)) 780 | - [Update pngquant to 0.1.4.](https://github.com/papandreou/express-processimage/commit/b522a3ebead21d03249a3f705b1135814be4ea45) ([Peter Müller](mailto:munter@fumle.dk)) 781 | 782 | ### v0.1.16 (2014-03-25) 783 | 784 | - [Update pngquant to 0.1.3.](https://github.com/papandreou/express-processimage/commit/03250ea406f3d2b03825939c73d12ac46c686a32) ([Andreas Lind Petersen](mailto:andreas@one.com)) 785 | 786 | ### v0.1.15 (2014-03-25) 787 | 788 | - [Update jpegtran to 0.0.5.](https://github.com/papandreou/express-processimage/commit/fa8ab157c79de0bcfb1dff8da7e4281da01f82f8) ([Andreas Lind Petersen](mailto:andreas@one.com)) 789 | - [Update pngquant to 0.1.2.](https://github.com/papandreou/express-processimage/commit/a6fc3794ddd6ce0eddd370b18fba86ee531a05f2) ([Andreas Lind Petersen](mailto:andreas@one.com)) 790 | - [Update pngcrush to 0.0.4.](https://github.com/papandreou/express-processimage/commit/194cc97de19e23e40bcd2e8c2a5e4dca67e1a914) ([Andreas Lind Petersen](mailto:andreas@one.com)) 791 | - [Update optipng to 0.0.5.](https://github.com/papandreou/express-processimage/commit/bdf8ed72ee83c59fc136fb0a17491b9762c6fc85) ([Andreas Lind Petersen](mailto:andreas@one.com)) 792 | - [Update inkscape to 0.0.4.](https://github.com/papandreou/express-processimage/commit/7f3ccafe8dd683ac7a600c1f7216f93c7051255e) ([Andreas Lind Petersen](mailto:andreas@one.com)) 793 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v0.1.14...v0.1.15) 794 | 795 | ### v0.1.14 (2014-03-22) 796 | 797 | - [Update pngquant to 0.1.1.](https://github.com/papandreou/express-processimage/commit/9b90b3fabec93fbfa9688c682b447d757b9daba7) ([Andreas Lind Petersen](mailto:andreas@one.com)) 798 | 799 | ### v0.1.13 (2014-02-25) 800 | 801 | - [Added command line tool for doing the same thing as the middleware.](https://github.com/papandreou/express-processimage/commit/188da4c3486f3bb9e7332948b30c3250db84a75f) ([Andreas Lind Petersen](mailto:andreas@one.com)) 802 | 803 | ### v0.1.12 804 | 805 | #### Pull requests 806 | 807 | - [#3](https://github.com/papandreou/express-processimage/pull/3) Fix git repository URL ([Jeppe Toustrup](mailto:tenzer@tenzer.dk)) 808 | 809 | #### Commits to master 810 | 811 | - [Release 0.1.12.](https://github.com/papandreou/express-processimage/commit/01de349a1fabdba02faa17d6dfe425bf487802ee) ([Andreas Lind Petersen](mailto:andreas@one.com)) 812 | - [Replace expect.js with unexpected.](https://github.com/papandreou/express-processimage/commit/b120c93269688e05042fbe863113de0c6220b114) ([Andreas Lind Petersen](mailto:andreas@one.com)) 813 | - [Update pngquant to 0.1.0.](https://github.com/papandreou/express-processimage/commit/241d441cf6ec9d730720dc37a6baf321207fc425) ([Andreas Lind Petersen](mailto:andreas@one.com)) 814 | 815 | ### v0.1.11 816 | 817 | - [Release 0.1.11.](https://github.com/papandreou/express-processimage/commit/0a0dc5124b10dc6d2894e82b9825b0128b99d52b) ([Andreas Lind Petersen](mailto:andreas@one.com)) 818 | - [package.json: Indent with 2 spaces.](https://github.com/papandreou/express-processimage/commit/2ca7465b7e0df02af6506e5fb9672b205c5e6dd4) ([Andreas Lind Petersen](mailto:andreas@one.com)) 819 | - [Update inkscape to 0.0.3.](https://github.com/papandreou/express-processimage/commit/c628de4e92ef001a649814cad85ca9803938fd79) ([Andreas Lind Petersen](mailto:andreas@one.com)) 820 | - [README: Added inkscape example.](https://github.com/papandreou/express-processimage/commit/5a4002528e28ce8d79cfae6359b859f3b7c5dc16) ([Andreas Lind Petersen](mailto:andreas@one.com)) 821 | - [getFiltersAndTargetContentTypeFromQueryString: Pass on args of 'true' and 'false' as boolean to gm.](https://github.com/papandreou/express-processimage/commit/0059578fe9e3a9459971d55d5d046f4877f9b926) ([Andreas Lind Petersen](mailto:andreas@one.com)) 822 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v0.1.10...v0.1.11) 823 | 824 | ### v0.1.10 825 | 826 | - [Release 0.1.10.](https://github.com/papandreou/express-processimage/commit/18fe1917f01444be407651898c9c5a0a78839e17) ([Andreas Lind Petersen](mailto:andreas@one.com)) 827 | - [Rolled back 5a6dd93 as it spooks livestyle. We'll have to live with the ETags not changing until I figure something out :\/](https://github.com/papandreou/express-processimage/commit/c32182828c5d1cf0923ae7d704a1acde1e0bdba5) ([Andreas Lind Petersen](mailto:andreas@one.com)) 828 | 829 | ### v0.1.9 830 | 831 | - [Release 0.1.9.](https://github.com/papandreou/express-processimage/commit/d53d24c8fd47fdda2fda3ff13ac9068043b70c2e) ([Andreas Lind Petersen](mailto:andreas@one.com)) 832 | - [Update svgfilter to 0.3.1 and include emitted 'etagFragment' events in the ETag for the produced image so conditional GET works correctly with external JavaScripts.](https://github.com/papandreou/express-processimage/commit/5a6dd93676f38b338ac41d8259053b63bfd1cd5f) ([Andreas Lind Petersen](mailto:andreas@one.com)) 833 | 834 | ### v0.1.8 835 | 836 | - [Release 0.1.8.](https://github.com/papandreou/express-processimage/commit/983707f2dcb6ce926841ab9fed6ef11e80a2b2df) ([Andreas Lind Petersen](mailto:andreas@one.com)) 837 | - [Fixed the SvgFilter arguments \(external --runScript was broken for files not residing at the root level\).](https://github.com/papandreou/express-processimage/commit/dcc8496dbc94391e2d984f0182d1412a257a3e46) ([Andreas Lind Petersen](mailto:andreas@one.com)) 838 | - [Added an svgfilter=... test and updated the docs.](https://github.com/papandreou/express-processimage/commit/f96ce2c5c75f74e0010d845e73a68861a3d77a05) ([Andreas Lind Petersen](mailto:andreas@one.com)) 839 | - [Take a 'root' option and pass it to SvgFilter so it knows where to find external JavaScript files on disc.](https://github.com/papandreou/express-processimage/commit/918fa772f775cf96d6d4b0178d0fa0d85f6eb709) ([Andreas Lind Petersen](mailto:andreas@one.com)) 840 | - [Improved error handling.](https://github.com/papandreou/express-processimage/commit/7973acef54cb2dfaa5264e3c0ac4210c2e705fab) ([Andreas Lind Petersen](mailto:andreas@one.com)) 841 | - [+1 more](https://github.com/papandreou/express-processimage/compare/v0.1.7...v0.1.8) 842 | 843 | ### v0.1.7 844 | 845 | - [Release 0.1.7.](https://github.com/papandreou/express-processimage/commit/28a0659edf4aa1479a7108d8150aa35dab113310) ([Andreas Lind Petersen](mailto:andreas@one.com)) 846 | - [Update svgfilter to 0.2.2.](https://github.com/papandreou/express-processimage/commit/6f4da0b24a24713489b711183249b4870f75f6a8) ([Andreas Lind Petersen](mailto:andreas@one.com)) 847 | 848 | ### v0.1.6 849 | 850 | #### Pull requests 851 | 852 | - [#1](https://github.com/papandreou/express-processimage/pull/1) Attempt to make svgfilter optional to ease windows installation ([Peter Müller](mailto:munter@fumle.dk)) 853 | 854 | #### Commits to master 855 | 856 | - [Release 0.1.6.](https://github.com/papandreou/express-processimage/commit/cdac41d7aef443b3ab640f524dcb7fd5cf9d670b) ([Andreas Lind Petersen](mailto:andreas@one.com)) 857 | 858 | ### v0.1.5 859 | 860 | - [Release 0.1.5.](https://github.com/papandreou/express-processimage/commit/59866a57e657bcb7b338ef711097b7e9e2380beb) ([Andreas Lind Petersen](mailto:andreas@one.com)) 861 | - [Update svgfilter to 0.2.1.](https://github.com/papandreou/express-processimage/commit/31fd5fb60cc4c30a8c0568c8487238aa926ca1e8) ([Andreas Lind Petersen](mailto:andreas@one.com)) 862 | 863 | ### v0.1.4 864 | 865 | - [Release 0.1.4.](https://github.com/papandreou/express-processimage/commit/50a683583eda71a26057a5bac598fa59855b1e87) ([Andreas Lind Petersen](mailto:andreas@one.com)) 866 | - [Update svgfilter to 0.2.0.](https://github.com/papandreou/express-processimage/commit/1ef4934da7e3493c46f387c1da987813163c8483) ([Andreas Lind Petersen](mailto:andreas@one.com)) 867 | 868 | ### v0.1.3 869 | 870 | - [Release 0.1.3.](https://github.com/papandreou/express-processimage/commit/06036598028d5b2a1161a180b7520b2577399334) ([Andreas Lind Petersen](mailto:andreas@one.com)) 871 | - [Update svgfilter to 0.1.1.](https://github.com/papandreou/express-processimage/commit/e34619f220c8208b2bc10d76973c474ce9e52914) ([Andreas Lind Petersen](mailto:andreas@one.com)) 872 | 873 | ### v0.1.2 874 | 875 | - [Release 0.1.2.](https://github.com/papandreou/express-processimage/commit/72f1339f935aba0a4b89ab7af37336b935973432) ([Andreas Lind Petersen](mailto:andreas@one.com)) 876 | - [Added svgfilter support.](https://github.com/papandreou/express-processimage/commit/50ad2dccb440e01b466ba3469f018c98f8b78e55) ([Andreas Lind Petersen](mailto:andreas@one.com)) 877 | 878 | ### v0.1.1 879 | 880 | - [Release 0.1.1.](https://github.com/papandreou/express-processimage/commit/bfac16e781eb54e7211489fc79ed3b6aba0ca22e) ([Andreas Lind Petersen](mailto:andreas@one.com)) 881 | - [Update inkscape to 0.0.2.](https://github.com/papandreou/express-processimage/commit/76dc9faf227b397b140d5c78963fd3ca2e77f672) ([Andreas Lind Petersen](mailto:andreas@one.com)) 882 | 883 | ### v0.1.0 884 | 885 | - [Release 0.1.0.](https://github.com/papandreou/express-processimage/commit/97e21b641efe7ab9b02543f61be95bf7a2215d67) ([Andreas Lind Petersen](mailto:andreas@one.com)) 886 | - [Added support for inkscape using node-inkscape.](https://github.com/papandreou/express-processimage/commit/038c43b0fab5fdb6a6c2ad71f62ebd073cda808e) ([Andreas Lind Petersen](mailto:andreas@one.com)) 887 | 888 | ### v0.0.6 889 | 890 | - [Release 0.0.6.](https://github.com/papandreou/express-processimage/commit/38ca2748963c833fb5638e1d10e62819a5670fb6) ([Andreas Lind Petersen](mailto:andreas@one.com)) 891 | - [Update jpegtran to 0.0.4 and optipng to 0.0.4.](https://github.com/papandreou/express-processimage/commit/d81ae41cd9abefa77175066c7698ac57393fccb9) ([Andreas Lind Petersen](mailto:andreas@one.com)) 892 | 893 | ### v0.0.5 894 | 895 | - [Release 0.0.5.](https://github.com/papandreou/express-processimage/commit/63f132f97dce9602bc502e310f2832aa9b47d3a5) ([Andreas Lind Petersen](mailto:andreas@one.com)) 896 | - [Update jpegtran to 0.0.3 and optipng to 0.0.3.](https://github.com/papandreou/express-processimage/commit/9b4c1efa6b745a2fe3528e8164a49ae9db7f5887) ([Andreas Lind Petersen](mailto:andreas@one.com)) 897 | 898 | ### v0.0.4 899 | 900 | - [Release 0.0.4.](https://github.com/papandreou/express-processimage/commit/f1b9642ed7eeb86e7ed1d6eae5a81423c313c773) ([Andreas Lind Petersen](mailto:andreas@one.com)) 901 | - [getFiltersAndTargetContentTypeFromQueryString: Also include an array of operation names in the returned object.](https://github.com/papandreou/express-processimage/commit/8e57671da981f3d91188398a0d9a8c4c4c690912) ([Andreas Lind Petersen](mailto:andreas@one.com)) 902 | 903 | ### v0.0.3 904 | 905 | - [Release 0.0.3.](https://github.com/papandreou/express-processimage/commit/257ea97636eba1617052d667a9fb13e7cbbe5286) ([Andreas Lind Petersen](mailto:andreas@one.com)) 906 | - [getFiltersAndTargetContentTypeFromQueryString: Fixed end method of the readable\/writable stream wrapped around the gm module.](https://github.com/papandreou/express-processimage/commit/07dec854e0f22d52dd6c9489eaa46c8fab1638a8) ([Andreas Lind Petersen](mailto:andreas@one.com)) 907 | 908 | ### v0.0.2 909 | 910 | - [Release 0.0.2.](https://github.com/papandreou/express-processimage/commit/3ddee72da8746ac8a3ab786ab68358281a8a2174) ([Andreas Lind Petersen](mailto:andreas@one.com)) 911 | - [getFiltersAndTargetContentTypeFromQueryString: Also report which fragments of the query string were used and which were not.](https://github.com/papandreou/express-processimage/commit/368a1c398d509d2bfd07d7f74b946e51e16bc80a) ([Andreas Lind Petersen](mailto:andreas@one.com)) 912 | 913 | ### v0.0.1 914 | 915 | - [Initial commit, release 0.0.1.](https://github.com/papandreou/express-processimage/commit/845cddf7d2df404f52b7f60d88ab77503ede5754) ([Andreas Lind Petersen](mailto:andreas@one.com)) 916 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Docker development environment for express-processimage 2 | # 3 | # This Dockerfile is for development only. 4 | # 5 | # It is built to closely resemble the Travis CI environment, to make the 6 | # development experience as flawless as possible. 7 | # 8 | # Based on https://github.com/creationix/nvm/blob/a1abfd1fe42308599b77461eb15460427fe05b9e/Dockerfile#L16 9 | 10 | FROM ubuntu:14.04 11 | LABEL maintainer="Gustav Nikolaj " 12 | LABEL name="express-processimage-dev" 13 | LABEL version="latest" 14 | 15 | # Set the SHELL to bash with pipefail option 16 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 17 | 18 | # Prevent dialog during apt install 19 | ENV DEBIAN_FRONTEND noninteractive 20 | 21 | # Pick a Ubuntu apt mirror site for better speed 22 | # ref: https://launchpad.net/ubuntu/+archivemirrors 23 | ENV UBUNTU_APT_SITE mirror.one.com 24 | 25 | # Disable src package source 26 | RUN sed -i 's/^deb-src\ /\#deb-src\ /g' /etc/apt/sources.list 27 | 28 | # Replace origin apt package site with the mirror site 29 | RUN sed -E -i "s/([a-z]+.)?archive.ubuntu.com/$UBUNTU_APT_SITE/g" /etc/apt/sources.list 30 | RUN sed -i "s/security.ubuntu.com/$UBUNTU_APT_SITE/g" /etc/apt/sources.list 31 | 32 | # Install apt packages 33 | RUN apt-get update && \ 34 | apt-get install -y \ 35 | git \ 36 | wget \ 37 | optipng \ 38 | pngcrush \ 39 | pngquant \ 40 | graphicsmagick \ 41 | libjpeg-turbo-progs \ 42 | inkscape \ 43 | libcairo2-dev \ 44 | libgif-dev \ 45 | libjpeg8-dev \ 46 | zlib1g-dev 47 | 48 | # Set locale 49 | RUN locale-gen en_US.UTF-8 50 | 51 | # Add user "nvm" as non-root user 52 | RUN useradd -ms /bin/bash nvm 53 | 54 | # Set sudoer for "nvm" 55 | RUN echo 'nvm ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers 56 | 57 | # Switch to user "nvm" from now 58 | USER nvm 59 | 60 | # nvm 61 | RUN wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash 62 | 63 | # Set WORKDIR to nvm directory 64 | WORKDIR /home/nvm/express-processimage 65 | 66 | # Install node version 8 (keep in sync with .travis.yml) 67 | RUN bash -c 'source $HOME/.nvm/nvm.sh && nvm install 8' 68 | 69 | ENTRYPOINT ["/bin/bash"] 70 | 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Andreas Lind Petersen 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of the author nor the names of contributors may 15 | be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-processimage 2 | 3 | [![NPM version](https://badge.fury.io/js/express-processimage.svg)](http://badge.fury.io/js/express-processimage) 4 | [![Build Status](https://github.com/papandreou/express-processimage/workflows/tests/badge.svg)](https://github.com/papandreou/express-processimage/actions) 5 | [![Coverage Status](https://coveralls.io/repos/papandreou/express-processimage/badge.svg)](https://coveralls.io/r/papandreou/express-processimage) 6 | [![Dependency Status](https://david-dm.org/papandreou/express-processimage.svg)](https://david-dm.org/papandreou/express-processimage) 7 | 8 | Middleware that processes images according to the query string. 9 | It is intended to be used in a development setting with the static 10 | middleware, but should play well with any middleware further down 11 | the stack, even an http proxy, via 12 | [hijackresponse](https://github.com/gustavnikolaj/hijackresponse). 13 | 14 | Images are processed using the [impro](https://github.com/papandreou/impro) 15 | module which implements automatic switching between a number of image 16 | libraries based on the requested options. 17 | 18 | > **Important note: This module is intended for development. While impro 19 | > validates requested image operations, ultimately image data which could 20 | > be untrusted in such use would be passed directly to various command line 21 | > tools. In addition, extremely large images represent an attack surface 22 | > unless restrictions on maximum input and output sizes are configured.** 23 | 24 | ## Installation 25 | 26 | Make sure you have node.js and npm installed, then run: 27 | 28 | npm install express-processimage 29 | 30 | ## Query string syntax 31 | 32 | `express-processimage` supports `pngcrush`, `pngquant`, `optipng`, 33 | `jpegtran`, `inkscape`, `svgfilter`, 36 | and all methods listed under "manipulation" and "drawing primitives" 37 | in the documentation 38 | for the gm module. 39 | 40 | Multiple tools can be applied to the same image (separated by `&`, and 41 | the order is significant). Arguments for the individual tools are 42 | separated by non-URL encoded comma or plus. 43 | 44 | ``` 45 | http://localhost:1337/myImage.png?pngcrush=-rem,alla 46 | http://localhost:1337/myImage.png?pngcrush=-rem+alla 47 | http://localhost:1337/myImage.png?optipng=-o7 48 | http://localhost:1337/bigImage.png?resize=400,300&pngquant=128&pngcrush 49 | http://localhost:1337/hello.png?setFormat=gif 50 | http://localhost:1337/logo.svg?inkscape 51 | http://localhost:1337/file.svg?svgfilter=--runScript=makeItBlue.js 52 | ``` 53 | 54 | ## Example usage 55 | 56 | Express 3.0 syntax: 57 | 58 | ```javascript 59 | var express = require('express'), 60 | processImage = require('express-processimage'), 61 | root = '/path/to/my/static/files'; 62 | 63 | express() 64 | .use(processImage({ root: root })) 65 | .use(express.static(root)) 66 | .listen(1337); 67 | ``` 68 | 69 | From this point forward, the resposnes tp GET requests to port 1337 are 70 | matched by their Content-Type matched and in the case of an it will be 71 | processed by the image pipeline using options specified in query string. 72 | The processed output is delivered to the client. 73 | 74 | ### Svg processing 75 | 76 | The `root` option is used by node-svgfilter 78 | for finding the location of external JavaScript files to run on the SVG document. 79 | 80 | ## Response processing 81 | 82 | The response will be be processed under these circumstances: 83 | 84 | - If the request has a query string and accepts `image/*`. 85 | - If the response is served with a `Content-Type` of `image/*`. 86 | 87 | `express-processimage` plays nice with conditional GET. If the 88 | original response has an ETag, `express-processimage` will add to it 89 | so the ETag of the processed image never clashes with the original 90 | ETag. That prevents the middleware issuing the original response from 91 | being confused into sending a false positive `304 Not Modified` if 92 | `express-processimage` is turned off or removed from the stack later. 93 | 94 | ## Development with Docker 95 | 96 | Build the docker image by running: 97 | 98 | ``` 99 | $ npm run docker:build 100 | ``` 101 | 102 | Open the development environment: 103 | 104 | ``` 105 | $ npm run docker 106 | ``` 107 | 108 | The above command will place you in a bash shell where the working directory is 109 | your express-processimage checkout from your local machine. It is mounted into 110 | the container which is based on Ubuntu 14.04 and contains all the required 111 | dependencies, and nvm with the latest node 8 version active. 112 | 113 | If you need to run the tests against another node version, you just have to 114 | change the version using nvm and reinstall your modules. 115 | 116 | The environment is configured to resemble our setup on Travis CI as much as 117 | possible. 118 | 119 | ## License 120 | 121 | 3-clause BSD license -- see the `LICENSE` file for details. 122 | -------------------------------------------------------------------------------- /bin/processImage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'), 4 | getFiltersAndTargetContentTypeFromQueryString = require('../lib/getFiltersAndTargetContentTypeFromQueryString'), 5 | commandLineOptions = require('optimist') 6 | .usage('$0 imageProcessingSpec [-o outputFileName]') 7 | .option('o', { 8 | alias: 'output', 9 | describe: 'The file to output' 10 | }) 11 | .demand(1) 12 | .argv; 13 | 14 | var filtersAndTargetContentType = getFiltersAndTargetContentTypeFromQueryString(commandLineOptions._[0]), 15 | filters = filtersAndTargetContentType.filters, 16 | inputStream = process.stdin, 17 | outputStream; 18 | 19 | if (commandLineOptions.o) { 20 | outputStream = fs.createWriteStream(commandLineOptions.o); 21 | } else { 22 | outputStream = process.stdout; 23 | } 24 | 25 | inputStream.pipe(filters[0]); 26 | 27 | for (var i = 0 ; i < filters.length ; i += 1) { 28 | var filter = filters[i]; 29 | filter.on('error', function (err) { 30 | if ('commandLine' in this) { 31 | err.message = this.commandLine + ': ' + err.message; 32 | } 33 | throw err; 34 | }); 35 | if (i < filters.length - 1) { 36 | filter.pipe(filters[i + 1]); 37 | } 38 | } 39 | 40 | filters[filters.length - 1].pipe(outputStream); 41 | -------------------------------------------------------------------------------- /lib/processImage.js: -------------------------------------------------------------------------------- 1 | const Path = require('path'); 2 | const httpErrors = require('httperrors'); 3 | const impro = require('impro'); 4 | const mime = require('mime'); 5 | const accepts = require('accepts'); 6 | const hijackResponse = require('hijackresponse'); 7 | 8 | const isImageByExtension = {}; 9 | Object.keys(mime._extensions).forEach((contentType) => { 10 | if (/^image\//.test(contentType)) { 11 | const extension = mime._extensions[contentType]; 12 | isImageByExtension[extension] = true; 13 | } 14 | }); 15 | 16 | isImageByExtension.jpg = true; 17 | 18 | function isImageExtension(extension) { 19 | return isImageByExtension[extension.toLowerCase()]; 20 | } 21 | 22 | function pickProperties(obj, properties) { 23 | if (!obj) return {}; 24 | const ret = {}; 25 | for (const property of properties) { 26 | ret[property] = obj[property]; 27 | } 28 | return ret; 29 | } 30 | 31 | function reverseIteratorFor(arr) { 32 | let index = arr.length; 33 | 34 | return { 35 | next: function () { 36 | index -= 1; 37 | 38 | const isEnded = index < 0; 39 | 40 | return { 41 | done: isEnded, 42 | value: !isEnded ? arr[index] : undefined, 43 | }; 44 | }, 45 | [Symbol.iterator]() { 46 | return this; 47 | }, 48 | }; 49 | } 50 | 51 | function toUsedNames(usedEngines) { 52 | if (usedEngines.length === 0) { 53 | return []; 54 | } else if (usedEngines.length === 1) { 55 | return [usedEngines[0].name]; 56 | } 57 | 58 | let lastUsedName = usedEngines[0].name; 59 | const orderedUsedNames = [lastUsedName]; 60 | // keep the first occurrence of every engine listed as used 61 | usedEngines.forEach(({ name }) => { 62 | if (name !== lastUsedName) { 63 | orderedUsedNames.push(name); 64 | lastUsedName = name; 65 | } 66 | }); 67 | 68 | return orderedUsedNames; 69 | } 70 | 71 | module.exports = (options) => { 72 | options = options || {}; 73 | 74 | const engines = pickProperties( 75 | options.filters, 76 | Object.keys(impro.engineByName) 77 | ); 78 | 79 | const middleware = (req, res, next) => { 80 | // Polyfill req.accepts for browser-sync compatibility 81 | if (typeof req.accepts !== 'function') { 82 | req.accepts = function requestAccepts() { 83 | const accept = accepts(req); 84 | return accept.types.apply(accept, arguments); 85 | }; 86 | } 87 | 88 | const matchExtensionAndQueryString = req.url.match(/\.(\w+)\?(.*)$/); 89 | const isMetadataRequest = 90 | matchExtensionAndQueryString && 91 | /^(?:.*&)?metadata(?:$|&|=true)/.test(matchExtensionAndQueryString[2]); 92 | if ( 93 | matchExtensionAndQueryString && 94 | (req.method === 'GET' || req.method === 'HEAD') && 95 | ((isImageExtension(matchExtensionAndQueryString[1]) && 96 | req.accepts('image/*')) || 97 | isMetadataRequest) 98 | ) { 99 | // Prevent If-None-Match revalidation with the downstream middleware with ETags that aren't suffixed with "-processimage": 100 | const queryString = matchExtensionAndQueryString[2]; 101 | 102 | const ifNoneMatch = req.headers['if-none-match']; 103 | if (ifNoneMatch) { 104 | const validIfNoneMatchTokens = ifNoneMatch 105 | .split(' ') 106 | .filter((etag) => /-processimage["-]/.test(etag)); 107 | if (validIfNoneMatchTokens.length > 0) { 108 | req.headers['if-none-match'] = validIfNoneMatchTokens 109 | .map((token) => token.replace(/-processimage(["-])/, '$1')) 110 | .join(' '); 111 | } else { 112 | delete req.headers['if-none-match']; 113 | } 114 | } 115 | delete req.headers['if-modified-since']; // Prevent false positive conditional GETs after enabling processimage 116 | hijackResponse(res, next).then( 117 | ({ readable, writable, destroyAndRestore }) => { 118 | // Polyfill res.status for browser-sync compatibility 119 | if (typeof res.status !== 'function') { 120 | res.status = function status(statusCode) { 121 | res.statusCode = statusCode; 122 | return res; 123 | }; 124 | } 125 | 126 | let sourceMetadata; 127 | 128 | function makeFilterInfosAndTargetFormat() { 129 | const parseResult = impro.queryString.parseLegacyQueryString( 130 | queryString, 131 | impro, 132 | options.allowOperation 133 | ); 134 | 135 | // determine the final content type based on the last 136 | // requested type conversion operation (if present) 137 | let outputContentType; 138 | for (const operation of reverseIteratorFor( 139 | parseResult.operations 140 | )) { 141 | if (operation.name === 'metadata') { 142 | outputContentType = 'application/json; charset=utf-8'; 143 | break; 144 | } else if (impro.isTypeByName[operation.name]) { 145 | outputContentType = `image/${operation.name}`; 146 | break; 147 | } 148 | } 149 | parseResult.outputContentType = 150 | outputContentType || sourceMetadata.contentType; 151 | 152 | return parseResult; 153 | } 154 | 155 | const contentLengthHeaderValue = res.getHeader('Content-Length'); 156 | res.removeHeader('Content-Length'); 157 | const oldETag = res.getHeader('ETag'); 158 | 159 | let newETag; 160 | if (oldETag) { 161 | newETag = oldETag.replace(/"$/g, '-processimage"'); 162 | res.setHeader('ETag', newETag); 163 | if (ifNoneMatch && ifNoneMatch.indexOf(newETag) !== -1) { 164 | res.status(304); 165 | return writable.end(); 166 | } 167 | } 168 | 169 | function startProcessing(optionalFirstChunk) { 170 | let hasEnded = false; 171 | let cleanedUp = false; 172 | 173 | function cleanUp(doNotDestroyHijacked) { 174 | if (!cleanedUp) { 175 | cleanedUp = true; 176 | 177 | if (!doNotDestroyHijacked) { 178 | destroyAndRestore(); 179 | } 180 | 181 | readable.removeAllListeners(); 182 | } 183 | } 184 | 185 | function handleError(err) { 186 | if (!hasEnded) { 187 | hasEnded = true; 188 | if (err) { 189 | if ('commandLine' in err) { 190 | err.message = `${err.commandLine}: ${err.message}`; 191 | } 192 | if ( 193 | err.message === 194 | 'Input buffer contains unsupported image format' 195 | ) { 196 | err = new httpErrors.UnsupportedMediaType(err.message); 197 | } 198 | if (err.message === 'Input image exceeds pixel limit') { 199 | // ?metadata with an unrecognized image format 200 | err = new httpErrors.RequestEntityTooLarge(err.message); 201 | } 202 | 203 | readable.unpipe(pipeline); 204 | next(err); 205 | } 206 | destroyAndRestore(); 207 | cleanUp(true); 208 | } 209 | } 210 | 211 | readable.once('error', (err) => { 212 | // trigger teardown of all pipeline streams 213 | pipeline.emit(err); 214 | // respond with an error 215 | handleError(err); 216 | }); 217 | readable.once('close', () => { 218 | cleanUp(); 219 | }); 220 | 221 | const outputContentType = 222 | filterInfosAndTargetFormat.outputContentType; 223 | if (outputContentType) { 224 | res.setHeader('Content-Type', outputContentType); 225 | } 226 | 227 | const type = sourceMetadata && sourceMetadata.contentType; 228 | 229 | const pipeline = impro.createPipeline( 230 | { 231 | type, 232 | sourceMetadata, 233 | ...engines, 234 | maxInputPixels: options.maxInputPixels, 235 | maxOutputPixels: options.maxOutputPixels, 236 | sharpCache: options.sharpCache, 237 | sharpFailOnError: options.sharpFailOnError, 238 | svgAssetPath: options.root 239 | ? Path.resolve(options.root, req.url.substr(1)) 240 | : null, 241 | }, 242 | filterInfosAndTargetFormat.operations 243 | ); 244 | 245 | if (options.debug) { 246 | let usedEngines; 247 | try { 248 | usedEngines = pipeline.flush().usedEngines; 249 | } catch (e) { 250 | destroyAndRestore(); 251 | return next(e); 252 | } 253 | 254 | // Only used by the test suite to assert that the right engine is used to process gifs: 255 | res.setHeader( 256 | 'X-Express-Processimage', 257 | toUsedNames(usedEngines).join(',') 258 | ); 259 | } 260 | 261 | if (typeof options.onPipeline === 'function') { 262 | options.onPipeline(pipeline); 263 | } 264 | 265 | if (optionalFirstChunk) { 266 | try { 267 | pipeline.write(optionalFirstChunk); 268 | } catch (e) { 269 | destroyAndRestore(); 270 | return next(e); 271 | } 272 | } 273 | 274 | // send along processed data 275 | pipeline 276 | .on('error', handleError) 277 | .on('end', () => { 278 | if (!hasEnded) { 279 | hasEnded = true; 280 | cleanUp(); 281 | writable.end(); 282 | } 283 | }) 284 | .on('readable', function () { 285 | if (!hasEnded) { 286 | let data; 287 | while ((data = this.read())) { 288 | writable.write(data); 289 | } 290 | } 291 | }); 292 | 293 | // initiate processing 294 | readable.pipe(pipeline); 295 | } 296 | 297 | const contentType = res.getHeader('Content-Type'); 298 | let filterInfosAndTargetFormat; 299 | if (res.statusCode === 304) { 300 | readable.pipe(writable); 301 | } else if ( 302 | isMetadataRequest || 303 | (contentType && 304 | (options.allowedImageSourceContentTypes 305 | ? options.allowedImageSourceContentTypes.indexOf( 306 | contentType 307 | ) !== -1 308 | : contentType.indexOf('image/') === 0)) 309 | ) { 310 | sourceMetadata = { 311 | contentType, 312 | filesize: 313 | contentLengthHeaderValue && 314 | parseInt(contentLengthHeaderValue, 10), 315 | etag: oldETag, 316 | }; 317 | 318 | filterInfosAndTargetFormat = makeFilterInfosAndTargetFormat(); 319 | 320 | if (filterInfosAndTargetFormat.operations.length === 0) { 321 | return readable.pipe(writable); 322 | } 323 | 324 | if (options.secondGuessSourceContentType) { 325 | const endOrCloseOrErrorBeforeFirstDataChunkListener = (err) => { 326 | if (err) { 327 | next(500); 328 | } else { 329 | // FIXME: Here, if we call like "startProcessing();" (without any parameter), it fails for Node JS 12 or older 330 | startProcessing(Buffer.from([])); 331 | } 332 | }; 333 | readable.once( 334 | 'error', 335 | endOrCloseOrErrorBeforeFirstDataChunkListener 336 | ); 337 | readable.once( 338 | 'end', 339 | endOrCloseOrErrorBeforeFirstDataChunkListener 340 | ); 341 | readable.once('data', (firstChunk) => { 342 | readable.removeListener( 343 | 'end', 344 | endOrCloseOrErrorBeforeFirstDataChunkListener 345 | ); 346 | readable.removeListener( 347 | 'close', 348 | endOrCloseOrErrorBeforeFirstDataChunkListener 349 | ); 350 | let detectedContentType; 351 | if ( 352 | firstChunk[0] === 0x47 && 353 | firstChunk[1] === 0x49 && 354 | firstChunk[2] === 0x46 355 | ) { 356 | detectedContentType = 'image/gif'; 357 | } else if (firstChunk[0] === 0xff && firstChunk[1] === 0xd8) { 358 | detectedContentType = 'image/jpeg'; 359 | } else if ( 360 | firstChunk[0] === 0x89 && 361 | firstChunk[1] === 0x50 && 362 | firstChunk[2] === 0x4e && 363 | firstChunk[3] === 0x47 364 | ) { 365 | detectedContentType = 'image/png'; 366 | } else if (firstChunk[0] === 0x42 && firstChunk[1] === 0x4d) { 367 | detectedContentType = 'image/bmp'; 368 | } else if ( 369 | firstChunk[0] === 0x0 && 370 | firstChunk[1] === 0x0 && 371 | firstChunk[2] === 0x1 && 372 | firstChunk[3] === 0x0 373 | ) { 374 | detectedContentType = 'image/x-icon'; 375 | } else if ( 376 | firstChunk[8] === 0x57 && 377 | firstChunk[9] === 0x45 && 378 | firstChunk[10] === 0x42 && 379 | firstChunk[11] === 0x50 380 | ) { 381 | detectedContentType = 'image/webp'; 382 | } 383 | if ( 384 | detectedContentType && 385 | detectedContentType !== sourceMetadata.contentType 386 | ) { 387 | sourceMetadata.contentType = detectedContentType; 388 | } 389 | startProcessing(firstChunk); 390 | }); 391 | } else { 392 | startProcessing(); 393 | } 394 | } else { 395 | readable.pipe(writable); 396 | } 397 | } 398 | ); 399 | } else { 400 | next(); 401 | } 402 | }; 403 | 404 | // exposed for some testing scenarios 405 | middleware._impro = impro; 406 | 407 | return middleware; 408 | }; 409 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-processimage", 3 | "version": "11.2.0", 4 | "description": "Express middleware that processes served images according to the query string", 5 | "main": "lib/processImage.js", 6 | "files": [ 7 | "bin", 8 | "lib" 9 | ], 10 | "dependencies": { 11 | "accepts": "^1.3.8", 12 | "animated-gif-detector": "^1.2.0", 13 | "exif-reader": "^1.0.3", 14 | "gm-papandreou": "^1.23.0-patch1", 15 | "hijackresponse": "^5.0.0", 16 | "httperrors": "^2.3.0", 17 | "impro": "~0.14.1", 18 | "inkscape": "^3.0.0", 19 | "jpegtran": "^2.0.0", 20 | "mime": "^3.0.0", 21 | "optimist": "^0.6.1", 22 | "optipng": "^4.0.0", 23 | "passerror": "^1.1.1", 24 | "pngcrush": "^3.0.0", 25 | "pngquant": "^4.0.0", 26 | "sharp": "^0.32.0" 27 | }, 28 | "devDependencies": { 29 | "browser-sync": "^3.0.2", 30 | "compression": "^1.7.4", 31 | "eslint": "^8.56.0", 32 | "eslint-config-prettier": "^9.1.0", 33 | "eslint-config-standard": "^17.1.0", 34 | "eslint-plugin-import": "^2.29.1", 35 | "eslint-plugin-mocha": "^10.4.3", 36 | "eslint-plugin-n": "^16.6.2", 37 | "eslint-plugin-node": "^11.1.0", 38 | "eslint-plugin-promise": "^6.1.1", 39 | "eslint-plugin-standard": "^5.0.0", 40 | "express": "^4.18.2", 41 | "gifsicle": "^5.3.0", 42 | "magicpen": "^6.2.4", 43 | "magicpen-prism": "^5.0.1", 44 | "memoizesync": "^1.1.1", 45 | "mocha": "^10.2.0", 46 | "nyc": "^15.1.0", 47 | "offline-github-changelog": "^3.0.1", 48 | "prettier": "~3.2.1", 49 | "sinon": "^17.0.1", 50 | "svgfilter": "^4.0.0", 51 | "unexpected": "^12.0.5", 52 | "unexpected-express": "^13.1.2", 53 | "unexpected-http": "^9.0.0", 54 | "unexpected-image": "^4.1.0", 55 | "unexpected-sinon": "^11.1.0" 56 | }, 57 | "scripts": { 58 | "docker:build": "docker build -t express-processimage-dev .", 59 | "docker": "docker run --rm -it -v \"$(pwd):/home/nvm/express-processimage\" express-processimage-dev", 60 | "lint": "eslint . && prettier --check '**/*.{js,md}'", 61 | "test": "mocha", 62 | "coverage": "NODE_ENV=development nyc --reporter=lcov --reporter=text --all -- npm test && echo google-chrome coverage/lcov-report/index.html", 63 | "version": "offline-github-changelog --next=${npm_new_version} > CHANGELOG.md && git add CHANGELOG.md" 64 | }, 65 | "repository": { 66 | "type": "git", 67 | "url": "git://github.com/papandreou/express-processimage.git" 68 | }, 69 | "keywords": [ 70 | "express", 71 | "middleware", 72 | "image", 73 | "images", 74 | "png", 75 | "jpg", 76 | "jpeg", 77 | "resize", 78 | "scale", 79 | "graphicsmagick", 80 | "optipng", 81 | "pngcrush", 82 | "pngquant", 83 | "jpegtran" 84 | ], 85 | "author": "Andreas Lind ", 86 | "license": "BSD-3-Clause", 87 | "nyc": { 88 | "include": [ 89 | "lib/**" 90 | ] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /reallyaico.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/reallyaico.gif -------------------------------------------------------------------------------- /reallyawebp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/reallyawebp.png -------------------------------------------------------------------------------- /test/browsersync-compat.js: -------------------------------------------------------------------------------- 1 | const bs = require('browser-sync').create(); 2 | const expect = require('unexpected').clone(); 3 | const pathModule = require('path'); 4 | const root = `${pathModule.resolve(__dirname, '..', 'testdata')}/`; 5 | const processImage = require('../lib/processImage'); 6 | 7 | const serverPort = '9999'; 8 | 9 | expect.use(require('unexpected-http')).use(require('unexpected-image')); 10 | 11 | describe('browser-sync compatibility', () => { 12 | before((done) => { 13 | bs.init( 14 | { 15 | port: serverPort, 16 | server: root, 17 | open: false, 18 | logLevel: 'silent', 19 | middleware: [processImage({ root })], 20 | }, 21 | done 22 | ); 23 | }); 24 | 25 | after(() => { 26 | bs.exit(); 27 | }); 28 | 29 | it('should not mess with request for non-image file', () => 30 | expect( 31 | `GET http://localhost:${serverPort}/something.txt`, 32 | 'to yield response', 33 | { 34 | headers: { 35 | 'Content-Type': 'text/plain; charset=UTF-8', 36 | }, 37 | body: 'foo\n', 38 | } 39 | )); 40 | 41 | it('should not mess with request for image with no query string', () => 42 | expect( 43 | `GET http://localhost:${serverPort}/ancillaryChunks.png`, 44 | 'to yield response', 45 | { 46 | headers: { 47 | 'Content-Type': 'image/png', 48 | }, 49 | body: expect.it('to have length', 3711), 50 | } 51 | )); 52 | 53 | it('should not mess with request for image with an unsupported operation in the query string', () => 54 | expect( 55 | `GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, 56 | 'to yield response', 57 | { 58 | headers: { 59 | 'Content-Type': 'image/png', 60 | }, 61 | body: expect.it('to have length', 3711), 62 | } 63 | )); 64 | 65 | it('should return a 304 status code when requesting the same image with unchanged modifications', () => 66 | expect( 67 | `GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, 68 | 'to yield response', 69 | { 70 | statusCode: 200, 71 | headers: { 72 | 'Content-Type': 'image/png', 73 | }, 74 | body: expect.it('to have length', 3711), 75 | } 76 | ).then((context) => { 77 | const etag = context.httpResponse.headers.get('ETag'); 78 | return expect( 79 | { 80 | url: `GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, 81 | headers: { 82 | 'If-None-Match': etag, 83 | }, 84 | }, 85 | 'to yield response', 86 | { 87 | statusCode: 304, 88 | headers: expect.it('to be empty'), 89 | body: expect.it('to be', ''), 90 | } 91 | ); 92 | })); 93 | 94 | it('should run the image through pngcrush when the pngcrush CGI param is specified', () => 95 | expect( 96 | `GET http://localhost:${serverPort}/ancillaryChunks.png?pngcrush=-rem+alla`, 97 | 'to yield response', 98 | { 99 | statusCode: 200, 100 | headers: { 101 | 'Content-Type': 'image/png', 102 | }, 103 | body: expect 104 | .it('to have metadata satisfying', { 105 | format: 'PNG', 106 | size: { 107 | width: 400, 108 | height: 20, 109 | }, 110 | }) 111 | .and((body) => { 112 | expect(body.length, 'to be within', 1, 3711); 113 | }), 114 | } 115 | )); 116 | }); 117 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec 2 | --timeout 60000 3 | --recursive 4 | --check-leaks 5 | -------------------------------------------------------------------------------- /test/processImage.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const fs = require('fs'); 3 | const http = require('http'); 4 | const pathModule = require('path'); 5 | const unexpected = require('unexpected'); 6 | const sinon = require('sinon'); 7 | const processImage = require('../lib/processImage'); 8 | const memoizeSync = require('memoizesync'); 9 | const sharp = require('sharp'); 10 | 11 | const isDarwin = process.platform === 'darwin'; 12 | const root = `${pathModule.resolve(__dirname, '..', 'testdata')}/`; 13 | 14 | const itSkipMac = isDarwin ? it.skip : it; 15 | 16 | const load = memoizeSync((fileName) => 17 | fs.readFileSync(pathModule.resolve(__dirname, '..', 'testdata', fileName)) 18 | ); 19 | 20 | /* 21 | Sample guide for updating image test data: 22 | * Suppose, the original test case looks like this: 23 | it('should do an entropy-based crop', () => 24 | expect( 25 | 'GET /turtle.jpg?resize=100,200&crop=entropy', 26 | 'to yield response', 27 | { 28 | body: expect 29 | .it('to equal', load('turtleCroppedEntropy100x200.jpg')) 30 | .and('to have metadata satisfying', { 31 | size: { 32 | width: 100, 33 | height: 200 34 | } 35 | }) 36 | } 37 | )); 38 | * Rename the concerned file to the new name (turtleCroppedEntropy100x200.jpg -> turtleCroppedEntropy100x200.old.jpg) 39 | * Now, temporarily update the test case in a way to make it pass, like: 40 | it('should do an entropy-based crop', () => 41 | expect( 42 | 'GET /turtle.jpg?resize=100,200&crop=entropy', 43 | 'to yield response', 44 | { 45 | statusCode: 200 46 | } 47 | ).then((context) => { 48 | const outputPath = pathModule.resolve(root, 'turtleCroppedEntropy100x200.jpg'); 49 | const body = context.httpResponse.body; 50 | fs.writeFileSync(outputPath, body); 51 | })); 52 | * Run the test case. This will create a new file with the new name (turtleCroppedEntropy100x200.jpg) 53 | * Now, compare the new file with the old file using appropriate tool, if required 54 | * If the new file is: 55 | * Correct, then: 56 | * revert the test case to the original state 57 | * delete the old file (turtleCroppedEntropy100x200.old.jpg) 58 | * Incorrect, then: 59 | * revert the test case to the original state and investigate 60 | */ 61 | 62 | describe('express-processimage', () => { 63 | let config; 64 | let impro; 65 | let sandbox; 66 | 67 | beforeEach(() => { 68 | config = { root, filters: {} }; 69 | sandbox = sinon.createSandbox(); 70 | }); 71 | 72 | afterEach(() => { 73 | if (impro) { 74 | // clear the cache marker to ensure clean state for each test 75 | delete impro._sharpCacheSet; 76 | } 77 | sandbox.restore(); 78 | }); 79 | 80 | const expect = unexpected 81 | .clone() 82 | .use(require('unexpected-express')) 83 | .use(require('unexpected-http')) 84 | .use(require('unexpected-image')) 85 | .use(require('unexpected-sinon')) 86 | .use(require('magicpen-prism')) 87 | .addAssertion( 88 | ' to yield response ', 89 | (expect, subject, value) => { 90 | const middleware = processImage(config); 91 | 92 | impro = middleware._impro; 93 | 94 | const app = express().use(middleware).use(express.static(root)); 95 | 96 | return expect(app, 'to yield exchange', { 97 | request: subject, 98 | response: value, 99 | }); 100 | } 101 | ) 102 | .addAssertion( 103 | ' [when] converted to PNG ', 104 | (expect, subject) => { 105 | expect.errorMode = 'bubble'; 106 | return sharp(subject) 107 | .png() 108 | .toBuffer() 109 | .then((pngBuffer) => expect.shift(pngBuffer)); 110 | } 111 | ); 112 | 113 | it('should not mess with request for non-image file', () => 114 | expect('GET /something.txt', 'to yield response', { 115 | headers: { 116 | 'Content-Type': 'text/plain; charset=UTF-8', 117 | }, 118 | body: 'foo\n', 119 | })); 120 | 121 | it('should not mess with request for image with no query string', () => 122 | expect('GET /ancillaryChunks.png', 'to yield response', { 123 | headers: { 124 | 'Content-Type': 'image/png', 125 | }, 126 | body: expect.it('to have length', 3711), 127 | })); 128 | 129 | it('should not mess with request for image with an unsupported operation in the query string', () => 130 | expect('GET /ancillaryChunks.png?foo=bar', 'to yield response', { 131 | headers: { 132 | 'Content-Type': 'image/png', 133 | }, 134 | body: expect.it('to have length', 3711), 135 | })); 136 | 137 | it('refuses to process an image whose dimensions exceed maxInputPixels', () => { 138 | config.maxInputPixels = 100000; 139 | return expect('GET /hugearea.png?resize=100,100', 'to yield response', 413); 140 | }); 141 | 142 | it('refuses to process an empty image', () => { 143 | config.secondGuessSourceContentType = true; 144 | return expect('GET /empty.jpg?resize=100,100', 'to yield response', 415); 145 | }); 146 | 147 | describe('with the sharp engine', () => { 148 | describe('when omitting the height', () => { 149 | it('should do a proportional resize to the given width', () => 150 | expect('GET /turtle.jpg?resize=500,', 'to yield response', { 151 | body: expect.it('to have metadata satisfying', { 152 | size: { 153 | width: 500, 154 | height: 441, 155 | }, 156 | }), 157 | })); 158 | 159 | describe('without a trailing comma', () => { 160 | it('should do a proportional resize to the given width', () => 161 | expect('GET /turtle.jpg?resize=500', 'to yield response', { 162 | body: expect.it('to have metadata satisfying', { 163 | size: { 164 | width: 500, 165 | height: 441, 166 | }, 167 | }), 168 | })); 169 | }); 170 | 171 | describe('with a maxOutputPixels setting in place', () => { 172 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 173 | config.maxOutputPixels = 250000; 174 | return expect('GET /turtle.jpg?resize=2000,', 'to yield response', { 175 | body: expect.it('to have metadata satisfying', { 176 | size: { 177 | width: 142, 178 | height: 125, 179 | }, 180 | }), 181 | }); 182 | }); 183 | }); 184 | }); 185 | 186 | describe('when omitting the width', () => { 187 | it('should do a proportional resize to the given height', () => 188 | expect('GET /turtle.jpg?resize=,500', 'to yield response', { 189 | body: expect.it('to have metadata satisfying', { 190 | size: { 191 | width: 567, 192 | height: 500, 193 | }, 194 | }), 195 | })); 196 | 197 | describe('with a maxOutputPixels setting in place', () => { 198 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 199 | config.maxOutputPixels = 250000; 200 | return expect('GET /turtle.jpg?resize=,2000', 'to yield response', { 201 | body: expect.it('to have metadata satisfying', { 202 | size: { 203 | width: 125, 204 | height: 110, 205 | }, 206 | }), 207 | }); 208 | }); 209 | }); 210 | }); 211 | 212 | it('should do an entropy-based crop', () => 213 | expect( 214 | 'GET /turtle.jpg?resize=100,200&crop=entropy', 215 | 'to yield response', 216 | { 217 | body: expect 218 | .it('to equal', load('turtleCroppedEntropy100x200.jpg')) 219 | .and('to have metadata satisfying', { 220 | size: { 221 | width: 100, 222 | height: 200, 223 | }, 224 | }), 225 | } 226 | )); 227 | 228 | it('should do an attention-based crop', () => 229 | expect( 230 | 'GET /turtle.jpg?resize=100,200&crop=attention', 231 | 'to yield response', 232 | { 233 | body: expect 234 | .it('to equal', load('turtleCroppedAttention100x200.jpg')) 235 | .and('to have metadata satisfying', { 236 | size: { 237 | width: 100, 238 | height: 200, 239 | }, 240 | }), 241 | } 242 | )); 243 | 244 | // https://github.com/papandreou/express-processimage/issues/23 245 | describe('when the quality and progressiveness of the image is being adjusted', () => { 246 | it('should work and not log deprecation warnings when there is no explicit conversion', () => { 247 | sandbox.spy(console, 'error'); 248 | return expect( 249 | 'GET /turtle.jpg?quality=10&progressive', 250 | 'to yield response', 251 | { 252 | body: expect.it('to have metadata satisfying', { 253 | size: { 254 | width: 481, 255 | height: 424, 256 | }, 257 | Interlace: 'Line', 258 | Filesize: expect 259 | .it('to match', /Ki?$/) 260 | .and( 261 | 'when passed as parameter to', 262 | parseFloat, 263 | 'to be less than', 264 | 10 265 | ), 266 | }), 267 | } 268 | ).then(() => 269 | expect(console.error, 'to have no calls satisfying', [ 270 | /DeprecationWarning/, 271 | ]) 272 | ); 273 | }); 274 | 275 | it('should work and not log deprecation warnings when there is an explicit conversion', () => { 276 | sandbox.spy(console, 'error'); 277 | return expect( 278 | 'GET /turtle.jpg?jpeg&quality=10&progressive', 279 | 'to yield response', 280 | { 281 | body: expect.it('to have metadata satisfying', { 282 | size: { 283 | width: 481, 284 | height: 424, 285 | }, 286 | Interlace: 'Line', 287 | Filesize: expect 288 | .it('to match', /Ki?$/) 289 | .and( 290 | 'when passed as parameter to', 291 | parseFloat, 292 | 'to be less than', 293 | 10 294 | ), 295 | }), 296 | } 297 | ).then(() => 298 | expect(console.error, 'to have no calls satisfying', [ 299 | /DeprecationWarning/, 300 | ]) 301 | ); 302 | }); 303 | }); 304 | 305 | it('should resize by specifying a bounding box (gm)', () => 306 | expect('GET /turtle.jpg?gm&resize=500,1000', 'to yield response', { 307 | body: expect.it('to have metadata satisfying', { 308 | size: { 309 | width: 500, 310 | height: 441, 311 | }, 312 | }), 313 | })); 314 | 315 | describe('with an explicit &sharp parameter', () => { 316 | it('should resize by specifying a bounding box', () => 317 | expect('GET /turtle.jpg?sharp&resize=500,1000', 'to yield response', { 318 | body: expect.it('to have metadata satisfying', { 319 | size: { 320 | width: 500, 321 | height: 441, 322 | }, 323 | }), 324 | })); 325 | }); 326 | 327 | // https://github.com/lovell/sharp/issues/375#issuecomment-214546310 328 | it.skip('should process and convert a transparent gif', () => 329 | expect('GET /transparentbw.gif?flip&png', 'to yield response', { 330 | body: expect.it('to have metadata satisfying', { 331 | format: 'PNG', 332 | }), 333 | })); 334 | 335 | it('should apply the sharpCache option', () => { 336 | config.sharpCache = 123; 337 | const cacheStub = sandbox.stub(sharp, 'cache'); 338 | return expect('GET /turtle.jpg?metadata', 'to yield response', { 339 | body: { 340 | contentType: 'image/jpeg', 341 | }, 342 | }).then(() => { 343 | expect(cacheStub, 'to have a call satisfying', [123]); 344 | }); 345 | }); 346 | 347 | it('should allow retrieving the image metadata as JSON and support conditional GET', () => 348 | expect('GET /turtle.jpg?metadata', 'to yield response', { 349 | headers: { 350 | ETag: expect.it('to be a string'), 351 | }, 352 | body: { 353 | contentType: 'image/jpeg', 354 | filesize: 105836, 355 | etag: expect 356 | .it('to match', /^W\//) 357 | .and('not to contain', '-processimage'), 358 | width: 481, 359 | height: 424, 360 | space: 'srgb', 361 | channels: 3, 362 | hasProfile: false, 363 | hasAlpha: false, 364 | }, 365 | }).then((context) => 366 | expect( 367 | { 368 | url: 'GET /turtle.jpg?metadata', 369 | headers: { 370 | 'If-None-Match': context.httpResponse.headers.get('ETag'), 371 | }, 372 | }, 373 | 'to yield response', 374 | 304 375 | ) 376 | )); 377 | 378 | // Regression test 379 | it('should not break when serving a 304 to a ?metadata request when secondGuessSourceContentType is enabled', () => { 380 | config.secondGuessSourceContentType = true; 381 | return expect( 382 | express() 383 | .use(processImage(config)) 384 | .use((req, res, next) => { 385 | res.status(304).end(); 386 | }), 387 | 'to yield exchange', 388 | { 389 | request: { 390 | url: 'GET /turtle.jpg?metadata', 391 | headers: { 392 | 'If-None-Match': '"foobar"', 393 | }, 394 | }, 395 | response: 304, 396 | } 397 | ); 398 | }); 399 | 400 | it('should allow retrieving the metadata of a non-image file with a non-image extension', () => 401 | expect('GET /something.txt?metadata', 'to yield response', { 402 | body: { 403 | contentType: 'text/plain; charset=UTF-8', 404 | filesize: 4, 405 | etag: expect.it('to be a string'), 406 | }, 407 | })); 408 | 409 | it('should allow retrieving the metadata of a non-image file with a non-image extension, even when unlisted in allowedImageSourceContentTypes', () => { 410 | config.allowedImageSourceContentTypes = ['image/png']; 411 | return expect('GET /something.txt?metadata', 'to yield response', { 412 | body: { 413 | contentType: 'text/plain; charset=UTF-8', 414 | filesize: 4, 415 | etag: expect.it('to be a string'), 416 | }, 417 | }); 418 | }); 419 | 420 | it('should set animated:true for an animated gif', () => 421 | expect('GET /animated.gif?metadata', 'to yield response', { 422 | body: { 423 | animated: true, 424 | }, 425 | })); 426 | 427 | it('should set animated:false for a non-animated gif', () => 428 | expect('GET /bulb.gif?metadata', 'to yield response', { 429 | body: { 430 | animated: false, 431 | }, 432 | })); 433 | 434 | it('should allow support ?metadata=true as well (legacy)', () => 435 | expect('GET /turtle.jpg?metadata=true', 'to yield response', { 436 | body: { 437 | contentType: 'image/jpeg', 438 | filesize: 105836, 439 | etag: /^W\//, 440 | width: 481, 441 | height: 424, 442 | space: 'srgb', 443 | channels: 3, 444 | hasProfile: false, 445 | hasAlpha: false, 446 | }, 447 | })); 448 | 449 | it('should allow retrieving the image metadata of a GIF', () => 450 | expect('GET /animated.gif?metadata', 'to yield response', { 451 | body: { 452 | format: 'gif', 453 | contentType: 'image/gif', 454 | filesize: 362, 455 | }, 456 | })); 457 | 458 | it('should allow retrieving the image metadata of a JPEG converted to GIF', () => 459 | expect('GET /turtle.jpg?setFormat=gif&metadata', 'to yield response', { 460 | body: { 461 | format: 'gif', 462 | contentType: 'image/gif', 463 | }, 464 | })); 465 | 466 | it('should allow retrieving the image metadata for the result of an operation', () => 467 | expect( 468 | 'GET /turtle.jpg?png&greyscale&resize=10,9&metadata', 469 | 'to yield response', 470 | { 471 | body: { 472 | width: 10, 473 | height: 9, 474 | space: 'srgb', 475 | channels: 3, 476 | hasProfile: false, 477 | hasAlpha: false, 478 | }, 479 | } 480 | )); 481 | 482 | it('should include the EXIF data in the image metadata', () => 483 | expect('GET /exifOriented.jpg?metadata', 'to yield response', { 484 | body: { 485 | image: { 486 | Make: 'Apple', 487 | Model: 'iPhone 6', 488 | }, 489 | exif: { 490 | ExposureTime: 0.025, 491 | }, 492 | }, 493 | })); 494 | 495 | it('should include orientedWidth and orientedHeight properties when the EXIF data specifies an orientation', () => 496 | expect('GET /exifOriented.jpg?metadata', 'to yield response', { 497 | body: { 498 | width: 3264, 499 | height: 2448, 500 | orientedWidth: 2448, 501 | orientedHeight: 3264, 502 | }, 503 | })); 504 | 505 | it('should auto-orient an image', () => 506 | expect('GET /exifOriented.jpg?rotate', 'to yield response', { 507 | body: expect.it('to have metadata satisfying', { 508 | size: { 509 | width: 2448, 510 | height: 3264, 511 | }, 512 | }), 513 | })); 514 | 515 | // Not yet supported by graphicsmagick (although imagemagick has -auto-orient) 516 | it.skip('should auto-orient an image with the gm engine', () => { 517 | config.debug = true; 518 | return expect('GET /exifOriented.jpg?gm&rotate', 'to yield response', { 519 | headers: { 520 | 'X-Express-Processimage': 'gm', 521 | }, 522 | body: expect.it('to have metadata satisfying', { 523 | size: { 524 | width: 2448, 525 | height: 3264, 526 | }, 527 | }), 528 | }); 529 | }); 530 | 531 | it('should parse the ICC Profile data if available', () => 532 | expect('GET /Landscape_8.jpg?metadata', 'to yield response', { 533 | body: { 534 | icc: { 535 | deviceClass: 'Monitor', 536 | colorSpace: 'RGB', 537 | // etc. 538 | }, 539 | }, 540 | })); 541 | 542 | it('should send back the upstream Content-Type and Content-Length when ?metadata is applied to a non-image with an image extension', () => 543 | expect('GET /certainlynotanimage.jpg?metadata', 'to yield response', { 544 | body: { 545 | contentType: 'image/jpeg', 546 | error: 'Input buffer contains unsupported image format', 547 | filesize: 4, 548 | etag: expect.it('to be a string'), 549 | }, 550 | })); 551 | 552 | it('should send back an error when an operation is applied to a non-image', () => 553 | expect( 554 | 'GET /certainlynotanimage.jpg?resize=10,10', 555 | 'to yield response', 556 | 415 557 | )); 558 | 559 | it('should allow a crop operation with the gravity specified as a string', () => 560 | expect('GET /turtle.jpg?resize=40,15&crop=north', 'to yield response', { 561 | body: expect.it('to equal', load('turtleCroppedNorth.jpg')), 562 | })); 563 | 564 | // https://github.com/lovell/sharp/issues/276 565 | it('should fix the ordering of the parameters to extract to be left,top,width,height', () => 566 | expect('GET /turtle.jpg?extract=40,60,30,40', 'to yield response', { 567 | body: expect.it('to equal', load('turtleExtract.jpg')), 568 | })); 569 | 570 | it('should propagate a "bad extract area" error correctly', () => 571 | expect('GET /turtle.jpg?extract=99,99,9999,9999', 'to yield response', { 572 | errorPassedToNext: /bad extract area/, 573 | })); 574 | 575 | it('should convert an animated gif to png', () => 576 | expect('GET /animated.gif?png', 'to yield response', { 577 | body: expect.it('to have metadata satisfying', { 578 | format: 'PNG', 579 | size: { 580 | width: 23, 581 | height: 20, 582 | }, 583 | }), 584 | })); 585 | 586 | it('should use the best engine for an operation for a GIF', () => { 587 | config.debug = true; 588 | return expect( 589 | 'GET /animated.gif?resize=40,100&png', 590 | 'to yield response', 591 | { 592 | headers: { 593 | 'X-Express-Processimage': 'gifsicle,sharp', 594 | }, 595 | body: expect.it('to have metadata satisfying', { 596 | format: 'PNG', 597 | size: { 598 | width: 23, 599 | }, 600 | }), 601 | } 602 | ); 603 | }); 604 | 605 | it('should support creating a progressive jpeg', () => { 606 | config.debug = true; 607 | return expect( 608 | 'GET /turtle.jpg?resize=100,100&progressive', 609 | 'to yield response', 610 | { 611 | body: expect.it('to have metadata satisfying', { 612 | size: { 613 | width: 100, 614 | height: 88, 615 | }, 616 | Interlace: 'Line', 617 | }), 618 | } 619 | ); 620 | }); 621 | 622 | it('should ignore invalid operations', () => 623 | expect('GET /turtle.jpg?resize=10%22', 'to yield response', { 624 | body: expect.it('to have metadata satisfying', { 625 | size: { 626 | width: 481, 627 | height: 424, 628 | }, 629 | }), 630 | })); 631 | 632 | it('should not have uncaught error when processing an image with bugos resize value', () => { 633 | config.secondGuessSourceContentType = true; 634 | return expect( 635 | 'GET /ancillaryChunks.png?ignoreAspectRatio&resize=22239,200&crop=center', 636 | 'to yield response', 637 | { 638 | errorPassedToNext: 639 | /sharp: ignoreAspectRatio\(\) operation must follow resize/, 640 | } 641 | ); 642 | }); 643 | }); 644 | 645 | it('should run the image through pngcrush when the pngcrush CGI param is specified', () => 646 | expect('GET /ancillaryChunks.png?pngcrush=-rem+alla', 'to yield response', { 647 | statusCode: 200, 648 | headers: { 649 | 'Content-Type': 'image/png', 650 | }, 651 | body: expect 652 | .it('to have metadata satisfying', { 653 | format: 'PNG', 654 | size: { 655 | width: 400, 656 | height: 20, 657 | }, 658 | }) 659 | .and((body) => { 660 | expect(body.length, 'to be within', 1, 3711); 661 | }), 662 | })); 663 | 664 | it('should run the image through pngquant when the pngquant CGI param is specified', () => 665 | expect('GET /purplealpha24bit.png?pngquant', 'to yield response', { 666 | statusCode: 200, 667 | headers: { 668 | 'Content-Type': 'image/png', 669 | }, 670 | body: expect 671 | .it('to have metadata satisfying', { 672 | format: 'PNG', 673 | size: { 674 | width: 100, 675 | height: 100, 676 | }, 677 | }) 678 | .and((body) => { 679 | expect(body.length, 'to be within', 1, 8285); 680 | }), 681 | })); 682 | 683 | it('should run the image through jpegtran when the jpegtran CGI param is specified', () => 684 | expect( 685 | 'GET /turtle.jpg?jpegtran=-grayscale,-flip,horizontal', 686 | 'to yield response', 687 | { 688 | statusCode: 200, 689 | headers: { 690 | 'Content-Type': 'image/jpeg', 691 | }, 692 | body: expect 693 | .it('to have metadata satisfying', { 694 | format: 'JPEG', 695 | 'Channel Depths': { 696 | Gray: '8 bits', 697 | }, 698 | size: { 699 | width: 481, 700 | height: 424, 701 | }, 702 | }) 703 | .and((body) => { 704 | expect(body.length, 'to be within', 1, 105836); 705 | }), 706 | } 707 | )); 708 | 709 | it('should run the image through graphicsmagick when methods exposed by the gm module are added as CGI params', () => 710 | expect('GET /turtle.jpg?gm&resize=340,300', 'to yield response', { 711 | statusCode: 200, 712 | headers: { 713 | 'Content-Type': 'image/jpeg', 714 | }, 715 | body: expect 716 | .it('to have metadata satisfying', { 717 | format: 'JPEG', 718 | size: { 719 | width: 340, 720 | height: 300, 721 | }, 722 | }) 723 | .and((body) => { 724 | expect(body.length, 'to be within', 1, 105836); 725 | expect( 726 | body.slice(0, 10), 727 | 'to equal', 728 | Buffer.from([ 729 | 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 730 | ]) 731 | ); 732 | }), 733 | })); 734 | 735 | it('should run the image through sharp when methods exposed by the sharp module are added as CGI params', () => 736 | expect('GET /turtle.jpg?sharp&resize=340,300&png', 'to yield response', { 737 | statusCode: 200, 738 | headers: { 739 | 'Content-Type': 'image/png', 740 | }, 741 | body: expect.it('to have metadata satisfying', { 742 | format: 'PNG', 743 | size: { 744 | width: 340, 745 | height: 300, 746 | }, 747 | }), 748 | })); 749 | 750 | it('should run the image through svgfilter when the svgfilter parameter is specified', () => 751 | expect( 752 | 'GET /dialog-information.svg?svgfilter=--runScript=addBogusElement.js,--bogusElementId=theBogusElementId', 753 | 'to yield response', 754 | { 755 | statusCode: 200, 756 | headers: { 757 | 'Content-Type': 'image/svg+xml', 758 | ETag: /"\w+-\w+-processimage"$/, 759 | }, 760 | body: expect 761 | .it('to match', / { 765 | const etag = context.httpResponse.headers.get('ETag'); 766 | return expect( 767 | { 768 | url: 'GET /dialog-information.svg?svgfilter=--runScript=addBogusElement.js,--bogusElementId=theBogusElementId', 769 | headers: { 770 | 'If-None-Match': etag, 771 | }, 772 | }, 773 | 'to yield response', 774 | { 775 | statusCode: 304, 776 | headers: { 777 | ETag: etag, 778 | }, 779 | } 780 | ); 781 | })); 782 | 783 | it('should run the image through multiple filters when multiple CGI params are specified', () => 784 | expect( 785 | 'GET /purplealpha24bit.png?resize=800,800&pngquant=8&pngcrush=-rem,gAMA', 786 | 'to yield response', 787 | { 788 | statusCode: 200, 789 | headers: { 790 | 'Content-Type': 'image/png', 791 | }, 792 | body: expect 793 | .it('when decoded as', 'ascii', 'not to match', /gAMA/) 794 | .and('to satisfy', { 795 | length: expect.it('to be greater than', 0), 796 | }) 797 | .and('to have metadata satisfying', { 798 | format: 'PNG', 799 | size: { 800 | width: 800, 801 | height: 800, 802 | }, 803 | }), 804 | } 805 | )); 806 | 807 | it('should serve a converted image with the correct Content-Type', () => 808 | expect('GET /purplealpha24bit.png?setFormat=jpg', 'to yield response', { 809 | statusCode: 200, 810 | headers: { 811 | 'Content-Type': 'image/jpeg', 812 | ETag: /-processimage/, 813 | }, 814 | body: expect 815 | .it('when decoded as', 'ascii', 'not to match', /gAMA/) 816 | .and('to satisfy', { 817 | length: expect.it('to be greater than', 0), 818 | }) 819 | .and('to have metadata satisfying', { 820 | format: 'JPEG', 821 | size: { 822 | width: 100, 823 | height: 100, 824 | }, 825 | }), 826 | }).then((context) => { 827 | const etag = context.httpResponse.headers.get('ETag'); 828 | return expect( 829 | { 830 | url: 'GET /purplealpha24bit.png?setFormat=jpg', 831 | headers: { 832 | 'If-None-Match': etag, 833 | }, 834 | }, 835 | 'to yield response', 836 | { 837 | statusCode: 304, 838 | headers: { 839 | ETag: etag, 840 | }, 841 | } 842 | ); 843 | })); 844 | 845 | it('should serve an error response if an invalid image is processed with GraphicsMagick', () => 846 | expect('GET /invalidImage.png?setFormat=jpg', 'to yield response', { 847 | errorPassedToNext: true, 848 | })); 849 | 850 | it('should serve an error response if an invalid image is processed with pngquant', () => 851 | expect('GET /invalidImage.png?pngquant', 'to yield response', { 852 | errorPassedToNext: true, 853 | })); 854 | 855 | it('should include the command line in the response body when an error is encountered', () => 856 | // TODO: This test results in a statusCode 404. That is weird... 857 | expect('GET /notajpeg.jpg?jpegtran=-grayscale', 'to yield response', { 858 | errorPassedToNext: /jpegtran -grayscale:/, 859 | })); 860 | 861 | // Undetectable by gm -- the source format must be explicitly specified 862 | it('should convert an icon to png via GraphicsMagick', () => 863 | expect('GET /favicon.ico?gm&png', 'to yield response', { 864 | headers: { 865 | 'Content-Type': 'image/png', 866 | }, 867 | body: expect.it('to have metadata satisfying', { 868 | format: 'PNG', 869 | size: { 870 | width: 16, 871 | height: 16, 872 | }, 873 | }), 874 | })); 875 | 876 | it('should convert an icon served as image/vnd.microsoft.icon to png via GraphicsMagick', () => 877 | expect( 878 | express() 879 | .use(processImage(config)) 880 | .get('/favicon.ico', (req, res, next) => { 881 | res.setHeader('Content-Type', 'image/vnd.microsoft.icon'); 882 | fs.createReadStream( 883 | pathModule.resolve(__dirname, '..', 'testdata', 'favicon.ico') 884 | ).pipe(res); 885 | }), 886 | 'to yield exchange', 887 | { 888 | request: 'GET /favicon.ico?gm&png', 889 | response: { 890 | headers: { 891 | 'Content-Type': 'image/png', 892 | }, 893 | body: expect.it('to have metadata satisfying', { 894 | format: 'PNG', 895 | size: { 896 | width: 16, 897 | height: 16, 898 | }, 899 | }), 900 | }, 901 | } 902 | )); 903 | 904 | describe('with an allowOperation option', () => { 905 | beforeEach(() => { 906 | config.allowOperation = sandbox 907 | .spy((keyValue) => keyValue !== 'png') 908 | .named('allowOperation'); 909 | }); 910 | 911 | it('should allow an operation for which allowOperation returns true', () => 912 | expect('GET /turtle.jpg?resize=87,100', 'to yield response', { 913 | headers: { 914 | 'Content-Type': 'image/jpeg', 915 | }, 916 | body: expect.it('to have metadata satisfying', { size: { width: 87 } }), 917 | }).then(() => { 918 | expect(config.allowOperation, 'to have a call satisfying', [ 919 | 'resize', 920 | [87, 100], 921 | ]); 922 | })); 923 | 924 | it('should disallow an operation for which allowOperation returns false', () => 925 | expect('GET /turtle.jpg?png', 'to yield response', { 926 | headers: { 927 | 'Content-Type': 'image/jpeg', 928 | }, 929 | body: expect.it('to have metadata satisfying', { 930 | format: 'JPEG', 931 | }), 932 | }).then(() => { 933 | expect(config.allowOperation, 'to have a call satisfying', ['png', []]); 934 | })); 935 | }); 936 | 937 | it('should process a big image when the compression middleware is present above express-processimage', () => 938 | expect( 939 | express() 940 | .use(require('compression')()) 941 | .use(processImage()) 942 | .use(express.static(root)), 943 | 'to yield exchange', 944 | { 945 | request: 946 | 'GET /the-villa-facade.png?sourceContentType=image%2Fpng&ignoreAspectRatio&resize=652,435&extract=315,10,280,420', 947 | response: { 948 | body: expect.it('to have metadata satisfying', { 949 | format: 'PNG', 950 | size: { 951 | width: 280, 952 | height: 420, 953 | }, 954 | }), 955 | }, 956 | } 957 | )); 958 | 959 | it('should work fine when cropping an item starting from top 0 and left 0', () => 960 | expect('GET /turtle.jpg?extract=0,0,300,200', 'to yield response', { 961 | body: expect.it('to equal', load('turtleCropped300x200FromTopLeft.jpg')), 962 | })); 963 | 964 | describe('with the gm engine', () => { 965 | itSkipMac('should allow a crop operation with a gravity of center', () => { 966 | return expect( 967 | 'GET /turtle.jpg?gm&resize=40,15&crop=center', 968 | 'to yield response', 969 | { 970 | body: expect.it('to equal', load('turtleCroppedCenterGm.jpg')), 971 | } 972 | ); 973 | }); 974 | 975 | itSkipMac('should allow a crop operation with a gravity of northeast', () => 976 | expect( 977 | 'GET /turtle.jpg?gm&resize=40,15&crop=northeast', 978 | 'to yield response', 979 | { 980 | body: expect.it('to equal', load('turtleCroppedNorthEastGm.jpg')), 981 | } 982 | ) 983 | ); 984 | 985 | describe('when omitting the height', () => { 986 | it('should do a proportional resize to the given width', () => 987 | expect('GET /turtle.jpg?gm&resize=500,', 'to yield response', { 988 | body: expect.it('to have metadata satisfying', { 989 | size: { 990 | width: 500, 991 | height: 441, 992 | }, 993 | }), 994 | })); 995 | 996 | describe('with a maxOutputPixels setting in place', () => { 997 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 998 | config.maxOutputPixels = 250000; 999 | return expect( 1000 | 'GET /turtle.jpg?gm&resize=2000,', 1001 | 'to yield response', 1002 | { 1003 | body: expect.it('to have metadata satisfying', { 1004 | size: { 1005 | width: 142, 1006 | height: 125, 1007 | }, 1008 | }), 1009 | } 1010 | ); 1011 | }); 1012 | }); 1013 | }); 1014 | 1015 | describe('when omitting the width', () => { 1016 | it('should do a proportional resize to the given height', () => 1017 | expect('GET /turtle.jpg?gm&resize=,500', 'to yield response', { 1018 | body: expect.it('to have metadata satisfying', { 1019 | size: { 1020 | width: 567, 1021 | height: 500, 1022 | }, 1023 | }), 1024 | })); 1025 | 1026 | describe('with a maxOutputPixels setting in place', () => { 1027 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 1028 | config.maxOutputPixels = 250000; 1029 | return expect( 1030 | 'GET /turtle.jpg?gm&resize=,2000', 1031 | 'to yield response', 1032 | { 1033 | body: expect.it('to have metadata satisfying', { 1034 | size: { 1035 | width: 125, 1036 | height: 110, 1037 | }, 1038 | }), 1039 | } 1040 | ); 1041 | }); 1042 | }); 1043 | }); 1044 | }); 1045 | 1046 | describe('with a GIF', () => { 1047 | [true, false].forEach((gifsicleAvailable) => { 1048 | const engineName = gifsicleAvailable ? 'gifsicle' : 'im'; 1049 | 1050 | describe(`with gifsicle ${ 1051 | gifsicleAvailable ? '' : 'un' 1052 | }available`, () => { 1053 | beforeEach(() => { 1054 | config.filters.gifsicle = gifsicleAvailable; 1055 | // use imageMagick to produce consistently identical output 1056 | config.filters.gm = { 1057 | imageMagick: true, 1058 | }; 1059 | config.debug = true; 1060 | }); 1061 | 1062 | it('should resize an animated gif', () => 1063 | expect('GET /animated.gif?resize=40,35', 'to yield response', { 1064 | headers: { 1065 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1066 | }, 1067 | body: expect.it('to have metadata satisfying', { 1068 | format: 'GIF', 1069 | // gifsicle does not enlarge to fill the bounding box 1070 | // https://github.com/kohler/gifsicle/issues/13#issuecomment-196321546 1071 | size: gifsicleAvailable 1072 | ? { width: 23, height: 20 } 1073 | : { width: 40, height: 35 }, 1074 | }), 1075 | })); 1076 | 1077 | it('should support the withoutEnlargement modfier', () => 1078 | expect( 1079 | 'GET /animated.gif?resize=40,35&withoutEnlargement', 1080 | 'to yield response', 1081 | { 1082 | headers: { 1083 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1084 | }, 1085 | body: expect.it('to have metadata satisfying', { 1086 | format: 'GIF', 1087 | // gifsicle does not enlarge to fill the bounding box 1088 | // https://github.com/kohler/gifsicle/issues/13#issuecomment-196321546 1089 | size: { width: 23, height: 20 }, 1090 | }), 1091 | } 1092 | )); 1093 | 1094 | it('should support the ignoreAspectRatio modfier', () => 1095 | expect( 1096 | 'GET /animated.gif?resize=100,100&ignoreAspectRatio', 1097 | 'to yield response', 1098 | { 1099 | headers: { 1100 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1101 | }, 1102 | body: expect.it('to have metadata satisfying', { 1103 | format: 'GIF', 1104 | size: { width: 100, height: 100 }, 1105 | }), 1106 | } 1107 | )); 1108 | 1109 | it('should support resize with crop', () => 1110 | expect( 1111 | 'GET /animated.gif?resize=40,35&crop=center', 1112 | 'to yield response', 1113 | { 1114 | headers: { 1115 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1116 | }, 1117 | body: expect.it('to have metadata satisfying', { 1118 | format: 'GIF', 1119 | // gifsicle does not support cropping to a specific gravity, 1120 | // so the parameter will be ignored: 1121 | size: gifsicleAvailable 1122 | ? { width: 23, height: 20 } 1123 | : { width: 40, height: 35 }, 1124 | }), 1125 | } 1126 | )); 1127 | 1128 | it('should resize a non-animated gif', () => 1129 | expect('GET /bulb.gif?resize=200,200', 'to yield response', { 1130 | headers: { 1131 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1132 | }, 1133 | body: expect.it('to have metadata satisfying', { 1134 | format: 'GIF', 1135 | size: gifsicleAvailable 1136 | ? { width: 48, height: 48 } 1137 | : { width: 200 }, 1138 | }), 1139 | })); 1140 | 1141 | it('should resize an animated gif with differently sized frames', () => 1142 | expect('GET /cat.gif?resize=200,200', 'to yield response', { 1143 | headers: { 1144 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1145 | }, 1146 | body: expect.it('to have metadata satisfying', { 1147 | format: 'GIF', 1148 | size: gifsicleAvailable 1149 | ? { width: 156, height: 200 } 1150 | : { width: 200 }, 1151 | }), 1152 | })); 1153 | 1154 | it('should support extract', () => 1155 | expect('GET /bulb.gif?extract=10,10,15,15', 'to yield response', { 1156 | headers: { 1157 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1158 | }, 1159 | body: expect 1160 | .it('to have metadata satisfying', { 1161 | format: 'GIF', 1162 | size: { 1163 | width: 15, 1164 | height: 15, 1165 | }, 1166 | }) 1167 | .and('to equal', load(`bulbCropped.${engineName}.gif`)), 1168 | })); 1169 | 1170 | itSkipMac('should support rotate with a single argument', () => 1171 | expect('GET /bulb.gif?rotate=90', 'to yield response', { 1172 | headers: { 1173 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1174 | }, 1175 | body: expect 1176 | .it('to have metadata satisfying', { 1177 | format: 'GIF', 1178 | size: { 1179 | width: 48, 1180 | height: 48, 1181 | }, 1182 | }) 1183 | .and('to equal', load(`bulbRotated.${engineName}.gif`)), 1184 | }) 1185 | ); 1186 | 1187 | itSkipMac('should support progressive (interlaced) GIF', () => 1188 | expect('GET /bulb.gif?rotate=90&progressive', 'to yield response', { 1189 | headers: { 1190 | 'X-Express-Processimage': gifsicleAvailable ? 'gifsicle' : 'gm', 1191 | }, 1192 | body: expect 1193 | .it('to have metadata satisfying', { 1194 | format: 'GIF', 1195 | size: { 1196 | width: 48, 1197 | height: 48, 1198 | }, 1199 | Interlace: 'Line', 1200 | }) 1201 | .and('to equal', load(`bulbInterlaced.${engineName}.gif`)), 1202 | }) 1203 | ); 1204 | 1205 | describe('when omitting the width', () => { 1206 | it('should do a proportional resize to the given height', () => 1207 | expect('GET /bulb.gif?resize=20,', 'to yield response', { 1208 | body: expect.it('to have metadata satisfying', { 1209 | size: { 1210 | width: 20, 1211 | height: 20, 1212 | }, 1213 | }), 1214 | })); 1215 | 1216 | describe('with a maxOutputPixels setting in place', () => { 1217 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 1218 | config.maxOutputPixels = 1000; 1219 | return expect('GET /bulb.gif?resize=40,', 'to yield response', { 1220 | body: expect.it('to have metadata satisfying', { 1221 | size: { 1222 | width: 25, 1223 | height: 25, 1224 | }, 1225 | }), 1226 | }); 1227 | }); 1228 | }); 1229 | }); 1230 | 1231 | describe('when omitting the height', () => { 1232 | it('should do a proportional resize to the given width', () => 1233 | expect('GET /bulb.gif?resize=,25', 'to yield response', { 1234 | body: expect.it('to have metadata satisfying', { 1235 | size: { 1236 | width: 25, 1237 | height: 25, 1238 | }, 1239 | }), 1240 | })); 1241 | 1242 | describe('with a maxOutputPixels setting in place', () => { 1243 | it('should limit the size of the bounding box based on the maxOutputPixels value', () => { 1244 | config.maxOutputPixels = 1000; 1245 | return expect('GET /bulb.gif?resize=,40', 'to yield response', { 1246 | body: expect.it('to have metadata satisfying', { 1247 | size: { 1248 | width: 25, 1249 | height: 25, 1250 | }, 1251 | }), 1252 | }); 1253 | }); 1254 | 1255 | it('should refuse to resize an image to exceed the max number of pixels', () => { 1256 | config.maxOutputPixels = 2; 1257 | return expect( 1258 | 'GET /bulb.gif?resize=100,100', 1259 | 'to yield response', 1260 | { 1261 | errorPassedToNext: expect.it('to satisfy', { 1262 | message: 1263 | 'resize: Target dimensions of 100x100 exceed maxOutputPixels (2)', 1264 | name: 'OutputDimensionsExceeded', 1265 | OutputDimensionsExceeded: true, 1266 | }), 1267 | } 1268 | ); 1269 | }); 1270 | }); 1271 | }); 1272 | }); 1273 | }); 1274 | }); 1275 | 1276 | it('should handle resize before extract', () => 1277 | expect( 1278 | 'GET /cat.gif?resize=380,486&extract=150,150,100,100', 1279 | 'to yield response', 1280 | { 1281 | body: expect 1282 | .it('to have metadata satisfying', { 1283 | size: { width: 100, height: 100 }, 1284 | Scene: ['0 of 4', '1 of 4', '2 of 4', '3 of 4'], // Animated 1285 | }) 1286 | .and('to equal', load('cat-resized-then-cropped.gif')), 1287 | } 1288 | )); 1289 | 1290 | describe('with invalid parameters', () => { 1291 | [ 1292 | 'resize=foo,100', 1293 | 'resize=', 1294 | 'resize=100,200,300', 1295 | 'resize=0,0', 1296 | 'resize=-1,-1', 1297 | 'resize=32000,32000', 1298 | 'crop=foo', 1299 | 'crop=', 1300 | 'crop=north,south', 1301 | 'extract=', 1302 | 'extract=1,2,3,4,5', 1303 | 'extract=32000,32000,32000,32000', 1304 | 'rotate=95', 1305 | 'rotate=90,270', 1306 | 'png=hey', 1307 | 'interpolateWith=something', 1308 | ].forEach((invalidOperation) => { 1309 | it(`disallows an operation of ${invalidOperation}`, () => 1310 | expect(`GET /testImage.png?${invalidOperation}`, 'to yield response', { 1311 | body: expect.it('to have metadata satisfying', { 1312 | size: { width: 12, height: 5 }, 1313 | }), 1314 | })); 1315 | }); 1316 | 1317 | it('should not break when there is only a "modifier" filter left after the invalid operations have been trimmed', () => 1318 | expect( 1319 | 'GET /bulb.gif?ignoreAspectRatio&resize=NaN,NaN', 1320 | 'to yield response', 1321 | { 1322 | statusCode: 200, 1323 | body: expect.it('to have metadata satisfying', { 1324 | format: 'GIF', 1325 | size: { width: 48, height: 48 }, 1326 | }), 1327 | } 1328 | )); 1329 | }); 1330 | 1331 | describe('against a real server', () => { 1332 | it('should destroy the created filters when the client closes the connection prematurely', async () => { 1333 | let resolveOnPipeline; 1334 | const onPipelinePromise = new Promise( 1335 | (resolve) => (resolveOnPipeline = resolve) 1336 | ); 1337 | const config = { 1338 | onPipeline: (p) => { 1339 | resolveOnPipeline(p); 1340 | }, 1341 | }; 1342 | 1343 | const server = express() 1344 | .use(processImage(config)) 1345 | .use(express.static(root)) 1346 | .listen(0); 1347 | const serverAddress = server.address(); 1348 | const serverHostname = 1349 | serverAddress.address === '::' ? 'localhost' : serverAddress.address; 1350 | const serverUrl = `http://${serverHostname}:${serverAddress.port}/testImage.png?progressive`; 1351 | const request = http.get(serverUrl); 1352 | request.end(); 1353 | 1354 | const spies = []; 1355 | 1356 | try { 1357 | const pipeline = await onPipelinePromise; 1358 | 1359 | spies.push(sinon.spy(pipeline._streams[0], 'unpipe')); 1360 | 1361 | setTimeout(() => { 1362 | request.abort(); 1363 | }, 0); 1364 | 1365 | await new Promise((resolve, reject) => { 1366 | request.once('error', (err) => { 1367 | try { 1368 | expect(err, 'to have message', 'socket hang up'); 1369 | resolve(); 1370 | } catch (e) { 1371 | reject(e); 1372 | } 1373 | }); 1374 | }); 1375 | 1376 | await new Promise((resolve) => setTimeout(resolve, 100)); 1377 | 1378 | expect(spies[0], 'was called once'); 1379 | } finally { 1380 | server.close(); 1381 | } 1382 | }); 1383 | }); 1384 | 1385 | describe('with secondGuessSourceContentType=true', () => { 1386 | beforeEach(() => { 1387 | config.secondGuessSourceContentType = true; 1388 | }); 1389 | 1390 | it('should recover gracefully when attempting to process a wrongly named webp', () => { 1391 | config.debug = true; 1392 | return expect('GET /reallyawebp.png?resize=40,30', 'to yield response', { 1393 | headers: { 1394 | 'X-Express-Processimage': 'sharp', 1395 | }, 1396 | body: expect.it('to have metadata satisfying', { 1397 | format: 'WEBP', 1398 | size: { width: 40, height: 30 }, 1399 | }), 1400 | }); 1401 | }); 1402 | 1403 | it('should return the correct contentType of a wrongly named ico', () => { 1404 | config.debug = true; 1405 | return expect('GET /reallyaico.gif?metadata', 'to yield response', { 1406 | body: { 1407 | format: expect.it('to equal', 'ico'), 1408 | contentType: expect.it('to equal', 'image/x-icon'), 1409 | }, 1410 | }); 1411 | }); 1412 | 1413 | it('should recover gracefully when attempting to process a wrongly named jpeg', () => { 1414 | config.debug = true; 1415 | return expect('GET /reallyajpeg.gif?resize=40,35', 'to yield response', { 1416 | headers: { 1417 | 'X-Express-Processimage': 'sharp', 1418 | }, 1419 | body: expect.it('to have metadata satisfying', { 1420 | format: 'JPEG', 1421 | size: { width: 40, height: 35 }, 1422 | }), 1423 | }); 1424 | }); 1425 | 1426 | it('should recover gracefully when attempting to process a wrongly named png', () => { 1427 | config.debug = true; 1428 | return expect('GET /reallyapng.gif?resize=40,35', 'to yield response', { 1429 | headers: { 1430 | 'X-Express-Processimage': 'sharp', 1431 | }, 1432 | body: expect.it('to have metadata satisfying', { 1433 | format: 'PNG', 1434 | size: { width: 40, height: 17 }, 1435 | }), 1436 | }); 1437 | }); 1438 | 1439 | it('should recover gracefully when attempting to process a wrongly named gif', () => { 1440 | config.debug = true; 1441 | return expect('GET /reallyagif.jpeg?resize=40,35', 'to yield response', { 1442 | headers: { 1443 | 'X-Express-Processimage': 'gifsicle', 1444 | }, 1445 | body: expect.it('to have metadata satisfying', { 1446 | format: 'GIF', 1447 | size: { width: 35, height: 35 }, 1448 | }), 1449 | }); 1450 | }); 1451 | 1452 | it('should recover gracefully when attempting to process a wrongly named bmp', () => { 1453 | config.debug = true; 1454 | return expect( 1455 | 'GET /reallyabmp.gif?gm&resize=40,35', 1456 | 'to yield response', 1457 | { 1458 | headers: { 1459 | 'X-Express-Processimage': 'gm', 1460 | }, 1461 | body: expect.it('to have metadata satisfying', { 1462 | format: 'BMP', 1463 | size: { width: 40, height: 25 }, 1464 | }), 1465 | } 1466 | ); 1467 | }); 1468 | }); 1469 | 1470 | it('should send an error response when an out-of-bounds extract operation is requested', () => { 1471 | const server = express() 1472 | .use(processImage(config)) 1473 | .use(express.static(root)) 1474 | .listen(0); 1475 | 1476 | const serverAddress = server.address(); 1477 | const serverHostname = 1478 | serverAddress.address === '::' ? 'localhost' : serverAddress.address; 1479 | const serverUrl = `http://${serverHostname}:${serverAddress.port}/`; 1480 | 1481 | return expect( 1482 | `${serverUrl}turtle.jpg?extract=100,100,800,10`, 1483 | 'to yield HTTP response satisfying', 1484 | { 1485 | body: /bad extract area/, 1486 | } 1487 | ).finally(() => { 1488 | server.close(); 1489 | }); 1490 | }); 1491 | 1492 | it('should discard If-None-Match tokens that do not have a -processimage suffix', () => 1493 | expect( 1494 | express() 1495 | .use(processImage(config)) 1496 | .use((req, res, next) => { 1497 | expect(req.headers['if-none-match'], 'to be falsy'); 1498 | res.end(); 1499 | }), 1500 | 'to yield exchange', 1501 | { 1502 | request: { 1503 | url: 'GET /turtle.jpg?resize=10,10', 1504 | headers: { 1505 | 'If-None-Match': '"foo"', 1506 | }, 1507 | }, 1508 | response: 200, 1509 | } 1510 | )); 1511 | 1512 | it('should strip the suffix from If-None-Match tokens that do have a -processimage suffix', () => 1513 | expect( 1514 | express() 1515 | .use(processImage(config)) 1516 | .use((req, res, next) => { 1517 | expect( 1518 | req.headers['if-none-match'], 1519 | 'to equal', 1520 | '"foo" "bar-somethingelse"' 1521 | ); 1522 | res.end(); 1523 | }), 1524 | 'to yield exchange', 1525 | { 1526 | request: { 1527 | url: 'GET /turtle.jpg?resize=10,10', 1528 | headers: { 1529 | 'If-None-Match': 1530 | '"foo-processimage" "bar-processimage-somethingelse"', 1531 | }, 1532 | }, 1533 | response: 200, 1534 | } 1535 | )); 1536 | 1537 | describe('with a allowedImageSourceContentTypes setting', () => { 1538 | it('should refuse to process a non-whitelisted image', () => { 1539 | config.allowedImageSourceContentTypes = ['image/png']; 1540 | return expect('GET /turtle.jpg?resize=100,100&png', 'to yield response', { 1541 | headers: { 1542 | 'Content-Type': 'image/jpeg', 1543 | }, 1544 | body: expect.it('to have metadata satisfying', { 1545 | size: { 1546 | width: 481, 1547 | height: 424, 1548 | }, 1549 | }), 1550 | }); 1551 | }); 1552 | }); 1553 | 1554 | it('should run resize .ico file with gm module by converting image from .ico to .png format', () => 1555 | expect('GET /favicon.ico?gm&png&resize=10,10', 'to yield response', { 1556 | statusCode: 200, 1557 | headers: { 1558 | 'Content-Type': 'image/png', 1559 | }, 1560 | body: expect.it('to have metadata satisfying', { 1561 | format: 'PNG', 1562 | size: { 1563 | width: 10, 1564 | height: 10, 1565 | }, 1566 | }), 1567 | })); 1568 | }); 1569 | -------------------------------------------------------------------------------- /testdata/Landscape_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/Landscape_8.jpg -------------------------------------------------------------------------------- /testdata/addBogusElement.js: -------------------------------------------------------------------------------- 1 | /* global svgFilter */ 2 | const g = document.createElement('g'); 3 | g.setAttribute('id', svgFilter.bogusElementId || 'blablaf'); 4 | document.documentElement.appendChild(g); 5 | -------------------------------------------------------------------------------- /testdata/ancillaryChunks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/ancillaryChunks.png -------------------------------------------------------------------------------- /testdata/animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/animated.gif -------------------------------------------------------------------------------- /testdata/bulb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulb.gif -------------------------------------------------------------------------------- /testdata/bulbCropped.gifsicle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbCropped.gifsicle.gif -------------------------------------------------------------------------------- /testdata/bulbCropped.im.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbCropped.im.gif -------------------------------------------------------------------------------- /testdata/bulbInterlaced.gifsicle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbInterlaced.gifsicle.gif -------------------------------------------------------------------------------- /testdata/bulbInterlaced.im.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbInterlaced.im.gif -------------------------------------------------------------------------------- /testdata/bulbRotated.gifsicle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbRotated.gifsicle.gif -------------------------------------------------------------------------------- /testdata/bulbRotated.im.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/bulbRotated.im.gif -------------------------------------------------------------------------------- /testdata/cat-resized-then-cropped.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/cat-resized-then-cropped.gif -------------------------------------------------------------------------------- /testdata/cat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/cat.gif -------------------------------------------------------------------------------- /testdata/certainlynotanimage.jpg: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /testdata/dialog-information.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | image/svg+xml 150 | 151 | Info 152 | 153 | 154 | Jakub Steiner 155 | 156 | 157 | 158 | 159 | dialog 160 | info 161 | 162 | 163 | http://jimmac.musichall.cz 164 | 165 | 166 | 167 | Garrett LeSage 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /testdata/empty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/empty.jpg -------------------------------------------------------------------------------- /testdata/exifOriented.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/exifOriented.jpg -------------------------------------------------------------------------------- /testdata/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/favicon.ico -------------------------------------------------------------------------------- /testdata/hugearea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/hugearea.png -------------------------------------------------------------------------------- /testdata/invalidImage.png: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /testdata/notajpeg.jpg: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /testdata/purplealpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/purplealpha24bit.png -------------------------------------------------------------------------------- /testdata/reallyabmp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyabmp.gif -------------------------------------------------------------------------------- /testdata/reallyagif.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyagif.jpeg -------------------------------------------------------------------------------- /testdata/reallyaico.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyaico.gif -------------------------------------------------------------------------------- /testdata/reallyajpeg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyajpeg.gif -------------------------------------------------------------------------------- /testdata/reallyapng.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyapng.gif -------------------------------------------------------------------------------- /testdata/reallyawebp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/reallyawebp.png -------------------------------------------------------------------------------- /testdata/rotatedBulb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/rotatedBulb.gif -------------------------------------------------------------------------------- /testdata/rotatedBulb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/rotatedBulb.png -------------------------------------------------------------------------------- /testdata/something.txt: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /testdata/testImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/testImage.png -------------------------------------------------------------------------------- /testdata/the-villa-facade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/the-villa-facade.png -------------------------------------------------------------------------------- /testdata/transparentbw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/transparentbw.gif -------------------------------------------------------------------------------- /testdata/turtle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtle.jpg -------------------------------------------------------------------------------- /testdata/turtleCropped300x200FromTopLeft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCropped300x200FromTopLeft.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedAttention100x200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedAttention100x200.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedCenter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedCenter.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedCenterGm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedCenterGm.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedEntropy100x200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedEntropy100x200.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedNorth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedNorth.jpg -------------------------------------------------------------------------------- /testdata/turtleCroppedNorthEastGm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleCroppedNorthEastGm.jpg -------------------------------------------------------------------------------- /testdata/turtleExtract.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papandreou/express-processimage/8b50a9dfc68c1aa77e7baae898b9f01b006dcffb/testdata/turtleExtract.jpg --------------------------------------------------------------------------------