diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..188bbcf --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +/browser.js +/test/imagediff.js diff --git a/.eslintrc.json b/.eslintrc.json index 8e4a18e..a66e018 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,182 +1,19 @@ { - "rules": { - "no-alert": "error", - "no-array-constructor": "off", - "no-bitwise": "off", - "no-caller": "error", - "no-catch-shadow": "error", - "no-class-assign": "error", - "no-cond-assign": "error", - "no-console": "error", - "no-const-assign": "error", - "no-constant-condition": "error", - "no-continue": "off", - "no-control-regex": "error", - "no-debugger": "error", - "no-delete-var": "error", - "no-div-regex": "off", - "no-dupe-keys": "error", - "no-dupe-args": "error", - "no-duplicate-case": "error", - "no-else-return": "error", - "no-empty": "error", - "no-empty-character-class": "error", - "no-eq-null": "off", - "no-eval": "error", - "no-ex-assign": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-boolean-cast": "error", - "no-extra-parens": "off", - "no-extra-semi": "error", - "no-fallthrough": "error", - "no-floating-decimal": "error", - "no-func-assign": "error", - "no-implicit-coercion": "error", - "no-implied-eval": "error", - "no-inline-comments": "off", - "no-inner-declarations": ["error", "functions"], - "no-invalid-regexp": "error", - "no-invalid-this": "error", - "no-irregular-whitespace": "error", - "no-iterator": "error", - "no-label-var": "error", - "no-labels": "error", - "no-lone-blocks": "error", - "no-lonely-if": "error", - "no-loop-func": "error", - "no-mixed-requires": ["error", false], - "no-mixed-spaces-and-tabs": ["error", false], - "linebreak-style": ["off", "unix"], - "no-multi-spaces": "error", - "no-multi-str": "off", - "no-multiple-empty-lines": ["error", {"max": 2}], - "no-native-reassign": "error", - "no-negated-in-lhs": "error", - "no-nested-ternary": "error", - "no-new": "error", - "no-new-func": "error", - "no-new-object": "error", - "no-new-require": "error", - "no-new-wrappers": "error", - "no-obj-calls": "error", - "no-octal": "error", - "no-octal-escape": "off", - "no-param-reassign": "off", - "no-path-concat": "off", - "no-plusplus": "off", - "no-process-env": "off", - "no-process-exit": "off", - "no-proto": "off", - "no-redeclare": "error", - "no-regex-spaces": "error", - "no-restricted-modules": "off", - "no-return-assign": "error", - "no-script-url": "off", - "no-self-compare": "error", - "no-sequences": "error", - "no-shadow": "error", - "no-shadow-restricted-names": "error", - "no-spaced-func": "error", - "no-sparse-arrays": "error", - "no-sync": "off", - "no-ternary": "off", - "no-trailing-spaces": "error", - "no-this-before-super": "error", - "no-throw-literal": "error", - "no-undef": "error", - "no-undef-init": "error", - "no-undefined": "off", - "no-unexpected-multiline": "error", - "no-underscore-dangle": "off", - "no-unneeded-ternary": "off", - "no-unreachable": "error", - "no-unused-expressions": "error", - "no-unused-vars": ["error", {"vars": "all", "args": "after-used"}], - "no-use-before-define": "error", - "no-useless-call": "error", - "no-void": "off", - "no-var": "off", - "no-warning-comments": ["error", { "terms": ["todo", "fixme", "xxx"], "location": "start" }], - "no-with": "error", - - "array-bracket-spacing": ["error", "never"], - "arrow-parens": "error", - "arrow-spacing": "error", - "accessor-pairs": "error", - "block-scoped-var": "off", - "brace-style": ["error", "stroustrup"], - "callback-return": ["error", ["callback", "cb", "next"]], - "camelcase": ["error", {"properties": "always"}], - "comma-dangle": ["error", "never"], - "comma-spacing": "error", - "comma-style": "error", - "complexity": "off", - "computed-property-spacing": ["off", "never"], - "consistent-return": "off", - "consistent-this": ["off", "that"], - "constructor-super": "error", - "curly": ["error", "all"], - "default-case": "error", - "dot-location": ["error", "property"], - "dot-notation": ["error", { "allowKeywords": true }], - "eol-last": "off", - "eqeqeq": ["error", "smart"], - "func-names": "off", - "func-style": ["off", "declaration"], - "generator-star-spacing": "off", - "guard-for-in": "error", - "handle-callback-err": "error", - "id-length": ["error", {"min": 3, "max": 25, "exceptions":["x", "y", "i", "j", "ex", "up"]}], - "indent": ["error", 2, {"SwitchCase": 1}], - "init-declarations": "off", - "key-spacing": ["error", { "beforeColon": false, "afterColon": true }], - "keyword-spacing": "error", - "lines-around-comment": "off", - "max-depth": ["error", 6], - "max-len": ["error", { "code": 160 }], - "max-nested-callbacks": ["error", 1], - "max-params": ["error", 6], - "max-statements": "off", - "new-cap": "error", - "new-parens": "error", - "newline-after-var": "off", - "object-curly-spacing": ["error", "always"], - "object-shorthand": "off", - "one-var": ["error", { - "initialized": "never" - }], - "operator-assignment": ["off", "always"], - "operator-linebreak": ["error", "after"], - "padded-blocks": "off", - "prefer-const": "off", - "prefer-spread": "off", - "prefer-reflect": "off", - "quote-props": "off", - "quotes": ["error", "single"], - "radix": "off", - "id-match": "off", - "require-yield": "off", - "semi": ["error", "always"], - "semi-spacing": ["error", {"before": false, "after": true}], - "sort-vars": "off", - "space-before-blocks": ["error", "always"], - "space-before-function-paren": ["error", "never"], - "space-in-parens": ["error", "never"], - "space-infix-ops": "error", - "space-unary-ops": ["error", { "words": true, "nonwords": false }], - "spaced-comment": "off", - "strict": ["error", "global"], - "use-isnan": "error", - "valid-jsdoc": "off", - "valid-typeof": "error", - "vars-on-top": "off", - "wrap-iife": "off", - "wrap-regex": "off", - "yoda": ["off", "never"] - }, - "env": { - "node": true, - "es6": true + "parserOptions": { "ecmaVersion": 2018 }, + "extends": ["eslint:recommended", "prettier"], + "env": { + "node": true, + "es6": true + }, + "rules": { + "no-var": "error" + }, + "overrides": [ + { + "files": ["test/*.js", "examples/*.js"], + "rules": { + "no-console": "off" + } } + ] } diff --git a/.gitignore b/.gitignore index 0158613..c423d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules coverage examples/*.png browser\.js +.nyc_output diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..188bbcf --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +/browser.js +/test/imagediff.js diff --git a/.travis.yml b/.travis.yml index c284d08..8becd6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: node_js after_success: - - if [ "$TRAVIS_NODE_VERSION" = "10" ]; then npm run coverage && npm i coveralls@2 && npm run coveralls; fi + - if [ "$TRAVIS_NODE_VERSION" = "10" ]; then yarn coverage && yarn coveralls; fi node_js: - - "8" - "10" - - "11" - "12" diff --git a/README.md b/README.md index 7f07bad..8f967d3 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,60 @@ [](https://travis-ci.org/lukeapage/pngjs) [](https://ci.appveyor.com/project/lukeapage/pngjs2/branch/master) [](https://coveralls.io/github/lukeapage/pngjs2?branch=master) [](http://badge.fury.io/js/pngjs) -pngjs -======== +# pngjs [](https://greenkeeper.io/) Simple PNG encoder/decoder for Node.js with no dependencies. Based on the original [pngjs](https://github.com/niegowski/node-pngjs) with the follow enhancements. - * Support for reading 1,2,4 & 16 bit files - * Support for reading interlace files - * Support for reading `tTRNS` transparent colours - * Support for writing colortype 0 (grayscale), colortype 2 (RGB), colortype 4 (grayscale alpha) and colortype 6 (RGBA) - * Sync interface as well as async - * API compatible with pngjs and node-pngjs +- Support for reading 1,2,4 & 16 bit files +- Support for reading interlace files +- Support for reading `tTRNS` transparent colours +- Support for writing colortype 0 (grayscale), colortype 2 (RGB), colortype 4 (grayscale alpha) and colortype 6 (RGBA) +- Sync interface as well as async +- API compatible with pngjs and node-pngjs Known lack of support for: - * Extended PNG e.g. Animation - * Writing in colortype 3 (indexed color) +- Extended PNG e.g. Animation +- Writing in colortype 3 (indexed color) # Table of Contents -* [Requirements](#requirements) -* [Comparison Table](#comparison-table) -* [Tests](#tests) -* [Installation](#installation) -* [Browser](#browser) -* [Example](#example) -* [Async API](#async-api) -* [Sync API](#sync-api) -* [Changelog](#changelog) -Requirements -============ +- [Requirements](#requirements) +- [Comparison Table](#comparison-table) +- [Tests](#tests) +- [Installation](#installation) +- [Browser](#browser) +- [Example](#example) +- [Async API](#async-api) +- [Sync API](#sync-api) +- [Changelog](#changelog) -* Node.js v4 (use older v2.3.0 for 0.10/0.12/iojs support) +# Requirements -Comparison Table -================ +- Node.js v4 (use older v2.3.0 for 0.10/0.12/iojs support) -Name | Forked From | Sync | Async | 16 Bit | 1/2/4 Bit | Interlace | Gamma | Encodes | Tested ----------|--------------|------|-------|--------|-----------|-----------|-------|---------|-------- -pngjs | | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes -node-png | pngjs | No | Yes | No | No | No | Hidden| Yes | Manual -png-coder| pngjs | No | Yes | Yes | No | No | Hidden| Yes | Manual -pngparse | | No | Yes | No | Yes | No | No | No | Yes -pngparse-sync | pngparse| Yes | No | No | Yes | No | No | No | Yes -png-async| | No | Yes | No | No | No | No | Yes | Yes -png-js | | No | Yes | No | No | No | No | No | No +# Comparison Table +| Name | Forked From | Sync | Async | 16 Bit | 1/2/4 Bit | Interlace | Gamma | Encodes | Tested | +| ------------- | ----------- | ---- | ----- | ------ | --------- | --------- | ------ | ------- | ------ | +| pngjs | | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +| node-png | pngjs | No | Yes | No | No | No | Hidden | Yes | Manual | +| png-coder | pngjs | No | Yes | Yes | No | No | Hidden | Yes | Manual | +| pngparse | | No | Yes | No | Yes | No | No | No | Yes | +| pngparse-sync | pngparse | Yes | No | No | Yes | No | No | No | Yes | +| png-async | | No | Yes | No | No | No | No | Yes | Yes | +| png-js | | No | Yes | No | No | No | No | No | No | Native C++ node decoders: - * png - * png-sync (sync version of above) - * pixel-png - * png-img -Tests -===== +- png +- png-sync (sync version of above) +- pixel-png +- png-img + +# Tests Tested using [PNG Suite](http://www.schaik.com/pngsuite/). We read every file into pngjs, output it in standard 8bit colour, synchronously and asynchronously, then compare the original with the newly saved images. @@ -67,65 +64,67 @@ The only thing not converted is gamma correction - this is because multiple vend In addition we use a tolerance of 3 for 16 bit images in PhantomJS because PhantomJS seems to have non-compliant rules for downscaling 16 bit images. -Installation -=============== +# Installation + ``` $ npm install pngjs --save ``` -Browser -=========== +# Browser + The package has been build with a [Browserify](browserify.org) version (`npm run browserify`) and you can use the browser version by including in your code: ``` import { PNG } from 'pngjs/browser'; ``` -Example -========== +# Example + ```js -var fs = require('fs'), - PNG = require('pngjs').PNG; +var fs = require("fs"), + PNG = require("pngjs").PNG; -fs.createReadStream('in.png') - .pipe(new PNG({ - filterType: 4 - })) - .on('parsed', function() { +fs.createReadStream("in.png") + .pipe( + new PNG({ + filterType: 4, + }) + ) + .on("parsed", function () { + for (var y = 0; y < this.height; y++) { + for (var x = 0; x < this.width; x++) { + var idx = (this.width * y + x) << 2; - for (var y = 0; y < this.height; y++) { - for (var x = 0; x < this.width; x++) { - var idx = (this.width * y + x) << 2; + // invert color + this.data[idx] = 255 - this.data[idx]; + this.data[idx + 1] = 255 - this.data[idx + 1]; + this.data[idx + 2] = 255 - this.data[idx + 2]; - // invert color - this.data[idx] = 255 - this.data[idx]; - this.data[idx+1] = 255 - this.data[idx+1]; - this.data[idx+2] = 255 - this.data[idx+2]; + // and reduce opacity + this.data[idx + 3] = this.data[idx + 3] >> 1; + } + } - // and reduce opacity - this.data[idx+3] = this.data[idx+3] >> 1; - } - } - - this.pack().pipe(fs.createWriteStream('out.png')); - }); + this.pack().pipe(fs.createWriteStream("out.png")); + }); ``` + For more examples see `examples` folder. -Async API -================ +# Async API As input any color type is accepted (grayscale, rgb, palette, grayscale with alpha, rgb with alpha) but 8 bit per sample (channel) is the only supported bit depth. Interlaced mode is not supported. ## Class: PNG + `PNG` is readable and writable `Stream`. - ### Options + - `width` - use this with `height` if you want to create png from scratch - `height` - as above - `checkCRC` - whether parser should be strict about checksums in source stream (default: `true`) -- `deflateChunkSize` - chunk size used for deflating data chunks, this should be power of 2 and must not be less than 256 and more than 32*1024 (default: 32 kB) +- `deflateChunkSize` - chunk size used for deflating data chunks, this should be power of 2 and must not be less than 256 and more than 32\*1024 (default: 32 kB) - `deflateLevel` - compression level for deflate (default: 9) - `deflateStrategy` - compression strategy for deflate (default: 3) - `deflateFactory` - deflate stream factory (default: `zlib.createDeflate`) @@ -133,15 +132,16 @@ As input any color type is accepted (grayscale, rgb, palette, grayscale with alp - `colorType` - the output colorType - see constants. 0 = grayscale, no alpha, 2 = color, no alpha, 4 = grayscale & alpha, 6 = color & alpha. Default currently 6, but in the future may calculate best mode. - `inputColorType` - the input colorType - see constants. Default is 6 (RGBA) - `bitDepth` - the bitDepth of the output, 8 or 16 bits. Input data is expected to have this bit depth. -16 bit data is expected in the system endianness (Default: 8) + 16 bit data is expected in the system endianness (Default: 8) - `inputHasAlpha` - whether the input bitmap has 4 bytes per pixel (rgb and alpha) or 3 (rgb - no alpha). - `bgColor` - an object containing red, green, and blue values between 0 and 255 -that is used when packing a PNG if alpha is not to be included (default: 255,255,255) - + that is used when packing a PNG if alpha is not to be included (default: 255,255,255) ### Event "metadata" + `function(metadata) { }` Image's header has been parsed, metadata contains this information: + - `width` image size in pixels - `height` image size in pixels - `palette` image is paletted @@ -149,17 +149,17 @@ Image's header has been parsed, metadata contains this information: - `alpha` image contains alpha channel - `interlace` image is interlaced - ### Event: "parsed" + `function(data) { }` Input image has been completely parsed, `data` is complete and ready for modification. - ### Event: "error" + `function(error) { }` - ### png.parse(data, [callback]) + Parses PNG file data. Can be `String` or `Buffer`. Alternatively you can stream data to instance of PNG. Optional `callback` is once called on `error` or `parsed`. The callback gets @@ -168,36 +168,39 @@ two arguments `(err, data)`. Returns `this` for method chaining. #### Example + ```js -new PNG({ filterType:4 }).parse( imageData, function(error, data) -{ - console.log(error, data) +new PNG({ filterType: 4 }).parse(imageData, function (error, data) { + console.log(error, data); }); ``` ### png.pack() + Starts converting data to PNG file Stream. Returns `this` for method chaining. - ### png.bitblt(dst, sx, sy, w, h, dx, dy) + Helper for image manipulation, copies a rectangle of pixels from current (i.e. the source) image (`sx`, `sy`, `w`, `h`) to `dst` image (at `dx`, `dy`). Returns `this` for method chaining. For example, the following code copies the top-left 100x50 px of `in.png` into dst and writes it to `out.png`: + ```js -var dst = new PNG({width: 100, height: 50}); -fs.createReadStream('in.png') - .pipe(new PNG()) - .on('parsed', function() { - this.bitblt(dst, 0, 0, 100, 50, 0, 0); - dst.pack().pipe(fs.createWriteStream('out.png')); - }); +var dst = new PNG({ width: 100, height: 50 }); +fs.createReadStream("in.png") + .pipe(new PNG()) + .on("parsed", function () { + this.bitblt(dst, 0, 0, 100, 50, 0, 0); + dst.pack().pipe(fs.createWriteStream("out.png")); + }); ``` ### Property: adjustGamma() + Helper that takes data and adjusts it to be gamma corrected. Note that it is not 100% reliable with transparent colours because that requires knowing the background colour the bitmap is rendered on to. In tests against PNG suite it compared 100% with chrome on all 8 bit and below images. On IE there were some differences. @@ -205,27 +208,28 @@ In tests against PNG suite it compared 100% with chrome on all 8 bit and below i The following example reads a file, adjusts the gamma (which sets the gamma to 0) and writes it out again, effectively removing any gamma correction from the image. ```js -fs.createReadStream('in.png') - .pipe(new PNG()) - .on('parsed', function() { - this.adjustGamma(); - this.pack().pipe(fs.createWriteStream('out.png')); - }); +fs.createReadStream("in.png") + .pipe(new PNG()) + .on("parsed", function () { + this.adjustGamma(); + this.pack().pipe(fs.createWriteStream("out.png")); + }); ``` ### Property: width + Width of image in pixels - ### Property: height + Height of image in pixels - ### Property: data + Buffer of image pixel data. Every pixel consists 4 bytes: R, G, B, A (opacity). - ### Property: gamma + Gamma of image (0 if not specified) ## Packing a PNG and removing alpha (RGBA to RGB) @@ -235,21 +239,23 @@ convert each pixel's transparency to the appropriate RGB value. By default, pngj the image against a white background. You can override this in the options: ```js -var fs = require('fs'), - PNG = require('pngjs').PNG; +var fs = require("fs"), + PNG = require("pngjs").PNG; -fs.createReadStream('in.png') - .pipe(new PNG({ - colorType: 2, - bgColor: { - red: 0, - green: 255, - blue: 0 - } - })) - .on('parsed', function() { - this.pack().pipe(fs.createWriteStream('out.png')); - }); +fs.createReadStream("in.png") + .pipe( + new PNG({ + colorType: 2, + bgColor: { + red: 0, + green: 255, + blue: 0, + }, + }) + ) + .on("parsed", function () { + this.pack().pipe(fs.createWriteStream("out.png")); + }); ``` # Sync API @@ -287,9 +293,7 @@ var png = PNG.sync.read(data); PNG.adjustGamma(png); ``` - -Changelog -============ +# Changelog ### 4.0.0 - 09/04/2020 @@ -325,62 +329,76 @@ Changelog - Support for encoding 8-bit grayscale images ### 3.1.0 - 30/04/2017 - - Support for pngs with zlib chunks that are malformed after valid data + +- Support for pngs with zlib chunks that are malformed after valid data ### 3.0.1 - 16/02/2017 - - Fix single pixel pngs + +- Fix single pixel pngs ### 3.0.0 - 03/08/2016 - - Drop support for node below v4 and iojs. Pin to 2.3.0 to use with old, unsupported or patched node versions. + +- Drop support for node below v4 and iojs. Pin to 2.3.0 to use with old, unsupported or patched node versions. ### 2.3.0 - 22/04/2016 - - Support for sync in node 0.10 + +- Support for sync in node 0.10 ### 2.2.0 - 04/12/2015 - - Add sync write api - - Fix newfile example - - Correct comparison table + +- Add sync write api +- Fix newfile example +- Correct comparison table ### 2.1.0 - 28/10/2015 - - rename package to pngjs - - added 'bgColor' option + +- rename package to pngjs +- added 'bgColor' option ### 2.0.0 - 08/10/2015 - - fixes to readme - - *breaking change* - bitblt on the png prototype now doesn't take a unused, unnecessary src first argument + +- fixes to readme +- _breaking change_ - bitblt on the png prototype now doesn't take a unused, unnecessary src first argument ### 1.2.0 - 13/09/2015 - - support passing colorType to write PNG's and writing bitmaps without alpha information + +- support passing colorType to write PNG's and writing bitmaps without alpha information ### 1.1.0 - 07/09/2015 - - support passing a deflate factory for controlled compression + +- support passing a deflate factory for controlled compression ### 1.0.2 - 22/08/2015 - - Expose all PNG creation info + +- Expose all PNG creation info ### 1.0.1 - 21/08/2015 - - Fix non square interlaced files + +- Fix non square interlaced files ### 1.0.0 - 08/08/2015 - - More tests - - source linted - - maintainability refactorings - - async API - exceptions in reading now emit warnings - - documentation improvement - sync api now documented, adjustGamma documented - - breaking change - gamma chunk is now written. previously a read then write would destroy gamma information, now it is persisted. + +- More tests +- source linted +- maintainability refactorings +- async API - exceptions in reading now emit warnings +- documentation improvement - sync api now documented, adjustGamma documented +- breaking change - gamma chunk is now written. previously a read then write would destroy gamma information, now it is persisted. ### 0.0.3 - 03/08/2015 - - Error handling fixes - - ignore files for smaller npm footprint + +- Error handling fixes +- ignore files for smaller npm footprint ### 0.0.2 - 02/08/2015 - - Bugfixes to interlacing, support for transparent colours + +- Bugfixes to interlacing, support for transparent colours ### 0.0.1 - 02/08/2015 - - Initial release, see pngjs for older changelog. -License -========= +- Initial release, see pngjs for older changelog. + +# License (The MIT License) diff --git a/appveyor.yml b/appveyor.yml index 5941cb6..b395160 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,8 +4,8 @@ clone_depth: 10 environment: matrix: - - nodejs_version: '4' - - nodejs_version: '6' + - nodejs_version: "10" + - nodejs_version: "12" install: - ps: Install-Product node $env:nodejs_version @@ -18,7 +18,7 @@ test_script: - npm test cache: - - node_modules # local npm modules + - node_modules # local npm modules matrix: fast_finish: true diff --git a/examples/16bit_write.js b/examples/16bit_write.js index 801d795..f36e671 100644 --- a/examples/16bit_write.js +++ b/examples/16bit_write.js @@ -1,51 +1,50 @@ #!/usr/bin/env node -var fs = require('fs'); -var PNG = require("../lib/png").PNG; -var w = 32; -var h = 64; +let fs = require("fs"); +let PNG = require("../lib/png").PNG; +let w = 32; +let h = 64; /// RGBA input (color type 6) -var buffer = Buffer.alloc(2 * w * h * 4); -var bitmap = new Uint16Array(buffer.buffer); -for (var i = 0; i < h; i++) { - for (var j = 0; j < w; j++) { - bitmap[i * 4 * w + 4*j] = i * 65535 / h; - bitmap[i * 4 * w + 4*j + 1] = j * 65535 / w; - bitmap[i * 4 * w + 4*j + 2] = (h-i) * 65535 / h; - bitmap[i * 4 * w + 4*j + 3] = 65535; +let buffer = Buffer.alloc(2 * w * h * 4); +let bitmap = new Uint16Array(buffer.buffer); +for (let i = 0; i < h; i++) { + for (let j = 0; j < w; j++) { + bitmap[i * 4 * w + 4 * j] = (i * 65535) / h; + bitmap[i * 4 * w + 4 * j + 1] = (j * 65535) / w; + bitmap[i * 4 * w + 4 * j + 2] = ((h - i) * 65535) / h; + bitmap[i * 4 * w + 4 * j + 3] = 65535; } } -var png = new PNG({ +let png = new PNG({ width: w, - height:h, + height: h, bitDepth: 16, colorType: 6, inputColorType: 6, - inputHasAlpha: true + inputHasAlpha: true, }); png.data = buffer; -png.pack().pipe(fs.createWriteStream('colortype6.png')); +png.pack().pipe(fs.createWriteStream("colortype6.png")); //////// Grayscale 16 bits/////// -var buffer = Buffer.alloc(2 * w * h); -var bitmap = new Uint16Array(buffer.buffer); -for (var i = 0; i < h; i++) { - for (var j = 0; j < w; j++) - bitmap[i * w + j] = i * 65535 / h; +buffer = Buffer.alloc(2 * w * h); +bitmap = new Uint16Array(buffer.buffer); +for (let i = 0; i < h; i++) { + for (let j = 0; j < w; j++) bitmap[i * w + j] = (i * 65535) / h; } png = new PNG({ width: w, - height:h, + height: h, bitDepth: 16, colorType: 0, inputColorType: 0, - inputHasAlpha: false + inputHasAlpha: false, }); png.data = buffer; -png.pack().pipe(fs.createWriteStream('colortype0.png')); \ No newline at end of file +png.pack().pipe(fs.createWriteStream("colortype0.png")); diff --git a/examples/fromdocs.js b/examples/fromdocs.js index fd6ce71..edf9d57 100644 --- a/examples/fromdocs.js +++ b/examples/fromdocs.js @@ -1,25 +1,22 @@ +let fs = require("fs"), + PNG = require("../lib/png").PNG; // note require('pngjs') outside this project -var fs = require('fs'), - PNG = require('../lib/png').PNG; // note require('pngjs') outside this project +fs.createReadStream("test/in/basi0g01.png") + .pipe(new PNG({})) + .on("parsed", function () { + for (let y = 0; y < this.height; y++) { + for (let x = 0; x < this.width; x++) { + let idx = (this.width * y + x) << 2; -fs.createReadStream('test/in/basi0g01.png') - .pipe(new PNG({ - })) - .on('parsed', function() { + // invert color + this.data[idx] = 255 - this.data[idx]; + this.data[idx + 1] = 255 - this.data[idx + 1]; + this.data[idx + 2] = 255 - this.data[idx + 2]; - for (var y = 0; y < this.height; y++) { - for (var x = 0; x < this.width; x++) { - var idx = (this.width * y + x) << 2; + // and reduce opacity + this.data[idx + 3] = this.data[idx + 3] >> 1; + } + } - // invert color - this.data[idx] = 255 - this.data[idx]; - this.data[idx+1] = 255 - this.data[idx+1]; - this.data[idx+2] = 255 - this.data[idx+2]; - - // and reduce opacity - this.data[idx+3] = this.data[idx+3] >> 1; - } - } - - this.pack().pipe(fs.createWriteStream('out.png')); - }); + this.pack().pipe(fs.createWriteStream("out.png")); + }); diff --git a/examples/newfile.js b/examples/newfile.js index d7725fc..5c4f3ed 100644 --- a/examples/newfile.js +++ b/examples/newfile.js @@ -1,13 +1,14 @@ -var PNG = require("../lib/png").PNG; -var fs = require("fs"); +let PNG = require("../lib/png").PNG; +let fs = require("fs"); -var newfile = new PNG({width:10,height:10}); +let newfile = new PNG({ width: 10, height: 10 }); -for (var y = 0; y < newfile.height; y++) { - for (var x = 0; x < newfile.width; x++) { - var idx = (newfile.width * y + x) << 2; +for (let y = 0; y < newfile.height; y++) { + for (let x = 0; x < newfile.width; x++) { + let idx = (newfile.width * y + x) << 2; - var col = x < (newfile.width >> 1) ^ y < (newfile.height >> 1) ? 0xe5 : 0xff; + let col = + (x < newfile.width >> 1) ^ (y < newfile.height >> 1) ? 0xe5 : 0xff; newfile.data[idx] = col; newfile.data[idx + 1] = col; @@ -16,8 +17,9 @@ for (var y = 0; y < newfile.height; y++) { } } -newfile.pack() - .pipe(fs.createWriteStream(__dirname + '/newfile.png')) - .on('finish', function() { - console.log('Written!'); +newfile + .pack() + .pipe(fs.createWriteStream(__dirname + "/newfile.png")) + .on("finish", function () { + console.log("Written!"); }); diff --git a/examples/set-colortype.js b/examples/set-colortype.js index ae9b3f6..1db1a08 100644 --- a/examples/set-colortype.js +++ b/examples/set-colortype.js @@ -1,34 +1,34 @@ -var fs = require('fs'); -var PNG = require("../lib/png").PNG; -var w = 320; -var h = 200; +let fs = require("fs"); +let PNG = require("../lib/png").PNG; +let w = 320; +let h = 200; -var bitmapWithoutAlpha = Buffer.alloc(w * h * 3); -var ofs=0; -for (var i = 0; i < bitmapWithoutAlpha.length; i+=3) { - bitmapWithoutAlpha[ofs++] = 0xff; - bitmapWithoutAlpha[ofs++] = i % 0xff; - bitmapWithoutAlpha[ofs++] = (i/3) % 0xff; +let bitmapWithoutAlpha = Buffer.alloc(w * h * 3); +let ofs = 0; +for (let i = 0; i < bitmapWithoutAlpha.length; i += 3) { + bitmapWithoutAlpha[ofs++] = 0xff; + bitmapWithoutAlpha[ofs++] = i % 0xff; + bitmapWithoutAlpha[ofs++] = (i / 3) % 0xff; } -var png = new PNG({ +let png = new PNG({ width: w, - height:h, + height: h, bitDepth: 8, colorType: 2, - inputHasAlpha: false + inputHasAlpha: false, }); png.data = bitmapWithoutAlpha; -png.pack().pipe(fs.createWriteStream('colortype2.png')); +png.pack().pipe(fs.createWriteStream("colortype2.png")); -var png = new PNG({ +png = new PNG({ width: w, - height:h, + height: h, bitDepth: 8, colorType: 6, - inputHasAlpha: false + inputHasAlpha: false, }); png.data = bitmapWithoutAlpha; -png.pack().pipe(fs.createWriteStream('colortype6.png')); \ No newline at end of file +png.pack().pipe(fs.createWriteStream("colortype6.png")); diff --git a/examples/simple.js b/examples/simple.js index 9edaab6..e1f9d42 100755 --- a/examples/simple.js +++ b/examples/simple.js @@ -1,30 +1,28 @@ #!/usr/bin/env node -var fs = require('fs'), - PNG = require('../lib/png').PNG; +let fs = require("fs"), + PNG = require("../lib/png").PNG; +let png = new PNG({ + filterType: -1, + }), + src = fs.createReadStream(process.argv[2]), + dst = fs.createWriteStream(process.argv[3] || "out.png"); -var png = new PNG({ - filterType: -1 - }), - src = fs.createReadStream(process.argv[2]), - dst = fs.createWriteStream(process.argv[3] || 'out.png'); +png.on("parsed", function () { + for (let y = 0; y < png.height; y++) { + for (let x = 0; x < png.width; x++) { + let idx = (png.width * y + x) << 2; - -png.on('parsed', function() { - - for (var y = 0; y < png.height; y++) { - for (var x = 0; x < png.width; x++) { - var idx = (png.width * y + x) << 2; - - if (Math.abs(png.data[idx] - png.data[idx+1]) <= 1 - && Math.abs(png.data[idx+1] - png.data[idx+2]) <= 1) - png.data[idx] = png.data[idx+1] = png.data[idx+2]; - - } + if ( + Math.abs(png.data[idx] - png.data[idx + 1]) <= 1 && + Math.abs(png.data[idx + 1] - png.data[idx + 2]) <= 1 + ) + png.data[idx] = png.data[idx + 1] = png.data[idx + 2]; } + } - png.pack().pipe(dst); + png.pack().pipe(dst); }); src.pipe(png); diff --git a/examples/sync.js b/examples/sync.js index 98b964c..ab90e70 100644 --- a/examples/sync.js +++ b/examples/sync.js @@ -1,19 +1,18 @@ #!/usr/bin/env node -var fs = require('fs'), - PNG = require('../lib/png').PNG; +let fs = require("fs"), + PNG = require("../lib/png").PNG; - -var srcFname = process.argv[2], - dstFname = process.argv[3] || 'out.png'; +let srcFname = process.argv[2], + dstFname = process.argv[3] || "out.png"; // Read a PNG file -var data = fs.readFileSync(srcFname); +let data = fs.readFileSync(srcFname); // Parse it -var png = PNG.sync.read(data, { - filterType: -1 +let png = PNG.sync.read(data, { + filterType: -1, }); // Pack it back into a PNG data -var buff = PNG.sync.write(png); +let buff = PNG.sync.write(png); // Write a PNG file -fs.writeFileSync(dstFname, buff); \ No newline at end of file +fs.writeFileSync(dstFname, buff); diff --git a/lib/bitmapper.js b/lib/bitmapper.js index f236406..18378a0 100644 --- a/lib/bitmapper.js +++ b/lib/bitmapper.js @@ -1,19 +1,19 @@ -'use strict'; +"use strict"; -var interlaceUtils = require('./interlace'); +let interlaceUtils = require("./interlace"); -var pixelBppMapper = [ +let pixelBppMapper = [ // 0 - dummy entry - function() {}, + function () {}, // 1 - L // 0: 0, 1: 0, 2: 0, 3: 0xff - function(pxData, data, pxPos, rawPos) { + function (pxData, data, pxPos, rawPos) { if (rawPos === data.length) { - throw new Error('Ran out of data'); + throw new Error("Ran out of data"); } - var pixel = data[rawPos]; + let pixel = data[rawPos]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; @@ -22,12 +22,12 @@ var pixelBppMapper = [ // 2 - LA // 0: 0, 1: 0, 2: 0, 3: 1 - function(pxData, data, pxPos, rawPos) { + function (pxData, data, pxPos, rawPos) { if (rawPos + 1 >= data.length) { - throw new Error('Ran out of data'); + throw new Error("Ran out of data"); } - var pixel = data[rawPos]; + let pixel = data[rawPos]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; @@ -36,9 +36,9 @@ var pixelBppMapper = [ // 3 - RGB // 0: 0, 1: 1, 2: 2, 3: 0xff - function(pxData, data, pxPos, rawPos) { + function (pxData, data, pxPos, rawPos) { if (rawPos + 2 >= data.length) { - throw new Error('Ran out of data'); + throw new Error("Ran out of data"); } pxData[pxPos] = data[rawPos]; @@ -49,26 +49,26 @@ var pixelBppMapper = [ // 4 - RGBA // 0: 0, 1: 1, 2: 2, 3: 3 - function(pxData, data, pxPos, rawPos) { + function (pxData, data, pxPos, rawPos) { if (rawPos + 3 >= data.length) { - throw new Error('Ran out of data'); + throw new Error("Ran out of data"); } pxData[pxPos] = data[rawPos]; pxData[pxPos + 1] = data[rawPos + 1]; pxData[pxPos + 2] = data[rawPos + 2]; pxData[pxPos + 3] = data[rawPos + 3]; - } + }, ]; -var pixelBppCustomMapper = [ +let pixelBppCustomMapper = [ // 0 - dummy entry - function() {}, + function () {}, // 1 - L // 0: 0, 1: 0, 2: 0, 3: 0xff - function(pxData, pixelData, pxPos, maxBit) { - var pixel = pixelData[0]; + function (pxData, pixelData, pxPos, maxBit) { + let pixel = pixelData[0]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; @@ -77,8 +77,8 @@ var pixelBppCustomMapper = [ // 2 - LA // 0: 0, 1: 0, 2: 0, 3: 1 - function(pxData, pixelData, pxPos) { - var pixel = pixelData[0]; + function (pxData, pixelData, pxPos) { + let pixel = pixelData[0]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; @@ -87,7 +87,7 @@ var pixelBppCustomMapper = [ // 3 - RGB // 0: 0, 1: 1, 2: 2, 3: 0xff - function(pxData, pixelData, pxPos, maxBit) { + function (pxData, pixelData, pxPos, maxBit) { pxData[pxPos] = pixelData[0]; pxData[pxPos + 1] = pixelData[1]; pxData[pxPos + 2] = pixelData[2]; @@ -96,33 +96,32 @@ var pixelBppCustomMapper = [ // 4 - RGBA // 0: 0, 1: 1, 2: 2, 3: 3 - function(pxData, pixelData, pxPos) { + function (pxData, pixelData, pxPos) { pxData[pxPos] = pixelData[0]; pxData[pxPos + 1] = pixelData[1]; pxData[pxPos + 2] = pixelData[2]; pxData[pxPos + 3] = pixelData[3]; - } + }, ]; function bitRetriever(data, depth) { - - var leftOver = []; - var i = 0; + let leftOver = []; + let i = 0; function split() { if (i === data.length) { - throw new Error('Ran out of data'); + throw new Error("Ran out of data"); } - var byte = data[i]; + let byte = data[i]; i++; - var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1; + let byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1; switch (depth) { default: - throw new Error('unrecognised depth'); + throw new Error("unrecognised depth"); case 16: byte2 = data[i]; i++; - leftOver.push(((byte << 8) + byte2)); + leftOver.push((byte << 8) + byte2); break; case 4: byte2 = byte & 0x0f; @@ -131,52 +130,53 @@ function bitRetriever(data, depth) { break; case 2: byte4 = byte & 3; - byte3 = byte >> 2 & 3; - byte2 = byte >> 4 & 3; - byte1 = byte >> 6 & 3; + byte3 = (byte >> 2) & 3; + byte2 = (byte >> 4) & 3; + byte1 = (byte >> 6) & 3; leftOver.push(byte1, byte2, byte3, byte4); break; case 1: byte8 = byte & 1; - byte7 = byte >> 1 & 1; - byte6 = byte >> 2 & 1; - byte5 = byte >> 3 & 1; - byte4 = byte >> 4 & 1; - byte3 = byte >> 5 & 1; - byte2 = byte >> 6 & 1; - byte1 = byte >> 7 & 1; + byte7 = (byte >> 1) & 1; + byte6 = (byte >> 2) & 1; + byte5 = (byte >> 3) & 1; + byte4 = (byte >> 4) & 1; + byte3 = (byte >> 5) & 1; + byte2 = (byte >> 6) & 1; + byte1 = (byte >> 7) & 1; leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8); break; } } return { - get: function(count) { + get: function (count) { while (leftOver.length < count) { split(); } - var returner = leftOver.slice(0, count); + let returner = leftOver.slice(0, count); leftOver = leftOver.slice(count); return returner; }, - resetAfterLine: function() { + resetAfterLine: function () { leftOver.length = 0; }, - end: function() { + end: function () { if (i !== data.length) { - throw new Error('extra data found'); + throw new Error("extra data found"); } - } + }, }; } -function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-disable-line max-params - var imageWidth = image.width; - var imageHeight = image.height; - var imagePass = image.index; - for (var y = 0; y < imageHeight; y++) { - for (var x = 0; x < imageWidth; x++) { - var pxPos = getPxPos(x, y, imagePass); +function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { + // eslint-disable-line max-params + let imageWidth = image.width; + let imageHeight = image.height; + let imagePass = image.index; + for (let y = 0; y < imageHeight; y++) { + for (let x = 0; x < imageWidth; x++) { + let pxPos = getPxPos(x, y, imagePass); pixelBppMapper[bpp](pxData, data, pxPos, rawPos); rawPos += bpp; //eslint-disable-line no-param-reassign } @@ -184,71 +184,82 @@ function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-di return rawPos; } -function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { // eslint-disable-line max-params - var imageWidth = image.width; - var imageHeight = image.height; - var imagePass = image.index; - for (var y = 0; y < imageHeight; y++) { - for (var x = 0; x < imageWidth; x++) { - var pixelData = bits.get(bpp); - var pxPos = getPxPos(x, y, imagePass); +function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { + // eslint-disable-line max-params + let imageWidth = image.width; + let imageHeight = image.height; + let imagePass = image.index; + for (let y = 0; y < imageHeight; y++) { + for (let x = 0; x < imageWidth; x++) { + let pixelData = bits.get(bpp); + let pxPos = getPxPos(x, y, imagePass); pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit); } bits.resetAfterLine(); } } -exports.dataToBitMap = function(data, bitmapInfo) { - - var width = bitmapInfo.width; - var height = bitmapInfo.height; - var depth = bitmapInfo.depth; - var bpp = bitmapInfo.bpp; - var interlace = bitmapInfo.interlace; +exports.dataToBitMap = function (data, bitmapInfo) { + let width = bitmapInfo.width; + let height = bitmapInfo.height; + let depth = bitmapInfo.depth; + let bpp = bitmapInfo.bpp; + let interlace = bitmapInfo.interlace; + let bits; if (depth !== 8) { - var bits = bitRetriever(data, depth); + bits = bitRetriever(data, depth); } - var pxData; + let pxData; if (depth <= 8) { pxData = Buffer.alloc(width * height * 4); - } - else { + } else { pxData = new Uint16Array(width * height * 4); } - var maxBit = Math.pow(2, depth) - 1; - var rawPos = 0; - var images; - var getPxPos; + let maxBit = Math.pow(2, depth) - 1; + let rawPos = 0; + let images; + let getPxPos; if (interlace) { images = interlaceUtils.getImagePasses(width, height); getPxPos = interlaceUtils.getInterlaceIterator(width, height); - } - else { - var nonInterlacedPxPos = 0; - getPxPos = function() { - var returner = nonInterlacedPxPos; + } else { + let nonInterlacedPxPos = 0; + getPxPos = function () { + let returner = nonInterlacedPxPos; nonInterlacedPxPos += 4; return returner; }; images = [{ width: width, height: height }]; } - for (var imageIndex = 0; imageIndex < images.length; imageIndex++) { + for (let imageIndex = 0; imageIndex < images.length; imageIndex++) { if (depth === 8) { - rawPos = mapImage8Bit(images[imageIndex], pxData, getPxPos, bpp, data, rawPos); - } - else { - mapImageCustomBit(images[imageIndex], pxData, getPxPos, bpp, bits, maxBit); + rawPos = mapImage8Bit( + images[imageIndex], + pxData, + getPxPos, + bpp, + data, + rawPos + ); + } else { + mapImageCustomBit( + images[imageIndex], + pxData, + getPxPos, + bpp, + bits, + maxBit + ); } } if (depth === 8) { if (rawPos !== data.length) { - throw new Error('extra data found'); + throw new Error("extra data found"); } - } - else { + } else { bits.end(); } diff --git a/lib/bitpacker.js b/lib/bitpacker.js index fd75f1a..d7a4e65 100644 --- a/lib/bitpacker.js +++ b/lib/bitpacker.js @@ -1,12 +1,15 @@ -'use strict'; +"use strict"; -var constants = require('./constants'); +let constants = require("./constants"); -module.exports = function(dataIn, width, height, options) { - var outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(options.colorType) !== -1; +module.exports = function (dataIn, width, height, options) { + let outHasAlpha = + [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf( + options.colorType + ) !== -1; if (options.colorType === options.inputColorType) { - var bigEndian = (function() { - var buffer = new ArrayBuffer(2); + let bigEndian = (function () { + let buffer = new ArrayBuffer(2); new DataView(buffer).setInt16(0, 256, true /* littleEndian */); // Int16Array uses the platform's endianness. return new Int16Array(buffer)[0] !== 256; @@ -18,24 +21,24 @@ module.exports = function(dataIn, width, height, options) { } // map to a UInt16 array if data is 16bit, fix endianness below - var data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer); + let data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer); - var maxValue = 255; - var inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType]; + let maxValue = 255; + let inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType]; if (inBpp === 4 && !options.inputHasAlpha) { inBpp = 3; } - var outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType]; + let outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType]; if (options.bitDepth === 16) { maxValue = 65535; outBpp *= 2; } - var outData = Buffer.alloc(width * height * outBpp); + let outData = Buffer.alloc(width * height * outBpp); - var inIndex = 0; - var outIndex = 0; + let inIndex = 0; + let outIndex = 0; - var bgColor = options.bgColor || {}; + let bgColor = options.bgColor || {}; if (bgColor.red === undefined) { bgColor.red = maxValue; } @@ -47,10 +50,10 @@ module.exports = function(dataIn, width, height, options) { } function getRGBA() { - var red; - var green; - var blue; - var alpha = maxValue; + let red; + let green; + let blue; + let alpha = maxValue; switch (options.inputColorType) { case constants.COLORTYPE_COLOR_ALPHA: alpha = data[inIndex + 3]; @@ -75,23 +78,36 @@ module.exports = function(dataIn, width, height, options) { blue = red; break; default: - throw new Error('input color type:' + options.inputColorType + ' is not supported at present'); + throw new Error( + "input color type:" + + options.inputColorType + + " is not supported at present" + ); } if (options.inputHasAlpha) { if (!outHasAlpha) { alpha /= maxValue; - red = Math.min(Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0), maxValue); - green = Math.min(Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0), maxValue); - blue = Math.min(Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0), maxValue); + red = Math.min( + Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0), + maxValue + ); + green = Math.min( + Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0), + maxValue + ); + blue = Math.min( + Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0), + maxValue + ); } } return { red: red, green: green, blue: blue, alpha: alpha }; } - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var rgba = getRGBA(data, inIndex); + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + let rgba = getRGBA(data, inIndex); switch (options.colorType) { case constants.COLORTYPE_COLOR_ALPHA: @@ -103,8 +119,7 @@ module.exports = function(dataIn, width, height, options) { if (outHasAlpha) { outData[outIndex + 3] = rgba.alpha; } - } - else { + } else { outData.writeUInt16BE(rgba.red, outIndex); outData.writeUInt16BE(rgba.green, outIndex + 2); outData.writeUInt16BE(rgba.blue, outIndex + 4); @@ -114,24 +129,24 @@ module.exports = function(dataIn, width, height, options) { } break; case constants.COLORTYPE_ALPHA: - case constants.COLORTYPE_GRAYSCALE: + case constants.COLORTYPE_GRAYSCALE: { // Convert to grayscale and alpha - var grayscale = (rgba.red + rgba.green + rgba.blue) / 3; + let grayscale = (rgba.red + rgba.green + rgba.blue) / 3; if (options.bitDepth === 8) { outData[outIndex] = grayscale; if (outHasAlpha) { outData[outIndex + 1] = rgba.alpha; } - } - else { + } else { outData.writeUInt16BE(grayscale, outIndex); if (outHasAlpha) { outData.writeUInt16BE(rgba.alpha, outIndex + 2); } } break; + } default: - throw new Error('unrecognised color Type ' + options.colorType); + throw new Error("unrecognised color Type " + options.colorType); } inIndex += inBpp; diff --git a/lib/chunkstream.js b/lib/chunkstream.js index 56c4681..71c8ce0 100644 --- a/lib/chunkstream.js +++ b/lib/chunkstream.js @@ -1,11 +1,9 @@ -'use strict'; +"use strict"; +let util = require("util"); +let Stream = require("stream"); -var util = require('util'); -var Stream = require('stream'); - - -var ChunkStream = module.exports = function() { +let ChunkStream = (module.exports = function () { Stream.call(this); this._buffers = []; @@ -14,44 +12,42 @@ var ChunkStream = module.exports = function() { this._reads = []; this._paused = false; - this._encoding = 'utf8'; + this._encoding = "utf8"; this.writable = true; -}; +}); util.inherits(ChunkStream, Stream); - -ChunkStream.prototype.read = function(length, callback) { - +ChunkStream.prototype.read = function (length, callback) { this._reads.push({ length: Math.abs(length), // if length < 0 then at most this length allowLess: length < 0, - func: callback + func: callback, }); - process.nextTick(function() { - this._process(); + process.nextTick( + function () { + this._process(); - // its paused and there is not enought data then ask for more - if (this._paused && this._reads.length > 0) { - this._paused = false; + // its paused and there is not enought data then ask for more + if (this._paused && this._reads.length > 0) { + this._paused = false; - this.emit('drain'); - } - }.bind(this)); + this.emit("drain"); + } + }.bind(this) + ); }; -ChunkStream.prototype.write = function(data, encoding) { - +ChunkStream.prototype.write = function (data, encoding) { if (!this.writable) { - this.emit('error', new Error('Stream not writable')); + this.emit("error", new Error("Stream not writable")); return false; } - var dataBuffer; + let dataBuffer; if (Buffer.isBuffer(data)) { dataBuffer = data; - } - else { + } else { dataBuffer = Buffer.from(data, encoding || this._encoding); } @@ -68,8 +64,7 @@ ChunkStream.prototype.write = function(data, encoding) { return this.writable && !this._paused; }; -ChunkStream.prototype.end = function(data, encoding) { - +ChunkStream.prototype.end = function (data, encoding) { if (data) { this.write(data, encoding); } @@ -84,8 +79,7 @@ ChunkStream.prototype.end = function(data, encoding) { // enqueue or handle end if (this._buffers.length === 0) { this._end(); - } - else { + } else { this._buffers.push(null); this._process(); } @@ -93,19 +87,15 @@ ChunkStream.prototype.end = function(data, encoding) { ChunkStream.prototype.destroySoon = ChunkStream.prototype.end; -ChunkStream.prototype._end = function() { - +ChunkStream.prototype._end = function () { if (this._reads.length > 0) { - this.emit('error', - new Error('Unexpected end of input') - ); + this.emit("error", new Error("Unexpected end of input")); } this.destroy(); }; -ChunkStream.prototype.destroy = function() { - +ChunkStream.prototype.destroy = function () { if (!this._buffers) { return; } @@ -114,26 +104,23 @@ ChunkStream.prototype.destroy = function() { this._reads = null; this._buffers = null; - this.emit('close'); + this.emit("close"); }; -ChunkStream.prototype._processReadAllowingLess = function(read) { +ChunkStream.prototype._processReadAllowingLess = function (read) { // ok there is any data so that we can satisfy this request this._reads.shift(); // == read // first we need to peek into first buffer - var smallerBuf = this._buffers[0]; + let smallerBuf = this._buffers[0]; // ok there is more data than we need if (smallerBuf.length > read.length) { - this._buffered -= read.length; this._buffers[0] = smallerBuf.slice(read.length); read.func.call(this, smallerBuf.slice(0, read.length)); - - } - else { + } else { // ok this is less than maximum length so use it all this._buffered -= smallerBuf.length; this._buffers.shift(); // == smallerBuf @@ -142,18 +129,17 @@ ChunkStream.prototype._processReadAllowingLess = function(read) { } }; -ChunkStream.prototype._processRead = function(read) { +ChunkStream.prototype._processRead = function (read) { this._reads.shift(); // == read - var pos = 0; - var count = 0; - var data = Buffer.alloc(read.length); + let pos = 0; + let count = 0; + let data = Buffer.alloc(read.length); // create buffer for all data while (pos < read.length) { - - var buf = this._buffers[count++]; - var len = Math.min(buf.length, read.length - pos); + let buf = this._buffers[count++]; + let len = Math.min(buf.length, read.length - pos); buf.copy(data, pos, 0, len); pos += len; @@ -174,25 +160,20 @@ ChunkStream.prototype._processRead = function(read) { read.func.call(this, data); }; -ChunkStream.prototype._process = function() { - +ChunkStream.prototype._process = function () { try { // as long as there is any data and read requests while (this._buffered > 0 && this._reads && this._reads.length > 0) { - - var read = this._reads[0]; + let read = this._reads[0]; // read any data (but no more than length) if (read.allowLess) { this._processReadAllowingLess(read); - - } - else if (this._buffered >= read.length) { + } else if (this._buffered >= read.length) { // ok we can meet some expectations this._processRead(read); - } - else { + } else { // not enought data to satisfy first request in queue // so we need to wait for more break; @@ -202,8 +183,7 @@ ChunkStream.prototype._process = function() { if (this._buffers && !this.writable) { this._end(); } - } - catch (ex) { - this.emit('error', ex); + } catch (ex) { + this.emit("error", ex); } }; diff --git a/lib/constants.js b/lib/constants.js index 22d919d..21fdad6 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,8 +1,6 @@ -'use strict'; - +"use strict"; module.exports = { - PNG_SIGNATURE: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], TYPE_IHDR: 0x49484452, @@ -27,8 +25,8 @@ module.exports = { 2: 3, 3: 1, 4: 2, - 6: 4 + 6: 4, }, - GAMMA_DIVISION: 100000 + GAMMA_DIVISION: 100000, }; diff --git a/lib/crc.js b/lib/crc.js index 0705ed2..950ec8a 100644 --- a/lib/crc.js +++ b/lib/crc.js @@ -1,43 +1,39 @@ -'use strict'; +"use strict"; -var crcTable = []; +let crcTable = []; -(function() { - for (var i = 0; i < 256; i++) { - var currentCrc = i; - for (var j = 0; j < 8; j++) { +(function () { + for (let i = 0; i < 256; i++) { + let currentCrc = i; + for (let j = 0; j < 8; j++) { if (currentCrc & 1) { currentCrc = 0xedb88320 ^ (currentCrc >>> 1); - } - else { + } else { currentCrc = currentCrc >>> 1; } } crcTable[i] = currentCrc; } -}()); +})(); -var CrcCalculator = module.exports = function() { +let CrcCalculator = (module.exports = function () { this._crc = -1; -}; +}); -CrcCalculator.prototype.write = function(data) { - - for (var i = 0; i < data.length; i++) { +CrcCalculator.prototype.write = function (data) { + for (let i = 0; i < data.length; i++) { this._crc = crcTable[(this._crc ^ data[i]) & 0xff] ^ (this._crc >>> 8); } return true; }; -CrcCalculator.prototype.crc32 = function() { +CrcCalculator.prototype.crc32 = function () { return this._crc ^ -1; }; - -CrcCalculator.crc32 = function(buf) { - - var crc = -1; - for (var i = 0; i < buf.length; i++) { +CrcCalculator.crc32 = function (buf) { + let crc = -1; + for (let i = 0; i < buf.length; i++) { crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8); } return crc ^ -1; diff --git a/lib/filter-pack.js b/lib/filter-pack.js index ebb15ac..32c85c4 100644 --- a/lib/filter-pack.js +++ b/lib/filter-pack.js @@ -1,43 +1,37 @@ -'use strict'; +"use strict"; -var paethPredictor = require('./paeth-predictor'); +let paethPredictor = require("./paeth-predictor"); function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) { - - for (var x = 0; x < byteWidth; x++) { + for (let x = 0; x < byteWidth; x++) { rawData[rawPos + x] = pxData[pxPos + x]; } } function filterSumNone(pxData, pxPos, byteWidth) { + let sum = 0; + let length = pxPos + byteWidth; - var sum = 0; - var length = pxPos + byteWidth; - - for (var i = pxPos; i < length; i++) { + for (let i = pxPos; i < length; i++) { sum += Math.abs(pxData[i]); } return sum; } function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) { - - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var val = pxData[pxPos + x] - left; + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let val = pxData[pxPos + x] - left; rawData[rawPos + x] = val; } } function filterSumSub(pxData, pxPos, byteWidth, bpp) { - - var sum = 0; - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var val = pxData[pxPos + x] - left; + let sum = 0; + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let val = pxData[pxPos + x] - left; sum += Math.abs(val); } @@ -46,24 +40,20 @@ function filterSumSub(pxData, pxPos, byteWidth, bpp) { } function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) { - - for (var x = 0; x < byteWidth; x++) { - - var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; - var val = pxData[pxPos + x] - up; + for (let x = 0; x < byteWidth; x++) { + let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; + let val = pxData[pxPos + x] - up; rawData[rawPos + x] = val; } } function filterSumUp(pxData, pxPos, byteWidth) { - - var sum = 0; - var length = pxPos + byteWidth; - for (var x = pxPos; x < length; x++) { - - var up = pxPos > 0 ? pxData[x - byteWidth] : 0; - var val = pxData[x] - up; + let sum = 0; + let length = pxPos + byteWidth; + for (let x = pxPos; x < length; x++) { + let up = pxPos > 0 ? pxData[x - byteWidth] : 0; + let val = pxData[x] - up; sum += Math.abs(val); } @@ -72,25 +62,21 @@ function filterSumUp(pxData, pxPos, byteWidth) { } function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) { - - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; - var val = pxData[pxPos + x] - ((left + up) >> 1); + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; + let val = pxData[pxPos + x] - ((left + up) >> 1); rawData[rawPos + x] = val; } } function filterSumAvg(pxData, pxPos, byteWidth, bpp) { - - var sum = 0; - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; - var val = pxData[pxPos + x] - ((left + up) >> 1); + let sum = 0; + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; + let val = pxData[pxPos + x] - ((left + up) >> 1); sum += Math.abs(val); } @@ -99,26 +85,25 @@ function filterSumAvg(pxData, pxPos, byteWidth, bpp) { } function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) { - - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; - var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0; - var val = pxData[pxPos + x] - paethPredictor(left, up, upleft); + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; + let upleft = + pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0; + let val = pxData[pxPos + x] - paethPredictor(left, up, upleft); rawData[rawPos + x] = val; } } function filterSumPaeth(pxData, pxPos, byteWidth, bpp) { - var sum = 0; - for (var x = 0; x < byteWidth; x++) { - - var left = x >= bpp ? pxData[pxPos + x - bpp] : 0; - var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; - var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0; - var val = pxData[pxPos + x] - paethPredictor(left, up, upleft); + let sum = 0; + for (let x = 0; x < byteWidth; x++) { + let left = x >= bpp ? pxData[pxPos + x - bpp] : 0; + let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0; + let upleft = + pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0; + let val = pxData[pxPos + x] - paethPredictor(left, up, upleft); sum += Math.abs(val); } @@ -126,53 +111,49 @@ function filterSumPaeth(pxData, pxPos, byteWidth, bpp) { return sum; } -var filters = { +let filters = { 0: filterNone, 1: filterSub, 2: filterUp, 3: filterAvg, - 4: filterPaeth + 4: filterPaeth, }; -var filterSums = { +let filterSums = { 0: filterSumNone, 1: filterSumSub, 2: filterSumUp, 3: filterSumAvg, - 4: filterSumPaeth + 4: filterSumPaeth, }; -module.exports = function(pxData, width, height, options, bpp) { - - var filterTypes; - if (!('filterType' in options) || options.filterType === -1) { +module.exports = function (pxData, width, height, options, bpp) { + let filterTypes; + if (!("filterType" in options) || options.filterType === -1) { filterTypes = [0, 1, 2, 3, 4]; - } - else if (typeof options.filterType === 'number') { + } else if (typeof options.filterType === "number") { filterTypes = [options.filterType]; - } - else { - throw new Error('unrecognised filter types'); + } else { + throw new Error("unrecognised filter types"); } if (options.bitDepth === 16) { bpp *= 2; } - var byteWidth = width * bpp; - var rawPos = 0; - var pxPos = 0; - var rawData = Buffer.alloc((byteWidth + 1) * height); + let byteWidth = width * bpp; + let rawPos = 0; + let pxPos = 0; + let rawData = Buffer.alloc((byteWidth + 1) * height); - var sel = filterTypes[0]; - - for (var y = 0; y < height; y++) { + let sel = filterTypes[0]; + for (let y = 0; y < height; y++) { if (filterTypes.length > 1) { // find best filter for this line (with lowest sum of values) - var min = Infinity; + let min = Infinity; - for (var i = 0; i < filterTypes.length; i++) { - var sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp); + for (let i = 0; i < filterTypes.length; i++) { + let sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp); if (sum < min) { sel = filterTypes[i]; min = sum; diff --git a/lib/filter-parse-async.js b/lib/filter-parse-async.js index 560c30e..832b86c 100644 --- a/lib/filter-parse-async.js +++ b/lib/filter-parse-async.js @@ -1,25 +1,24 @@ -'use strict'; +"use strict"; -var util = require('util'); -var ChunkStream = require('./chunkstream'); -var Filter = require('./filter-parse'); +let util = require("util"); +let ChunkStream = require("./chunkstream"); +let Filter = require("./filter-parse"); - -var FilterAsync = module.exports = function(bitmapInfo) { +let FilterAsync = (module.exports = function (bitmapInfo) { ChunkStream.call(this); - var buffers = []; - var that = this; + let buffers = []; + let that = this; this._filter = new Filter(bitmapInfo, { read: this.read.bind(this), - write: function(buffer) { + write: function (buffer) { buffers.push(buffer); }, - complete: function() { - that.emit('complete', Buffer.concat(buffers)); - } + complete: function () { + that.emit("complete", Buffer.concat(buffers)); + }, }); this._filter.start(); -}; +}); util.inherits(FilterAsync, ChunkStream); diff --git a/lib/filter-parse-sync.js b/lib/filter-parse-sync.js index 958c676..6924d16 100644 --- a/lib/filter-parse-sync.js +++ b/lib/filter-parse-sync.js @@ -1,24 +1,21 @@ -'use strict'; +"use strict"; -var SyncReader = require('./sync-reader'); -var Filter = require('./filter-parse'); +let SyncReader = require("./sync-reader"); +let Filter = require("./filter-parse"); - -exports.process = function(inBuffer, bitmapInfo) { - - var outBuffers = []; - var reader = new SyncReader(inBuffer); - var filter = new Filter(bitmapInfo, { +exports.process = function (inBuffer, bitmapInfo) { + let outBuffers = []; + let reader = new SyncReader(inBuffer); + let filter = new Filter(bitmapInfo, { read: reader.read.bind(reader), - write: function(bufferPart) { + write: function (bufferPart) { outBuffers.push(bufferPart); }, - complete: function() { - } + complete: function () {}, }); filter.start(); reader.process(); return Buffer.concat(outBuffers); -}; \ No newline at end of file +}; diff --git a/lib/filter-parse.js b/lib/filter-parse.js index 4c2e047..3a32e5e 100644 --- a/lib/filter-parse.js +++ b/lib/filter-parse.js @@ -1,23 +1,22 @@ -'use strict'; +"use strict"; -var interlaceUtils = require('./interlace'); -var paethPredictor = require('./paeth-predictor'); +let interlaceUtils = require("./interlace"); +let paethPredictor = require("./paeth-predictor"); function getByteWidth(width, bpp, depth) { - var byteWidth = width * bpp; + let byteWidth = width * bpp; if (depth !== 8) { byteWidth = Math.ceil(byteWidth / (8 / depth)); } return byteWidth; } -var Filter = module.exports = function(bitmapInfo, dependencies) { - - var width = bitmapInfo.width; - var height = bitmapInfo.height; - var interlace = bitmapInfo.interlace; - var bpp = bitmapInfo.bpp; - var depth = bitmapInfo.depth; +let Filter = (module.exports = function (bitmapInfo, dependencies) { + let width = bitmapInfo.width; + let height = bitmapInfo.height; + let interlace = bitmapInfo.interlace; + let bpp = bitmapInfo.bpp; + let depth = bitmapInfo.depth; this.read = dependencies.read; this.write = dependencies.write; @@ -26,20 +25,19 @@ var Filter = module.exports = function(bitmapInfo, dependencies) { this._imageIndex = 0; this._images = []; if (interlace) { - var passes = interlaceUtils.getImagePasses(width, height); - for (var i = 0; i < passes.length; i++) { + let passes = interlaceUtils.getImagePasses(width, height); + for (let i = 0; i < passes.length; i++) { this._images.push({ byteWidth: getByteWidth(passes[i].width, bpp, depth), height: passes[i].height, - lineIndex: 0 + lineIndex: 0, }); } - } - else { + } else { this._images.push({ byteWidth: getByteWidth(width, bpp, depth), height: height, - lineIndex: 0 + lineIndex: 0, }); } @@ -49,85 +47,95 @@ var Filter = module.exports = function(bitmapInfo, dependencies) { // a pixel rather than just a different byte part. However if we are sub byte, we ignore. if (depth === 8) { this._xComparison = bpp; - } - else if (depth === 16) { + } else if (depth === 16) { this._xComparison = bpp * 2; - } - else { + } else { this._xComparison = 1; } +}); + +Filter.prototype.start = function () { + this.read( + this._images[this._imageIndex].byteWidth + 1, + this._reverseFilterLine.bind(this) + ); }; -Filter.prototype.start = function() { - this.read(this._images[this._imageIndex].byteWidth + 1, this._reverseFilterLine.bind(this)); -}; +Filter.prototype._unFilterType1 = function ( + rawData, + unfilteredLine, + byteWidth +) { + let xComparison = this._xComparison; + let xBiggerThan = xComparison - 1; -Filter.prototype._unFilterType1 = function(rawData, unfilteredLine, byteWidth) { - - var xComparison = this._xComparison; - var xBiggerThan = xComparison - 1; - - for (var x = 0; x < byteWidth; x++) { - var rawByte = rawData[1 + x]; - var f1Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; + for (let x = 0; x < byteWidth; x++) { + let rawByte = rawData[1 + x]; + let f1Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; unfilteredLine[x] = rawByte + f1Left; } }; -Filter.prototype._unFilterType2 = function(rawData, unfilteredLine, byteWidth) { +Filter.prototype._unFilterType2 = function ( + rawData, + unfilteredLine, + byteWidth +) { + let lastLine = this._lastLine; - var lastLine = this._lastLine; - - for (var x = 0; x < byteWidth; x++) { - var rawByte = rawData[1 + x]; - var f2Up = lastLine ? lastLine[x] : 0; + for (let x = 0; x < byteWidth; x++) { + let rawByte = rawData[1 + x]; + let f2Up = lastLine ? lastLine[x] : 0; unfilteredLine[x] = rawByte + f2Up; } }; -Filter.prototype._unFilterType3 = function(rawData, unfilteredLine, byteWidth) { +Filter.prototype._unFilterType3 = function ( + rawData, + unfilteredLine, + byteWidth +) { + let xComparison = this._xComparison; + let xBiggerThan = xComparison - 1; + let lastLine = this._lastLine; - var xComparison = this._xComparison; - var xBiggerThan = xComparison - 1; - var lastLine = this._lastLine; - - for (var x = 0; x < byteWidth; x++) { - var rawByte = rawData[1 + x]; - var f3Up = lastLine ? lastLine[x] : 0; - var f3Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; - var f3Add = Math.floor((f3Left + f3Up) / 2); + for (let x = 0; x < byteWidth; x++) { + let rawByte = rawData[1 + x]; + let f3Up = lastLine ? lastLine[x] : 0; + let f3Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; + let f3Add = Math.floor((f3Left + f3Up) / 2); unfilteredLine[x] = rawByte + f3Add; } }; -Filter.prototype._unFilterType4 = function(rawData, unfilteredLine, byteWidth) { +Filter.prototype._unFilterType4 = function ( + rawData, + unfilteredLine, + byteWidth +) { + let xComparison = this._xComparison; + let xBiggerThan = xComparison - 1; + let lastLine = this._lastLine; - var xComparison = this._xComparison; - var xBiggerThan = xComparison - 1; - var lastLine = this._lastLine; - - for (var x = 0; x < byteWidth; x++) { - var rawByte = rawData[1 + x]; - var f4Up = lastLine ? lastLine[x] : 0; - var f4Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; - var f4UpLeft = x > xBiggerThan && lastLine ? lastLine[x - xComparison] : 0; - var f4Add = paethPredictor(f4Left, f4Up, f4UpLeft); + for (let x = 0; x < byteWidth; x++) { + let rawByte = rawData[1 + x]; + let f4Up = lastLine ? lastLine[x] : 0; + let f4Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0; + let f4UpLeft = x > xBiggerThan && lastLine ? lastLine[x - xComparison] : 0; + let f4Add = paethPredictor(f4Left, f4Up, f4UpLeft); unfilteredLine[x] = rawByte + f4Add; } }; -Filter.prototype._reverseFilterLine = function(rawData) { - - var filter = rawData[0]; - var unfilteredLine; - var currentImage = this._images[this._imageIndex]; - var byteWidth = currentImage.byteWidth; +Filter.prototype._reverseFilterLine = function (rawData) { + let filter = rawData[0]; + let unfilteredLine; + let currentImage = this._images[this._imageIndex]; + let byteWidth = currentImage.byteWidth; if (filter === 0) { unfilteredLine = rawData.slice(1, byteWidth + 1); - } - else { - + } else { unfilteredLine = Buffer.alloc(byteWidth); switch (filter) { @@ -144,7 +152,7 @@ Filter.prototype._reverseFilterLine = function(rawData) { this._unFilterType4(rawData, unfilteredLine, byteWidth); break; default: - throw new Error('Unrecognised filter type - ' + filter); + throw new Error("Unrecognised filter type - " + filter); } } @@ -155,16 +163,14 @@ Filter.prototype._reverseFilterLine = function(rawData) { this._lastLine = null; this._imageIndex++; currentImage = this._images[this._imageIndex]; - } - else { + } else { this._lastLine = unfilteredLine; } if (currentImage) { // read, using the byte width that may be from the new current image this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this)); - } - else { + } else { this._lastLine = null; this.complete(); } diff --git a/lib/format-normaliser.js b/lib/format-normaliser.js index 1e40cbc..634d566 100644 --- a/lib/format-normaliser.js +++ b/lib/format-normaliser.js @@ -1,17 +1,17 @@ -'use strict'; +"use strict"; function dePalette(indata, outdata, width, height, palette) { - var pxPos = 0; + let pxPos = 0; // use values from palette - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var color = palette[indata[pxPos]]; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + let color = palette[indata[pxPos]]; if (!color) { - throw new Error('index ' + indata[pxPos] + ' not in palette'); + throw new Error("index " + indata[pxPos] + " not in palette"); } - for (var i = 0; i < 4; i++) { + for (let i = 0; i < 4; i++) { outdata[pxPos + i] = color[i]; } pxPos += 4; @@ -20,21 +20,24 @@ function dePalette(indata, outdata, width, height, palette) { } function replaceTransparentColor(indata, outdata, width, height, transColor) { - var pxPos = 0; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var makeTrans = false; + let pxPos = 0; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + let makeTrans = false; if (transColor.length === 1) { if (transColor[0] === indata[pxPos]) { makeTrans = true; } - } - else if (transColor[0] === indata[pxPos] && transColor[1] === indata[pxPos + 1] && transColor[2] === indata[pxPos + 2]) { + } else if ( + transColor[0] === indata[pxPos] && + transColor[1] === indata[pxPos + 1] && + transColor[2] === indata[pxPos + 2] + ) { makeTrans = true; } if (makeTrans) { - for (var i = 0; i < 4; i++) { + for (let i = 0; i < 4; i++) { outdata[pxPos + i] = 0; } } @@ -44,35 +47,36 @@ function replaceTransparentColor(indata, outdata, width, height, transColor) { } function scaleDepth(indata, outdata, width, height, depth) { - var maxOutSample = 255; - var maxInSample = Math.pow(2, depth) - 1; - var pxPos = 0; + let maxOutSample = 255; + let maxInSample = Math.pow(2, depth) - 1; + let pxPos = 0; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - for (var i = 0; i < 4; i++) { - outdata[pxPos + i] = Math.floor((indata[pxPos + i] * maxOutSample) / maxInSample + 0.5); + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + for (let i = 0; i < 4; i++) { + outdata[pxPos + i] = Math.floor( + (indata[pxPos + i] * maxOutSample) / maxInSample + 0.5 + ); } pxPos += 4; } } } -module.exports = function(indata, imageData) { +module.exports = function (indata, imageData) { + let depth = imageData.depth; + let width = imageData.width; + let height = imageData.height; + let colorType = imageData.colorType; + let transColor = imageData.transColor; + let palette = imageData.palette; - var depth = imageData.depth; - var width = imageData.width; - var height = imageData.height; - var colorType = imageData.colorType; - var transColor = imageData.transColor; - var palette = imageData.palette; + let outdata = indata; // only different for 16 bits - var outdata = indata; // only different for 16 bits - - if (colorType === 3) { // paletted + if (colorType === 3) { + // paletted dePalette(indata, outdata, width, height, palette); - } - else { + } else { if (transColor) { replaceTransparentColor(indata, outdata, width, height, transColor); } diff --git a/lib/interlace.js b/lib/interlace.js index 734ea23..a035cb1 100644 --- a/lib/interlace.js +++ b/lib/interlace.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; // Adam 7 // 0 1 2 3 4 5 6 7 @@ -11,61 +11,65 @@ // 6 5 6 5 6 5 6 5 6 // 7 7 7 7 7 7 7 7 7 - -var imagePasses = [ - { // pass 1 - 1px +let imagePasses = [ + { + // pass 1 - 1px x: [0], - y: [0] + y: [0], }, - { // pass 2 - 1px + { + // pass 2 - 1px x: [4], - y: [0] + y: [0], }, - { // pass 3 - 2px + { + // pass 3 - 2px x: [0, 4], - y: [4] + y: [4], }, - { // pass 4 - 4px + { + // pass 4 - 4px x: [2, 6], - y: [0, 4] + y: [0, 4], }, - { // pass 5 - 8px + { + // pass 5 - 8px x: [0, 2, 4, 6], - y: [2, 6] + y: [2, 6], }, - { // pass 6 - 16px + { + // pass 6 - 16px x: [1, 3, 5, 7], - y: [0, 2, 4, 6] + y: [0, 2, 4, 6], }, - { // pass 7 - 32px + { + // pass 7 - 32px x: [0, 1, 2, 3, 4, 5, 6, 7], - y: [1, 3, 5, 7] - } + y: [1, 3, 5, 7], + }, ]; -exports.getImagePasses = function(width, height) { - var images = []; - var xLeftOver = width % 8; - var yLeftOver = height % 8; - var xRepeats = (width - xLeftOver) / 8; - var yRepeats = (height - yLeftOver) / 8; - for (var i = 0; i < imagePasses.length; i++) { - var pass = imagePasses[i]; - var passWidth = xRepeats * pass.x.length; - var passHeight = yRepeats * pass.y.length; - for (var j = 0; j < pass.x.length; j++) { +exports.getImagePasses = function (width, height) { + let images = []; + let xLeftOver = width % 8; + let yLeftOver = height % 8; + let xRepeats = (width - xLeftOver) / 8; + let yRepeats = (height - yLeftOver) / 8; + for (let i = 0; i < imagePasses.length; i++) { + let pass = imagePasses[i]; + let passWidth = xRepeats * pass.x.length; + let passHeight = yRepeats * pass.y.length; + for (let j = 0; j < pass.x.length; j++) { if (pass.x[j] < xLeftOver) { passWidth++; - } - else { + } else { break; } } - for (j = 0; j < pass.y.length; j++) { + for (let j = 0; j < pass.y.length; j++) { if (pass.y[j] < yLeftOver) { passHeight++; - } - else { + } else { break; } } @@ -76,12 +80,16 @@ exports.getImagePasses = function(width, height) { return images; }; -exports.getInterlaceIterator = function(width) { - return function(x, y, pass) { - var outerXLeftOver = x % imagePasses[pass].x.length; - var outerX = (((x - outerXLeftOver) / imagePasses[pass].x.length) * 8) + imagePasses[pass].x[outerXLeftOver]; - var outerYLeftOver = y % imagePasses[pass].y.length; - var outerY = (((y - outerYLeftOver) / imagePasses[pass].y.length) * 8) + imagePasses[pass].y[outerYLeftOver]; - return (outerX * 4) + (outerY * width * 4); +exports.getInterlaceIterator = function (width) { + return function (x, y, pass) { + let outerXLeftOver = x % imagePasses[pass].x.length; + let outerX = + ((x - outerXLeftOver) / imagePasses[pass].x.length) * 8 + + imagePasses[pass].x[outerXLeftOver]; + let outerYLeftOver = y % imagePasses[pass].y.length; + let outerY = + ((y - outerYLeftOver) / imagePasses[pass].y.length) * 8 + + imagePasses[pass].y[outerYLeftOver]; + return outerX * 4 + outerY * width * 4; }; -}; \ No newline at end of file +}; diff --git a/lib/packer-async.js b/lib/packer-async.js index 5be2653..f3df73a 100644 --- a/lib/packer-async.js +++ b/lib/packer-async.js @@ -1,45 +1,50 @@ -'use strict'; +"use strict"; -var util = require('util'); -var Stream = require('stream'); -var constants = require('./constants'); -var Packer = require('./packer'); +let util = require("util"); +let Stream = require("stream"); +let constants = require("./constants"); +let Packer = require("./packer"); -var PackerAsync = module.exports = function(opt) { +let PackerAsync = (module.exports = function (opt) { Stream.call(this); - var options = opt || {}; + let options = opt || {}; this._packer = new Packer(options); this._deflate = this._packer.createDeflate(); this.readable = true; -}; +}); util.inherits(PackerAsync, Stream); - -PackerAsync.prototype.pack = function(data, width, height, gamma) { +PackerAsync.prototype.pack = function (data, width, height, gamma) { // Signature - this.emit('data', Buffer.from(constants.PNG_SIGNATURE)); - this.emit('data', this._packer.packIHDR(width, height)); + this.emit("data", Buffer.from(constants.PNG_SIGNATURE)); + this.emit("data", this._packer.packIHDR(width, height)); if (gamma) { - this.emit('data', this._packer.packGAMA(gamma)); + this.emit("data", this._packer.packGAMA(gamma)); } - var filteredData = this._packer.filterData(data, width, height); + let filteredData = this._packer.filterData(data, width, height); // compress it - this._deflate.on('error', this.emit.bind(this, 'error')); + this._deflate.on("error", this.emit.bind(this, "error")); - this._deflate.on('data', function(compressedData) { - this.emit('data', this._packer.packIDAT(compressedData)); - }.bind(this)); + this._deflate.on( + "data", + function (compressedData) { + this.emit("data", this._packer.packIDAT(compressedData)); + }.bind(this) + ); - this._deflate.on('end', function() { - this.emit('data', this._packer.packIEND()); - this.emit('end'); - }.bind(this)); + this._deflate.on( + "end", + function () { + this.emit("data", this._packer.packIEND()); + this.emit("end"); + }.bind(this) + ); this._deflate.end(filteredData); }; diff --git a/lib/packer-sync.js b/lib/packer-sync.js index ad60a28..f5ab0b3 100644 --- a/lib/packer-sync.js +++ b/lib/packer-sync.js @@ -1,24 +1,25 @@ -'use strict'; +"use strict"; -var hasSyncZlib = true; -var zlib = require('zlib'); +let hasSyncZlib = true; +let zlib = require("zlib"); if (!zlib.deflateSync) { hasSyncZlib = false; } -var constants = require('./constants'); -var Packer = require('./packer'); - -module.exports = function(metaData, opt) { +let constants = require("./constants"); +let Packer = require("./packer"); +module.exports = function (metaData, opt) { if (!hasSyncZlib) { - throw new Error('To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0'); + throw new Error( + "To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0" + ); } - var options = opt || {}; + let options = opt || {}; - var packer = new Packer(options); + let packer = new Packer(options); - var chunks = []; + let chunks = []; // Signature chunks.push(Buffer.from(constants.PNG_SIGNATURE)); @@ -30,14 +31,21 @@ module.exports = function(metaData, opt) { chunks.push(packer.packGAMA(metaData.gamma)); } - var filteredData = packer.filterData(metaData.data, metaData.width, metaData.height); + let filteredData = packer.filterData( + metaData.data, + metaData.width, + metaData.height + ); // compress it - var compressedData = zlib.deflateSync(filteredData, packer.getDeflateOptions()); + let compressedData = zlib.deflateSync( + filteredData, + packer.getDeflateOptions() + ); filteredData = null; if (!compressedData || !compressedData.length) { - throw new Error('bad png - invalid compressed data response'); + throw new Error("bad png - invalid compressed data response"); } chunks.push(packer.packIDAT(compressedData)); diff --git a/lib/packer.js b/lib/packer.js index 1f0c515..4aba12c 100644 --- a/lib/packer.js +++ b/lib/packer.js @@ -1,71 +1,91 @@ -'use strict'; +"use strict"; -var constants = require('./constants'); -var CrcStream = require('./crc'); -var bitPacker = require('./bitpacker'); -var filter = require('./filter-pack'); -var zlib = require('zlib'); +let constants = require("./constants"); +let CrcStream = require("./crc"); +let bitPacker = require("./bitpacker"); +let filter = require("./filter-pack"); +let zlib = require("zlib"); -var Packer = module.exports = function(options) { +let Packer = (module.exports = function (options) { this._options = options; options.deflateChunkSize = options.deflateChunkSize || 32 * 1024; - options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9; - options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3; - options.inputHasAlpha = options.inputHasAlpha != null ? options.inputHasAlpha : true; + options.deflateLevel = + options.deflateLevel != null ? options.deflateLevel : 9; + options.deflateStrategy = + options.deflateStrategy != null ? options.deflateStrategy : 3; + options.inputHasAlpha = + options.inputHasAlpha != null ? options.inputHasAlpha : true; options.deflateFactory = options.deflateFactory || zlib.createDeflate; options.bitDepth = options.bitDepth || 8; // This is outputColorType - options.colorType = (typeof options.colorType === 'number') ? options.colorType : constants.COLORTYPE_COLOR_ALPHA; - options.inputColorType = (typeof options.inputColorType === 'number') ? options.inputColorType : constants.COLORTYPE_COLOR_ALPHA; + options.colorType = + typeof options.colorType === "number" + ? options.colorType + : constants.COLORTYPE_COLOR_ALPHA; + options.inputColorType = + typeof options.inputColorType === "number" + ? options.inputColorType + : constants.COLORTYPE_COLOR_ALPHA; - if ([ - constants.COLORTYPE_GRAYSCALE, - constants.COLORTYPE_COLOR, - constants.COLORTYPE_COLOR_ALPHA, - constants.COLORTYPE_ALPHA - ].indexOf(options.colorType) === -1) { - throw new Error('option color type:' + options.colorType + ' is not supported at present'); + if ( + [ + constants.COLORTYPE_GRAYSCALE, + constants.COLORTYPE_COLOR, + constants.COLORTYPE_COLOR_ALPHA, + constants.COLORTYPE_ALPHA, + ].indexOf(options.colorType) === -1 + ) { + throw new Error( + "option color type:" + options.colorType + " is not supported at present" + ); } - if ([ - constants.COLORTYPE_GRAYSCALE, - constants.COLORTYPE_COLOR, - constants.COLORTYPE_COLOR_ALPHA, - constants.COLORTYPE_ALPHA - ].indexOf(options.inputColorType) === -1) { - throw new Error('option input color type:' + options.inputColorType + ' is not supported at present'); + if ( + [ + constants.COLORTYPE_GRAYSCALE, + constants.COLORTYPE_COLOR, + constants.COLORTYPE_COLOR_ALPHA, + constants.COLORTYPE_ALPHA, + ].indexOf(options.inputColorType) === -1 + ) { + throw new Error( + "option input color type:" + + options.inputColorType + + " is not supported at present" + ); } if (options.bitDepth !== 8 && options.bitDepth !== 16) { - throw new Error('option bit depth:' + options.bitDepth + ' is not supported at present'); + throw new Error( + "option bit depth:" + options.bitDepth + " is not supported at present" + ); } -}; +}); -Packer.prototype.getDeflateOptions = function() { +Packer.prototype.getDeflateOptions = function () { return { chunkSize: this._options.deflateChunkSize, level: this._options.deflateLevel, - strategy: this._options.deflateStrategy + strategy: this._options.deflateStrategy, }; }; -Packer.prototype.createDeflate = function() { +Packer.prototype.createDeflate = function () { return this._options.deflateFactory(this.getDeflateOptions()); }; -Packer.prototype.filterData = function(data, width, height) { +Packer.prototype.filterData = function (data, width, height) { // convert to correct format for filtering (e.g. right bpp and bit depth) - var packedData = bitPacker(data, width, height, this._options); + let packedData = bitPacker(data, width, height, this._options); // filter pixel data - var bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType]; - var filteredData = filter(packedData, width, height, this._options, bpp); + let bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType]; + let filteredData = filter(packedData, width, height, this._options, bpp); return filteredData; }; -Packer.prototype._packChunk = function(type, data) { - - var len = (data ? data.length : 0); - var buf = Buffer.alloc(len + 12); +Packer.prototype._packChunk = function (type, data) { + let len = data ? data.length : 0; + let buf = Buffer.alloc(len + 12); buf.writeUInt32BE(len, 0); buf.writeUInt32BE(type, 4); @@ -74,19 +94,21 @@ Packer.prototype._packChunk = function(type, data) { data.copy(buf, 8); } - buf.writeInt32BE(CrcStream.crc32(buf.slice(4, buf.length - 4)), buf.length - 4); + buf.writeInt32BE( + CrcStream.crc32(buf.slice(4, buf.length - 4)), + buf.length - 4 + ); return buf; }; -Packer.prototype.packGAMA = function(gamma) { - var buf = Buffer.alloc(4); +Packer.prototype.packGAMA = function (gamma) { + let buf = Buffer.alloc(4); buf.writeUInt32BE(Math.floor(gamma * constants.GAMMA_DIVISION), 0); return this._packChunk(constants.TYPE_gAMA, buf); }; -Packer.prototype.packIHDR = function(width, height) { - - var buf = Buffer.alloc(13); +Packer.prototype.packIHDR = function (width, height) { + let buf = Buffer.alloc(13); buf.writeUInt32BE(width, 0); buf.writeUInt32BE(height, 4); buf[8] = this._options.bitDepth; // Bit depth @@ -98,10 +120,10 @@ Packer.prototype.packIHDR = function(width, height) { return this._packChunk(constants.TYPE_IHDR, buf); }; -Packer.prototype.packIDAT = function(data) { +Packer.prototype.packIDAT = function (data) { return this._packChunk(constants.TYPE_IDAT, data); }; -Packer.prototype.packIEND = function() { +Packer.prototype.packIEND = function () { return this._packChunk(constants.TYPE_IEND, null); }; diff --git a/lib/paeth-predictor.js b/lib/paeth-predictor.js index 74d254e..9634497 100644 --- a/lib/paeth-predictor.js +++ b/lib/paeth-predictor.js @@ -1,17 +1,16 @@ -'use strict'; - -module.exports = function paethPredictor(left, above, upLeft) { - - var paeth = left + above - upLeft; - var pLeft = Math.abs(paeth - left); - var pAbove = Math.abs(paeth - above); - var pUpLeft = Math.abs(paeth - upLeft); - - if (pLeft <= pAbove && pLeft <= pUpLeft) { - return left; - } - if (pAbove <= pUpLeft) { - return above; - } - return upLeft; -}; \ No newline at end of file +"use strict"; + +module.exports = function paethPredictor(left, above, upLeft) { + let paeth = left + above - upLeft; + let pLeft = Math.abs(paeth - left); + let pAbove = Math.abs(paeth - above); + let pUpLeft = Math.abs(paeth - upLeft); + + if (pLeft <= pAbove && pLeft <= pUpLeft) { + return left; + } + if (pAbove <= pUpLeft) { + return above; + } + return upLeft; +}; diff --git a/lib/parser-async.js b/lib/parser-async.js index 4ff599a..a69d153 100644 --- a/lib/parser-async.js +++ b/lib/parser-async.js @@ -1,39 +1,37 @@ -'use strict'; +"use strict"; -var util = require('util'); -var zlib = require('zlib'); -var ChunkStream = require('./chunkstream'); -var FilterAsync = require('./filter-parse-async'); -var Parser = require('./parser'); -var bitmapper = require('./bitmapper'); -var formatNormaliser = require('./format-normaliser'); +let util = require("util"); +let zlib = require("zlib"); +let ChunkStream = require("./chunkstream"); +let FilterAsync = require("./filter-parse-async"); +let Parser = require("./parser"); +let bitmapper = require("./bitmapper"); +let formatNormaliser = require("./format-normaliser"); -var ParserAsync = module.exports = function(options) { +let ParserAsync = (module.exports = function (options) { ChunkStream.call(this); this._parser = new Parser(options, { read: this.read.bind(this), error: this._handleError.bind(this), metadata: this._handleMetaData.bind(this), - gamma: this.emit.bind(this, 'gamma'), + gamma: this.emit.bind(this, "gamma"), palette: this._handlePalette.bind(this), transColor: this._handleTransColor.bind(this), finished: this._finished.bind(this), inflateData: this._inflateData.bind(this), simpleTransparency: this._simpleTransparency.bind(this), - headersFinished: this._headersFinished.bind(this) + headersFinished: this._headersFinished.bind(this), }); this._options = options; this.writable = true; this._parser.start(); -}; +}); util.inherits(ParserAsync, ChunkStream); - -ParserAsync.prototype._handleError = function(err) { - - this.emit('error', err); +ParserAsync.prototype._handleError = function (err) { + this.emit("error", err); this.writable = false; @@ -48,42 +46,47 @@ ParserAsync.prototype._handleError = function(err) { // For backward compatibility with Node 7 and below. // Suppress errors due to _inflate calling write() even after // it's destroy()'ed. - this._filter.on('error', function() {}); + this._filter.on("error", function () {}); } this.errord = true; }; -ParserAsync.prototype._inflateData = function(data) { +ParserAsync.prototype._inflateData = function (data) { if (!this._inflate) { if (this._bitmapInfo.interlace) { this._inflate = zlib.createInflate(); - this._inflate.on('error', this.emit.bind(this, 'error')); - this._filter.on('complete', this._complete.bind(this)); + this._inflate.on("error", this.emit.bind(this, "error")); + this._filter.on("complete", this._complete.bind(this)); this._inflate.pipe(this._filter); - } - else { - var rowSize = ((this._bitmapInfo.width * this._bitmapInfo.bpp * this._bitmapInfo.depth + 7) >> 3) + 1; - var imageSize = rowSize * this._bitmapInfo.height; - var chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK); + } else { + let rowSize = + ((this._bitmapInfo.width * + this._bitmapInfo.bpp * + this._bitmapInfo.depth + + 7) >> + 3) + + 1; + let imageSize = rowSize * this._bitmapInfo.height; + let chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK); this._inflate = zlib.createInflate({ chunkSize: chunkSize }); - var leftToInflate = imageSize; + let leftToInflate = imageSize; - var emitError = this.emit.bind(this, 'error'); - this._inflate.on('error', function(err) { + let emitError = this.emit.bind(this, "error"); + this._inflate.on("error", function (err) { if (!leftToInflate) { return; } emitError(err); }); - this._filter.on('complete', this._complete.bind(this)); + this._filter.on("complete", this._complete.bind(this)); - var filterWrite = this._filter.write.bind(this._filter); - this._inflate.on('data', function(chunk) { + let filterWrite = this._filter.write.bind(this._filter); + this._inflate.on("data", function (chunk) { if (!leftToInflate) { return; } @@ -97,67 +100,66 @@ ParserAsync.prototype._inflateData = function(data) { filterWrite(chunk); }); - this._inflate.on('end', this._filter.end.bind(this._filter)); + this._inflate.on("end", this._filter.end.bind(this._filter)); } } this._inflate.write(data); }; -ParserAsync.prototype._handleMetaData = function(metaData) { +ParserAsync.prototype._handleMetaData = function (metaData) { this._metaData = metaData; this._bitmapInfo = Object.create(metaData); this._filter = new FilterAsync(this._bitmapInfo); }; -ParserAsync.prototype._handleTransColor = function(transColor) { +ParserAsync.prototype._handleTransColor = function (transColor) { this._bitmapInfo.transColor = transColor; }; -ParserAsync.prototype._handlePalette = function(palette) { +ParserAsync.prototype._handlePalette = function (palette) { this._bitmapInfo.palette = palette; }; -ParserAsync.prototype._simpleTransparency = function() { +ParserAsync.prototype._simpleTransparency = function () { this._metaData.alpha = true; }; -ParserAsync.prototype._headersFinished = function() { +ParserAsync.prototype._headersFinished = function () { // Up until this point, we don't know if we have a tRNS chunk (alpha) // so we can't emit metadata any earlier - this.emit('metadata', this._metaData); + this.emit("metadata", this._metaData); }; -ParserAsync.prototype._finished = function() { +ParserAsync.prototype._finished = function () { if (this.errord) { return; } if (!this._inflate) { - this.emit('error', 'No Inflate block'); - } - else { + this.emit("error", "No Inflate block"); + } else { // no more data to inflate this._inflate.end(); } }; -ParserAsync.prototype._complete = function(filteredData) { - +ParserAsync.prototype._complete = function (filteredData) { if (this.errord) { return; } - try { - var bitmapData = bitmapper.dataToBitMap(filteredData, this._bitmapInfo); + let normalisedBitmapData; - var normalisedBitmapData = formatNormaliser(bitmapData, this._bitmapInfo); + try { + let bitmapData = bitmapper.dataToBitMap(filteredData, this._bitmapInfo); + + normalisedBitmapData = formatNormaliser(bitmapData, this._bitmapInfo); bitmapData = null; - } - catch (ex) { + } catch (ex) { this._handleError(ex); return; } - this.emit('parsed', normalisedBitmapData); + this.emit("parsed", normalisedBitmapData); }; diff --git a/lib/parser-sync.js b/lib/parser-sync.js index ed899a4..e79796b 100644 --- a/lib/parser-sync.js +++ b/lib/parser-sync.js @@ -1,30 +1,30 @@ -'use strict'; +"use strict"; -var hasSyncZlib = true; -var zlib = require('zlib'); -var inflateSync = require('./sync-inflate'); +let hasSyncZlib = true; +let zlib = require("zlib"); +let inflateSync = require("./sync-inflate"); if (!zlib.deflateSync) { hasSyncZlib = false; } -var SyncReader = require('./sync-reader'); -var FilterSync = require('./filter-parse-sync'); -var Parser = require('./parser'); -var bitmapper = require('./bitmapper'); -var formatNormaliser = require('./format-normaliser'); - - -module.exports = function(buffer, options) { +let SyncReader = require("./sync-reader"); +let FilterSync = require("./filter-parse-sync"); +let Parser = require("./parser"); +let bitmapper = require("./bitmapper"); +let formatNormaliser = require("./format-normaliser"); +module.exports = function (buffer, options) { if (!hasSyncZlib) { - throw new Error('To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0'); + throw new Error( + "To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0" + ); } - var err; + let err; function handleError(_err_) { err = _err_; } - var metaData; + let metaData; function handleMetaData(_metaData_) { metaData = _metaData_; } @@ -41,19 +41,19 @@ module.exports = function(buffer, options) { metaData.alpha = true; } - var gamma; + let gamma; function handleGamma(_gamma_) { gamma = _gamma_; } - var inflateDataList = []; + let inflateDataList = []; function handleInflateData(inflatedData) { inflateDataList.push(inflatedData); } - var reader = new SyncReader(buffer); + let reader = new SyncReader(buffer); - var parser = new Parser(options, { + let parser = new Parser(options, { read: reader.read.bind(reader), error: handleError, metadata: handleMetaData, @@ -61,7 +61,7 @@ module.exports = function(buffer, options) { palette: handlePalette, transColor: handleTransColor, inflateData: handleInflateData, - simpleTransparency: handleSimpleTransparency + simpleTransparency: handleSimpleTransparency, }); parser.start(); @@ -72,31 +72,34 @@ module.exports = function(buffer, options) { } //join together the inflate datas - var inflateData = Buffer.concat(inflateDataList); + let inflateData = Buffer.concat(inflateDataList); inflateDataList.length = 0; - var inflatedData; + let inflatedData; if (metaData.interlace) { inflatedData = zlib.inflateSync(inflateData); - } - else { - var rowSize = ((metaData.width * metaData.bpp * metaData.depth + 7) >> 3) + 1; - var imageSize = rowSize * metaData.height; - inflatedData = inflateSync(inflateData, { chunkSize: imageSize, maxLength: imageSize }); + } else { + let rowSize = + ((metaData.width * metaData.bpp * metaData.depth + 7) >> 3) + 1; + let imageSize = rowSize * metaData.height; + inflatedData = inflateSync(inflateData, { + chunkSize: imageSize, + maxLength: imageSize, + }); } inflateData = null; if (!inflatedData || !inflatedData.length) { - throw new Error('bad png - invalid inflate data response'); + throw new Error("bad png - invalid inflate data response"); } - var unfilteredData = FilterSync.process(inflatedData, metaData); + let unfilteredData = FilterSync.process(inflatedData, metaData); inflateData = null; - var bitmapData = bitmapper.dataToBitMap(unfilteredData, metaData); + let bitmapData = bitmapper.dataToBitMap(unfilteredData, metaData); unfilteredData = null; - var normalisedBitmapData = formatNormaliser(bitmapData, metaData); + let normalisedBitmapData = formatNormaliser(bitmapData, metaData); metaData.data = normalisedBitmapData; metaData.gamma = gamma || 0; diff --git a/lib/parser.js b/lib/parser.js index 21a8109..51a8f2a 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,11 +1,9 @@ -'use strict'; +"use strict"; -var constants = require('./constants'); -var CrcCalculator = require('./crc'); - - -var Parser = module.exports = function(options, dependencies) { +let constants = require("./constants"); +let CrcCalculator = require("./crc"); +let Parser = (module.exports = function (options, dependencies) { this._options = options; options.checkCRC = options.checkCRC !== false; @@ -35,49 +33,45 @@ var Parser = module.exports = function(options, dependencies) { this.inflateData = dependencies.inflateData; this.finished = dependencies.finished; this.simpleTransparency = dependencies.simpleTransparency; - this.headersFinished = dependencies.headersFinished || function() {}; + this.headersFinished = dependencies.headersFinished || function () {}; +}); + +Parser.prototype.start = function () { + this.read(constants.PNG_SIGNATURE.length, this._parseSignature.bind(this)); }; -Parser.prototype.start = function() { - this.read(constants.PNG_SIGNATURE.length, - this._parseSignature.bind(this) - ); -}; +Parser.prototype._parseSignature = function (data) { + let signature = constants.PNG_SIGNATURE; -Parser.prototype._parseSignature = function(data) { - - var signature = constants.PNG_SIGNATURE; - - for (var i = 0; i < signature.length; i++) { + for (let i = 0; i < signature.length; i++) { if (data[i] !== signature[i]) { - this.error(new Error('Invalid file signature')); + this.error(new Error("Invalid file signature")); return; } } this.read(8, this._parseChunkBegin.bind(this)); }; -Parser.prototype._parseChunkBegin = function(data) { - +Parser.prototype._parseChunkBegin = function (data) { // chunk content length - var length = data.readUInt32BE(0); + let length = data.readUInt32BE(0); // chunk type - var type = data.readUInt32BE(4); - var name = ''; - for (var i = 4; i < 8; i++) { + let type = data.readUInt32BE(4); + let name = ""; + for (let i = 4; i < 8; i++) { name += String.fromCharCode(data[i]); } //console.log('chunk ', name, length); // chunk flags - var ancillary = Boolean(data[4] & 0x20); // or critical + let ancillary = Boolean(data[4] & 0x20); // or critical // priv = Boolean(data[5] & 0x20), // or public // safeToCopy = Boolean(data[7] & 0x20); // or unsafe if (!this._hasIHDR && type !== constants.TYPE_IHDR) { - this.error(new Error('Expected IHDR on beggining')); + this.error(new Error("Expected IHDR on beggining")); return; } @@ -89,29 +83,28 @@ Parser.prototype._parseChunkBegin = function(data) { } if (!ancillary) { - this.error(new Error('Unsupported critical chunk type ' + name)); + this.error(new Error("Unsupported critical chunk type " + name)); return; } this.read(length + 4, this._skipChunk.bind(this)); }; -Parser.prototype._skipChunk = function(/*data*/) { +Parser.prototype._skipChunk = function (/*data*/) { this.read(8, this._parseChunkBegin.bind(this)); }; -Parser.prototype._handleChunkEnd = function() { +Parser.prototype._handleChunkEnd = function () { this.read(4, this._parseChunkEnd.bind(this)); }; -Parser.prototype._parseChunkEnd = function(data) { - - var fileCrc = data.readInt32BE(0); - var calcCrc = this._crc.crc32(); +Parser.prototype._parseChunkEnd = function (data) { + let fileCrc = data.readInt32BE(0); + let calcCrc = this._crc.crc32(); // check CRC if (this._options.checkCRC && calcCrc !== fileCrc) { - this.error(new Error('Crc error - ' + fileCrc + ' - ' + calcCrc)); + this.error(new Error("Crc error - " + fileCrc + " - " + calcCrc)); return; } @@ -120,50 +113,55 @@ Parser.prototype._parseChunkEnd = function(data) { } }; -Parser.prototype._handleIHDR = function(length) { +Parser.prototype._handleIHDR = function (length) { this.read(length, this._parseIHDR.bind(this)); }; -Parser.prototype._parseIHDR = function(data) { - +Parser.prototype._parseIHDR = function (data) { this._crc.write(data); - var width = data.readUInt32BE(0); - var height = data.readUInt32BE(4); - var depth = data[8]; - var colorType = data[9]; // bits: 1 palette, 2 color, 4 alpha - var compr = data[10]; - var filter = data[11]; - var interlace = data[12]; + let width = data.readUInt32BE(0); + let height = data.readUInt32BE(4); + let depth = data[8]; + let colorType = data[9]; // bits: 1 palette, 2 color, 4 alpha + let compr = data[10]; + let filter = data[11]; + let interlace = data[12]; // console.log(' width', width, 'height', height, // 'depth', depth, 'colorType', colorType, // 'compr', compr, 'filter', filter, 'interlace', interlace // ); - if (depth !== 8 && depth !== 4 && depth !== 2 && depth !== 1 && depth !== 16) { - this.error(new Error('Unsupported bit depth ' + depth)); + if ( + depth !== 8 && + depth !== 4 && + depth !== 2 && + depth !== 1 && + depth !== 16 + ) { + this.error(new Error("Unsupported bit depth " + depth)); return; } if (!(colorType in constants.COLORTYPE_TO_BPP_MAP)) { - this.error(new Error('Unsupported color type')); + this.error(new Error("Unsupported color type")); return; } if (compr !== 0) { - this.error(new Error('Unsupported compression method')); + this.error(new Error("Unsupported compression method")); return; } if (filter !== 0) { - this.error(new Error('Unsupported filter method')); + this.error(new Error("Unsupported filter method")); return; } if (interlace !== 0 && interlace !== 1) { - this.error(new Error('Unsupported interlace method')); + this.error(new Error("Unsupported interlace method")); return; } this._colorType = colorType; - var bpp = constants.COLORTYPE_TO_BPP_MAP[this._colorType]; + let bpp = constants.COLORTYPE_TO_BPP_MAP[this._colorType]; this._hasIHDR = true; @@ -176,30 +174,23 @@ Parser.prototype._parseIHDR = function(data) { color: Boolean(colorType & constants.COLORTYPE_COLOR), alpha: Boolean(colorType & constants.COLORTYPE_ALPHA), bpp: bpp, - colorType: colorType + colorType: colorType, }); this._handleChunkEnd(); }; - -Parser.prototype._handlePLTE = function(length) { +Parser.prototype._handlePLTE = function (length) { this.read(length, this._parsePLTE.bind(this)); }; -Parser.prototype._parsePLTE = function(data) { - +Parser.prototype._parsePLTE = function (data) { this._crc.write(data); - var entries = Math.floor(data.length / 3); + let entries = Math.floor(data.length / 3); // console.log('Palette:', entries); - for (var i = 0; i < entries; i++) { - this._palette.push([ - data[i * 3], - data[i * 3 + 1], - data[i * 3 + 2], - 0xff - ]); + for (let i = 0; i < entries; i++) { + this._palette.push([data[i * 3], data[i * 3 + 1], data[i * 3 + 2], 0xff]); } this.palette(this._palette); @@ -207,25 +198,24 @@ Parser.prototype._parsePLTE = function(data) { this._handleChunkEnd(); }; -Parser.prototype._handleTRNS = function(length) { +Parser.prototype._handleTRNS = function (length) { this.simpleTransparency(); this.read(length, this._parseTRNS.bind(this)); }; -Parser.prototype._parseTRNS = function(data) { - +Parser.prototype._parseTRNS = function (data) { this._crc.write(data); // palette if (this._colorType === constants.COLORTYPE_PALETTE_COLOR) { if (this._palette.length === 0) { - this.error(new Error('Transparency chunk must be after palette')); + this.error(new Error("Transparency chunk must be after palette")); return; } if (data.length > this._palette.length) { - this.error(new Error('More transparent colors than palette size')); + this.error(new Error("More transparent colors than palette size")); return; } - for (var i = 0; i < data.length; i++) { + for (let i = 0; i < data.length; i++) { this._palette[i][3] = data[i]; } this.palette(this._palette); @@ -238,54 +228,57 @@ Parser.prototype._parseTRNS = function(data) { this.transColor([data.readUInt16BE(0)]); } if (this._colorType === constants.COLORTYPE_COLOR) { - this.transColor([data.readUInt16BE(0), data.readUInt16BE(2), data.readUInt16BE(4)]); + this.transColor([ + data.readUInt16BE(0), + data.readUInt16BE(2), + data.readUInt16BE(4), + ]); } this._handleChunkEnd(); }; -Parser.prototype._handleGAMA = function(length) { +Parser.prototype._handleGAMA = function (length) { this.read(length, this._parseGAMA.bind(this)); }; -Parser.prototype._parseGAMA = function(data) { - +Parser.prototype._parseGAMA = function (data) { this._crc.write(data); this.gamma(data.readUInt32BE(0) / constants.GAMMA_DIVISION); this._handleChunkEnd(); }; -Parser.prototype._handleIDAT = function(length) { +Parser.prototype._handleIDAT = function (length) { if (!this._emittedHeadersFinished) { this._emittedHeadersFinished = true; this.headersFinished(); } this.read(-length, this._parseIDAT.bind(this, length)); }; -Parser.prototype._parseIDAT = function(length, data) { - +Parser.prototype._parseIDAT = function (length, data) { this._crc.write(data); - if (this._colorType === constants.COLORTYPE_PALETTE_COLOR && this._palette.length === 0) { - throw new Error('Expected palette not found'); + if ( + this._colorType === constants.COLORTYPE_PALETTE_COLOR && + this._palette.length === 0 + ) { + throw new Error("Expected palette not found"); } this.inflateData(data); - var leftOverLength = length - data.length; + let leftOverLength = length - data.length; if (leftOverLength > 0) { this._handleIDAT(leftOverLength); - } - else { + } else { this._handleChunkEnd(); } }; -Parser.prototype._handleIEND = function(length) { +Parser.prototype._handleIEND = function (length) { this.read(length, this._parseIEND.bind(this)); }; -Parser.prototype._parseIEND = function(data) { - +Parser.prototype._parseIEND = function (data) { this._crc.write(data); this._hasIEND = true; diff --git a/lib/png-sync.js b/lib/png-sync.js index 81d04a4..68cac9b 100644 --- a/lib/png-sync.js +++ b/lib/png-sync.js @@ -1,16 +1,12 @@ -'use strict'; +"use strict"; +let parse = require("./parser-sync"); +let pack = require("./packer-sync"); -var parse = require('./parser-sync'); -var pack = require('./packer-sync'); - - -exports.read = function(buffer, options) { - +exports.read = function (buffer, options) { return parse(buffer, options || {}); }; -exports.write = function(png, options) { - +exports.write = function (png, options) { return pack(png, options); }; diff --git a/lib/png.js b/lib/png.js index 8cf3988..0b8af3f 100644 --- a/lib/png.js +++ b/lib/png.js @@ -1,13 +1,12 @@ -'use strict'; +"use strict"; -var util = require('util'); -var Stream = require('stream'); -var Parser = require('./parser-async'); -var Packer = require('./packer-async'); -var PNGSync = require('./png-sync'); +let util = require("util"); +let Stream = require("stream"); +let Parser = require("./parser-async"); +let Packer = require("./packer-async"); +let PNGSync = require("./png-sync"); - -var PNG = exports.PNG = function(options) { +let PNG = (exports.PNG = function (options) { Stream.call(this); options = options || {}; // eslint-disable-line no-param-reassign @@ -16,8 +15,10 @@ var PNG = exports.PNG = function(options) { this.width = options.width | 0; this.height = options.height | 0; - this.data = this.width > 0 && this.height > 0 ? - Buffer.alloc(4 * this.width * this.height) : null; + this.data = + this.width > 0 && this.height > 0 + ? Buffer.alloc(4 * this.width * this.height) + : null; if (options.fill && this.data) { this.data.fill(0); @@ -28,95 +29,96 @@ var PNG = exports.PNG = function(options) { this._parser = new Parser(options); - this._parser.on('error', this.emit.bind(this, 'error')); - this._parser.on('close', this._handleClose.bind(this)); - this._parser.on('metadata', this._metadata.bind(this)); - this._parser.on('gamma', this._gamma.bind(this)); - this._parser.on('parsed', function(data) { - this.data = data; - this.emit('parsed', data); - }.bind(this)); + this._parser.on("error", this.emit.bind(this, "error")); + this._parser.on("close", this._handleClose.bind(this)); + this._parser.on("metadata", this._metadata.bind(this)); + this._parser.on("gamma", this._gamma.bind(this)); + this._parser.on( + "parsed", + function (data) { + this.data = data; + this.emit("parsed", data); + }.bind(this) + ); this._packer = new Packer(options); - this._packer.on('data', this.emit.bind(this, 'data')); - this._packer.on('end', this.emit.bind(this, 'end')); - this._parser.on('close', this._handleClose.bind(this)); - this._packer.on('error', this.emit.bind(this, 'error')); - -}; + this._packer.on("data", this.emit.bind(this, "data")); + this._packer.on("end", this.emit.bind(this, "end")); + this._parser.on("close", this._handleClose.bind(this)); + this._packer.on("error", this.emit.bind(this, "error")); +}); util.inherits(PNG, Stream); PNG.sync = PNGSync; -PNG.prototype.pack = function() { - +PNG.prototype.pack = function () { if (!this.data || !this.data.length) { - this.emit('error', 'No data provided'); + this.emit("error", "No data provided"); return this; } - process.nextTick(function() { - this._packer.pack(this.data, this.width, this.height, this.gamma); - }.bind(this)); + process.nextTick( + function () { + this._packer.pack(this.data, this.width, this.height, this.gamma); + }.bind(this) + ); return this; }; - -PNG.prototype.parse = function(data, callback) { - +PNG.prototype.parse = function (data, callback) { if (callback) { - var onParsed, onError; + let onParsed, onError; - onParsed = function(parsedData) { - this.removeListener('error', onError); + onParsed = function (parsedData) { + this.removeListener("error", onError); this.data = parsedData; callback(null, this); }.bind(this); - onError = function(err) { - this.removeListener('parsed', onParsed); + onError = function (err) { + this.removeListener("parsed", onParsed); callback(err, null); }.bind(this); - this.once('parsed', onParsed); - this.once('error', onError); + this.once("parsed", onParsed); + this.once("error", onError); } this.end(data); return this; }; -PNG.prototype.write = function(data) { +PNG.prototype.write = function (data) { this._parser.write(data); return true; }; -PNG.prototype.end = function(data) { +PNG.prototype.end = function (data) { this._parser.end(data); }; -PNG.prototype._metadata = function(metadata) { +PNG.prototype._metadata = function (metadata) { this.width = metadata.width; this.height = metadata.height; - this.emit('metadata', metadata); + this.emit("metadata", metadata); }; -PNG.prototype._gamma = function(gamma) { +PNG.prototype._gamma = function (gamma) { this.gamma = gamma; }; -PNG.prototype._handleClose = function() { +PNG.prototype._handleClose = function () { if (!this._parser.writable && !this._packer.readable) { - this.emit('close'); + this.emit("close"); } }; - -PNG.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) { // eslint-disable-line max-params +PNG.bitblt = function (src, dst, srcX, srcY, width, height, deltaX, deltaY) { + // eslint-disable-line max-params // coerce pixel dimensions to integers (also coerces undefined -> 0): /* eslint-disable no-param-reassign */ srcX |= 0; @@ -127,16 +129,27 @@ PNG.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) { // deltaY |= 0; /* eslint-enable no-param-reassign */ - if (srcX > src.width || srcY > src.height || srcX + width > src.width || srcY + height > src.height) { - throw new Error('bitblt reading outside image'); + if ( + srcX > src.width || + srcY > src.height || + srcX + width > src.width || + srcY + height > src.height + ) { + throw new Error("bitblt reading outside image"); } - if (deltaX > dst.width || deltaY > dst.height || deltaX + width > dst.width || deltaY + height > dst.height) { - throw new Error('bitblt writing outside image'); + if ( + deltaX > dst.width || + deltaY > dst.height || + deltaX + width > dst.width || + deltaY + height > dst.height + ) { + throw new Error("bitblt writing outside image"); } - for (var y = 0; y < height; y++) { - src.data.copy(dst.data, + for (let y = 0; y < height; y++) { + src.data.copy( + dst.data, ((deltaY + y) * dst.width + deltaX) << 2, ((srcY + y) * src.width + srcX) << 2, ((srcY + y) * src.width + srcX + width) << 2 @@ -144,21 +157,29 @@ PNG.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) { // } }; - -PNG.prototype.bitblt = function(dst, srcX, srcY, width, height, deltaX, deltaY) { // eslint-disable-line max-params +PNG.prototype.bitblt = function ( + dst, + srcX, + srcY, + width, + height, + deltaX, + deltaY +) { + // eslint-disable-line max-params PNG.bitblt(this, dst, srcX, srcY, width, height, deltaX, deltaY); return this; }; -PNG.adjustGamma = function(src) { +PNG.adjustGamma = function (src) { if (src.gamma) { - for (var y = 0; y < src.height; y++) { - for (var x = 0; x < src.width; x++) { - var idx = (src.width * y + x) << 2; + for (let y = 0; y < src.height; y++) { + for (let x = 0; x < src.width; x++) { + let idx = (src.width * y + x) << 2; - for (var i = 0; i < 3; i++) { - var sample = src.data[idx + i] / 255; + for (let i = 0; i < 3; i++) { + let sample = src.data[idx + i] / 255; sample = Math.pow(sample, 1 / 2.2 / src.gamma); src.data[idx + i] = Math.round(sample * 255); } @@ -168,6 +189,6 @@ PNG.adjustGamma = function(src) { } }; -PNG.prototype.adjustGamma = function() { +PNG.prototype.adjustGamma = function () { PNG.adjustGamma(this); }; diff --git a/lib/sync-inflate.js b/lib/sync-inflate.js index 87c19a1..4da0d5f 100644 --- a/lib/sync-inflate.js +++ b/lib/sync-inflate.js @@ -1,10 +1,10 @@ -'use strict'; +"use strict"; -var assert = require('assert').ok; -var zlib = require('zlib'); -var util = require('util'); +let assert = require("assert").ok; +let zlib = require("zlib"); +let util = require("util"); -var kMaxLength = require('buffer').kMaxLength; +let kMaxLength = require("buffer").kMaxLength; function Inflate(opts) { if (!(this instanceof Inflate)) { @@ -44,23 +44,23 @@ function _close(engine, callback) { engine._handle = null; } -Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { - if (typeof asyncCb === 'function') { +Inflate.prototype._processChunk = function (chunk, flushFlag, asyncCb) { + if (typeof asyncCb === "function") { return zlib.Inflate._processChunk.call(this, chunk, flushFlag, asyncCb); } - var self = this; + let self = this; - var availInBefore = chunk && chunk.length; - var availOutBefore = this._chunkSize - this._offset; - var leftToInflate = this._maxLength; - var inOff = 0; + let availInBefore = chunk && chunk.length; + let availOutBefore = this._chunkSize - this._offset; + let leftToInflate = this._maxLength; + let inOff = 0; - var buffers = []; - var nread = 0; + let buffers = []; + let nread = 0; - var error; - this.on('error', function(err) { + let error; + this.on("error", function (err) { error = err; }); @@ -69,11 +69,11 @@ Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { return; } - var have = availOutBefore - availOutAfter; - assert(have >= 0, 'have should not go down'); + let have = availOutBefore - availOutAfter; + assert(have >= 0, "have should not go down"); if (have > 0) { - var out = self._buffer.slice(self._offset, self._offset + have); + let out = self._buffer.slice(self._offset, self._offset + have); self._offset += have; if (out.length > leftToInflate) { @@ -96,7 +96,7 @@ Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { } if (availOutAfter === 0) { - inOff += (availInBefore - availInAfter); + inOff += availInBefore - availInAfter; availInBefore = availInAfter; return true; @@ -105,15 +105,18 @@ Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { return false; } - assert(this._handle, 'zlib binding closed'); + assert(this._handle, "zlib binding closed"); + let res; do { - var res = this._handle.writeSync(flushFlag, + res = this._handle.writeSync( + flushFlag, chunk, // in inOff, // in_off availInBefore, // in_len this._buffer, // out this._offset, //out_off - availOutBefore); // out_len + availOutBefore + ); // out_len // Node 8 --> 9 compatibility check res = res || this._writeState; } while (!this._hadError && handleChunk(res[0], res[1])); @@ -124,10 +127,14 @@ Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { if (nread >= kMaxLength) { _close(this); - throw new RangeError('Cannot create final Buffer. It would be larger than 0x' + kMaxLength.toString(16) + ' bytes'); + throw new RangeError( + "Cannot create final Buffer. It would be larger than 0x" + + kMaxLength.toString(16) + + " bytes" + ); } - var buf = Buffer.concat(buffers, nread); + let buf = Buffer.concat(buffers, nread); _close(this); return buf; @@ -136,14 +143,14 @@ Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) { util.inherits(Inflate, zlib.Inflate); function zlibBufferSync(engine, buffer) { - if (typeof buffer === 'string') { + if (typeof buffer === "string") { buffer = Buffer.from(buffer); } if (!(buffer instanceof Buffer)) { - throw new TypeError('Not a string or buffer'); + throw new TypeError("Not a string or buffer"); } - var flushFlag = engine._finishFlushFlag; + let flushFlag = engine._finishFlushFlag; if (flushFlag == null) { flushFlag = zlib.Z_FINISH; } diff --git a/lib/sync-reader.js b/lib/sync-reader.js index 70ee2db..15cbd4c 100644 --- a/lib/sync-reader.js +++ b/lib/sync-reader.js @@ -1,51 +1,45 @@ -'use strict'; - -var SyncReader = module.exports = function(buffer) { +"use strict"; +let SyncReader = (module.exports = function (buffer) { this._buffer = buffer; this._reads = []; -}; - -SyncReader.prototype.read = function(length, callback) { +}); +SyncReader.prototype.read = function (length, callback) { this._reads.push({ length: Math.abs(length), // if length < 0 then at most this length allowLess: length < 0, - func: callback + func: callback, }); }; -SyncReader.prototype.process = function() { - +SyncReader.prototype.process = function () { // as long as there is any data and read requests while (this._reads.length > 0 && this._buffer.length) { + let read = this._reads[0]; - var read = this._reads[0]; - - if (this._buffer.length && (this._buffer.length >= read.length || read.allowLess)) { - + if ( + this._buffer.length && + (this._buffer.length >= read.length || read.allowLess) + ) { // ok there is any data so that we can satisfy this request this._reads.shift(); // == read - var buf = this._buffer; + let buf = this._buffer; this._buffer = buf.slice(read.length); read.func.call(this, buf.slice(0, read.length)); - - } - else { + } else { break; } - } if (this._reads.length > 0) { - return new Error('There are some read requests waitng on finished stream'); + return new Error("There are some read requests waitng on finished stream"); } if (this._buffer.length > 0) { - return new Error('unrecognised content at end of stream'); + return new Error("unrecognised content at end of stream"); } - }; diff --git a/package.json b/package.json index 0234ca6..4dfd8c8 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "pngjs" ], "engines": { - "node": ">=8.0.0" + "node": ">=10.13.0" }, "main": "./lib/png.js", "directories": { @@ -39,14 +39,15 @@ "test": "test" }, "scripts": { - "build": "npm run prepublish", - "prepublish": "npm run browserify", + "build": "yarn prepublish", + "prepublish": "yarn browserify", "browserify": "browserify lib/png.js --standalone png > browser.js", - "coverage": "istanbul -- cover node_modules/tape/bin/tape test/*-spec.js nolarge", - "coverage-report": "npm run coverage && istanbul report html", + "coverage": "nyc tape test/*-spec.js nolarge", "coveralls": "cat ./coverage/lcov.info | coveralls", - "test": "npm run lint && tape test/*-spec.js | tap-dot && node test/run-compare", - "lint": "eslint lib" + "test": "yarn lint && yarn prettier:check && tape test/*-spec.js | tap-dot && node test/run-compare", + "lint": "eslint .", + "prettier:write": "prettier --write .", + "prettier:check": "prettier --check ." }, "repository": { "type": "git", @@ -57,14 +58,18 @@ "url": "https://github.com/lukeapage/pngjs2/issues" }, "devDependencies": { - "browserify": "^14.5.0", + "browserify": "16.5.1", "buffer-equal": "1.0.0", - "connect": "^3.4.0", - "eslint": "^5.15.2", - "istanbul": "^0.4.4", + "connect": "3.4.0", + "coveralls": "3.0.11", + "eslint": "5.15.2", + "eslint-config-prettier": "6.10.1", + "istanbul": "0.4.4", + "nyc": "15.0.1", + "prettier": "2.0.4", "puppeteer": "1.20.0", - "serve-static": "^1.10.0", - "tap-dot": "^2.0.0", - "tape": "^4.0.2" + "serve-static": "1.10.0", + "tap-dot": "2.0.0", + "tape": "4.0.2" } } diff --git a/test/bg-spec.js b/test/bg-spec.js index 7ece2cb..6fc0b0e 100644 --- a/test/bg-spec.js +++ b/test/bg-spec.js @@ -1,26 +1,24 @@ #!/usr/bin/env node -var fs = require('fs'); -var PNG = require('../lib/png').PNG; -var test = require('tape'); -var bufferEqual = require('buffer-equal'); - -test('outputs background, created from scratch', function (t) { +let fs = require("fs"); +let PNG = require("../lib/png").PNG; +let test = require("tape"); +let bufferEqual = require("buffer-equal"); +test("outputs background, created from scratch", function (t) { t.timeoutAfter(1000 * 60 * 5); - var png = new PNG({ + let png = new PNG({ width: 10, height: 10, - filterType: -1 + filterType: -1, }); + for (let y = 0; y < png.height; y++) { + for (let x = 0; x < png.width; x++) { + let idx = (png.width * y + x) << 2; - for (var y = 0; y < png.height; y++) { - for (var x = 0; x < png.width; x++) { - var idx = (png.width * y + x) << 2; - - var col = x < (png.width >> 1) ^ y < (png.height >> 1) ? 0xe5 : 0xff; + let col = (x < png.width >> 1) ^ (y < png.height >> 1) ? 0xe5 : 0xff; png.data[idx] = col; png.data[idx + 1] = col; @@ -29,13 +27,14 @@ test('outputs background, created from scratch', function (t) { } } - png.pack().pipe(fs.createWriteStream(__dirname + '/bg.png')) + png + .pack() + .pipe(fs.createWriteStream(__dirname + "/bg.png")) .on("finish", function () { + let out = fs.readFileSync(__dirname + "/bg.png"); + let ref = fs.readFileSync(__dirname + "/bg-ref.png"); - var out = fs.readFileSync(__dirname + '/bg.png'); - var ref = fs.readFileSync(__dirname + '/bg-ref.png'); - - var isBufferEqual = bufferEqual(out, ref); + let isBufferEqual = bufferEqual(out, ref); t.ok(isBufferEqual, "compares with working file ok"); if (!isBufferEqual) { diff --git a/test/convert-images-spec.js b/test/convert-images-spec.js index ec8d1e9..205520a 100644 --- a/test/convert-images-spec.js +++ b/test/convert-images-spec.js @@ -1,35 +1,44 @@ -var fs = require('fs'); -var PNG = require('../lib/png').PNG; -var test = require('tape'); +let fs = require("fs"); +let PNG = require("../lib/png").PNG; +let test = require("tape"); -var noLargeOption = process.argv.indexOf("nolarge") >= 0; +let noLargeOption = process.argv.indexOf("nolarge") >= 0; -fs.readdir(__dirname + '/in/', function (err, files) { +fs.readdir(__dirname + "/in/", function (err, files) { if (err) throw err; files = files.filter(function (file) { - return (!noLargeOption || !file.match(/large/i)) && Boolean(file.match(/\.png$/i)); + return ( + (!noLargeOption || !file.match(/large/i)) && + Boolean(file.match(/\.png$/i)) + ); }); console.log("Converting images"); files.forEach(function (file) { - - var expectedError = false; + let expectedError = false; if (file.match(/^x/)) { expectedError = true; } - test('convert sync - ' + file, function (t) { - + test("convert sync - " + file, function (t) { t.timeoutAfter(1000 * 60 * 5); - var data = fs.readFileSync(__dirname + '/in/' + file); + let data = fs.readFileSync(__dirname + "/in/" + file); + let png; try { - var png = PNG.sync.read(data); + png = PNG.sync.read(data); } catch (e) { if (!expectedError) { - t.fail('Unexpected error parsing..' + file + '\n' + e.message + "\n" + e.stack); + t.fail( + "Unexpected error parsing.." + + file + + "\n" + + e.message + + "\n" + + e.stack + ); } else { t.pass("completed"); } @@ -41,47 +50,55 @@ fs.readdir(__dirname + '/in/', function (err, files) { return t.end(); } - var outpng = new PNG(); + let outpng = new PNG(); outpng.gamma = png.gamma; outpng.data = png.data; outpng.width = png.width; outpng.height = png.height; - outpng.pack() - .pipe(fs.createWriteStream(__dirname + '/outsync/' + file) + outpng.pack().pipe( + fs + .createWriteStream(__dirname + "/outsync/" + file) .on("finish", function () { t.pass("completed"); t.end(); - })); + }) + ); }); - test('convert async - ' + file, function (t) { - + test("convert async - " + file, function (t) { t.timeoutAfter(1000 * 60 * 5); - fs.createReadStream(__dirname + '/in/' + file) + fs.createReadStream(__dirname + "/in/" + file) .pipe(new PNG()) - .on('error', function (err) { + .on("error", function (err) { if (!expectedError) { - t.fail("Async: Unexpected error parsing.." + file + '\n' + err.message + '\n' + err.stack); + t.fail( + "Async: Unexpected error parsing.." + + file + + "\n" + + err.message + + "\n" + + err.stack + ); } else { t.pass("completed"); } t.end(); }) - .on('parsed', function () { - + .on("parsed", function () { if (expectedError) { t.fail("Async: Error expected, parsed fine .." + file); return t.end(); } - this.pack() - .pipe( - fs.createWriteStream(__dirname + '/out/' + file) + this.pack().pipe( + fs + .createWriteStream(__dirname + "/out/" + file) .on("finish", function () { t.pass("completed"); t.end(); - })); + }) + ); }); }); }); diff --git a/test/http-server.js b/test/http-server.js index 711c87b..e888e92 100644 --- a/test/http-server.js +++ b/test/http-server.js @@ -1,14 +1,16 @@ -var serveStatic = require('serve-static'); -//var serveIndex = require('serve-index'); -var http = require('http'); -var connect = require('connect'); +let serveStatic = require("serve-static"); +let http = require("http"); +let connect = require("connect"); -var app = connect(); -server = http.createServer(app); +let app = connect(); +let server = http.createServer(app); -app.use(serveStatic('test')); -//app.use(serveIndex('test')); +app.use(serveStatic("test")); server.listen(8000); +module.exports = () => { + server.close(); +}; + console.log("Tests available at http://localhost:8000/"); diff --git a/test/index.html b/test/index.html index 2a523d0..47445c1 100644 --- a/test/index.html +++ b/test/index.html @@ -1,292 +1,999 @@ -
+
+
+
+
filter changing per
+ scanline, grayscale, 4 bit
+
+
+
+
no filtering, colour,
+ 8 bit
+
+
+
+
no filtering,
+ grayscale, 8 bit
+
+
+
+
filter 3, colour, 8
+ bit
+
+
+
+
filter 3, grayscale,
+ 8 bit
+
+
+
+
filter 2, colour, 8
+ bit
+
+
+
+
filter 2, grayscale,
+ 8 bit
+
+
+
+
filter 1, colour, 8
+ bit
+
+
+
+
filter 1, grayscale,
+ 8 bit
+
+
+
+
filter 0, colour, 8
+ bit
+
+
+
+
filter 0, grayscale,
+ 8 bit
+
filter changing per scanline, grayscale, 4 bit
no filtering, colour, 8 bit
no filtering, grayscale, 8 bit
filter 3, colour, 8 bit
filter 3, grayscale, 8 bit
filter 2, colour, 8 bit
filter 2, grayscale, 8 bit
filter 1, colour, 8 bit
filter 1, grayscale, 8 bit
filter 0, colour, 8 bit
filter 0, grayscale, 8 bit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
basn0g01 - black &
+ white
+
+
+
+
basn0g02 - 2 bit (4
+ level) grayscale
+
+
+
+
basn0g04 - 4 bit (16
+ level) grayscale
+
+
+
+
basn0g08 - 8 bit (256
+ level) grayscale
+
+
+
+
basn0g16 - 16 bit (64k
+ level) grayscale
+
+
+
+
basn2c08 - 3x8 bits
+ rgb color
+
+
+
+
basn2c16 - 3x16 bits
+ rgb color
+
+
+
+
basn3p01 - 1 bit (2
+ color) paletted
+
+
+
+
basn3p02 - 2 bit (4
+ color) paletted
+
+
+
+
basn3p04 - 4 bit (16
+ color) paletted
+
+
+
+
basn3p08 - 8 bit (256
+ color) paletted
+
+
+
+
basn4a08 - 8 bit
+ grayscale + 8 bit alpha-channel
+
+
+
+
basn4a16 - 16 bit
+ grayscale + 16 bit alpha-channel
+
+
+
+
basn6a08 - 3x8 bits
+ rgb color + 8 bit alpha-channel
+
+
+
+
basn6a16 - 3x16 bits
+ rgb color + 16 bit alpha-channel
+
basn0g01 - black & white
basn0g02 - 2 bit (4 level) grayscale
basn0g04 - 4 bit (16 level) grayscale
basn0g08 - 8 bit (256 level) grayscale
basn0g16 - 16 bit (64k level) grayscale
basn2c08 - 3x8 bits rgb color
basn2c16 - 3x16 bits rgb color
basn3p01 - 1 bit (2 color) paletted
basn3p02 - 2 bit (4 color) paletted
basn3p04 - 4 bit (16 color) paletted
basn3p08 - 8 bit (256 color) paletted
basn4a08 - 8 bit grayscale + 8 bit alpha-channel
basn4a16 - 16 bit grayscale + 16 bit alpha-channel
basn6a08 - 3x8 bits rgb color + 8 bit alpha-channel
basn6a16 - 3x16 bits rgb color + 16 bit alpha-channel
+
+
+
basi0g01 - black &
+ white
+
+
+
+
basi0g02 - 2 bit (4
+ level) grayscale
+
+
+
+
basi0g04 - 4 bit (16
+ level) grayscale
+
+
+
+
basi0g08 - 8 bit (256
+ level) grayscale
+
+
+
+
basi0g16 - 16 bit (64k
+ level) grayscale
+
+
+
+
basi2c08 - 3x8 bits
+ rgb color
+
+
+
+
basi2c16 - 3x16 bits
+ rgb color
+
basi0g01 - black & white
basi0g02 - 2 bit (4 level) grayscale
basi0g04 - 4 bit (16 level) grayscale
basi0g08 - 8 bit (256 level) grayscale
basi0g16 - 16 bit (64k level) grayscale
basi2c08 - 3x8 bits rgb color
basi2c16 - 3x16 bits rgb color
+
+
+
basi3p01 - 1 bit (2
+ color) paletted
+
+
+
+
basi3p02 - 2 bit (4
+ color) paletted
+
+
+
+
basi3p04 - 4 bit (16
+ color) paletted
+
+
+
+
basi3p08 - 8 bit (256
+ color) paletted
+
+
+
+
basi4a08 - 8 bit
+ grayscale + 8 bit alpha-channel
+
+
+
+
basi4a16 - 16 bit
+ grayscale + 16 bit alpha-channel
+
+
+
+
basi6a08 - 3x8 bits
+ rgb color + 8 bit alpha-channel
+
+
+
+
basi6a16 - 3x16 bits
+ rgb color + 16 bit alpha-channel
+
basi3p01 - 1 bit (2 color) paletted
basi3p02 - 2 bit (4 color) paletted
basi3p04 - 4 bit (16 color) paletted
basi3p08 - 8 bit (256 color) paletted
basi4a08 - 8 bit grayscale + 8 bit alpha-channel
basi4a16 - 16 bit grayscale + 16 bit alpha-channel
basi6a08 - 3x8 bits rgb color + 8 bit alpha-channel
basi6a16 - 3x16 bits rgb color + 16 bit alpha-channel
+
+
+
bgyn6a16 - 3x16 bits
+ rgb color, alpha, yellow background chunk
+
+
+
+
bgwn6a08 - 3x8 bits
+ rgb color, alpha, white background chunk
+
+
+
+
bggn4a16 - 16 bit
+ grayscale, alpha, gray background chunk
+
+
+
+
bgbn4a08 - 8 bit
+ grayscale, alpha, black background chunk
+
+
+
+
bgan6a16 - 3x16 bits
+ rgb color, alpha, no background chunk
+
+
+
+
bgan6a08 - 3x8 bits
+ rgb color, alpha, no background chunk
+
+
+
+
bgai4a16 - 16 bit
+ grayscale, alpha, no background chunk, interlaced
+
+
+
+
bgai4a08 - 8 bit
+ grayscale, alpha, no background chunk, interlaced
+
bgyn6a16 - 3x16 bits rgb color, alpha, yellow background chunk
bgwn6a08 - 3x8 bits rgb color, alpha, white background chunk
bggn4a16 - 16 bit grayscale, alpha, gray background chunk
bgbn4a08 - 8 bit grayscale, alpha, black background chunk
bgan6a16 - 3x16 bits rgb color, alpha, no background chunk
bgan6a08 - 3x8 bits rgb color, alpha, no background chunk
bgai4a16 - 16 bit grayscale, alpha, no background chunk, interlaced
bgai4a08 - 8 bit grayscale, alpha, no background chunk, interlaced
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+