Added support for encoding 8-bit grayscale images (colorType = 0 and 4) (#76)

* Added support for encoding 8-bit grayscale images (colorType = 4)

* Fixed unit tests, updated README

* [README.md] Added Browserify and TOC
This commit is contained in:
Eugene Kulabuhov 2017-04-30 12:45:27 +03:00 committed by Luke Page
parent 4c09644993
commit f28d2a9e02
5 changed files with 1745 additions and 22 deletions

View file

@ -11,15 +11,25 @@ Based on the original [pngjs](https://github.com/niegowski/node-pngjs) with the
* Support for reading 1,2,4 & 16 bit files * Support for reading 1,2,4 & 16 bit files
* Support for reading interlace files * Support for reading interlace files
* Support for reading `tTRNS` transparent colours * Support for reading `tTRNS` transparent colours
* Support for writing colortype 2 (RGB) and colortype 6 (RGBA) * Support for writing colortype 0 (grayscale), colortype 2 (RGB), colortype 4 (grayscale alpha) and colortype 6 (RGBA)
* Sync interface as well as async * Sync interface as well as async
* API compatible with pngjs and node-pngjs * API compatible with pngjs and node-pngjs
Known lack of support for: Known lack of support for:
* Extended PNG e.g. Animation * Extended PNG e.g. Animation
* Writing in different formats, colortype 0 (greyscale), colortype 3 (indexed color), colortype 4 (greyscale with alpha) * Writing in colortype 3 (indexed color)
* Synchronous write
# Table of Contents
* [Requirements](#requirements)
* [Comparison Table](#comparison-table)
* [Tests](#tests)
* [Installation](#installation)
* [Browserify](#browserify)
* [Example](#example)
* [Async API](#async-api)
* [Sync API](#sync-api)
* [Changelog](#changelog)
Requirements Requirements
============ ============
@ -63,6 +73,14 @@ Installation
$ npm install pngjs --save $ npm install pngjs --save
``` ```
Browserify
===========
Use [Browserify](browserify.org) to build a version of library that can run client-side:
```
$ browserify lib/png.js --standalone png > bundle.js
```
Then depending on your module system you can either `require('bundle.js')` or if you're not using module loader you can use plain old `<script src="bundle.js"></script>` tag and the library will be available under `window.PNG` or just `PNG`.
Example Example
========== ==========
```js ```js
@ -112,7 +130,7 @@ As input any color type is accepted (grayscale, rgb, palette, grayscale with alp
- `deflateStrategy` - compression strategy for delate (default: 3) - `deflateStrategy` - compression strategy for delate (default: 3)
- `deflateFactory` - deflate stream factory (default: `zlib.createDeflate`) - `deflateFactory` - deflate stream factory (default: `zlib.createDeflate`)
- `filterType` - png filtering method for scanlines (default: -1 => auto, accepts array of numbers 0-4) - `filterType` - png filtering method for scanlines (default: -1 => auto, accepts array of numbers 0-4)
- `colorType` - the output colorType - see constants. 2 = color, no alpha, 6 = color & alpha. Default currently 6, but in the future may calculate best mode. - `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.
- `inputHasAlpha` - whether the input bitmap has 4 bits per pixel (rgb and alpha) or 3 (rgb - no alpha). - `inputHasAlpha` - whether the input bitmap has 4 bits per pixel (rgb and alpha) or 3 (rgb - no alpha).
- `bgColor` - an object containing red, green, and blue values between 0 and 255 - `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)
@ -251,7 +269,8 @@ Take a PNG image and returns a buffer. The properties on the image include the m
``` ```
var data = fs.readFileSync('in.png'); var data = fs.readFileSync('in.png');
var png = PNG.sync.read(data); var png = PNG.sync.read(data);
var buffer = PNG.sync.write(png); var options = { colorType: 6 };
var buffer = PNG.sync.write(png, options);
fs.writeFileSync('out.png', buffer); fs.writeFileSync('out.png', buffer);
``` ```

View file

@ -3,15 +3,19 @@
var constants = require('./constants'); var constants = require('./constants');
module.exports = function(data, width, height, options) { module.exports = function(data, width, height, options) {
var outHasAlpha = options.colorType === constants.COLORTYPE_COLOR_ALPHA; var outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(options.colorType) !== -1;
if (options.inputHasAlpha && outHasAlpha) {
return data; if ([constants.COLORTYPE_GRAYSCALE, constants.COLORTYPE_ALPHA].indexOf(options.colorType) === -1) {
} // If no need to convert to grayscale and alpha is present/absent in both, take a fast route
if (!options.inputHasAlpha && !outHasAlpha) { if (options.inputHasAlpha && outHasAlpha) {
return data; return data;
}
if (!options.inputHasAlpha && !outHasAlpha) {
return data;
}
} }
var outBpp = outHasAlpha ? 4 : 3; var outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType];
var outData = new Buffer(width * height * outBpp); var outData = new Buffer(width * height * outBpp);
var inBpp = options.inputHasAlpha ? 4 : 3; var inBpp = options.inputHasAlpha ? 4 : 3;
var inIndex = 0; var inIndex = 0;
@ -48,11 +52,25 @@ module.exports = function(data, width, height, options) {
alpha = 255; alpha = 255;
} }
outData[outIndex] = red; switch (options.colorType) {
outData[outIndex + 1] = green; case constants.COLORTYPE_COLOR_ALPHA:
outData[outIndex + 2] = blue; case constants.COLORTYPE_COLOR:
if (outHasAlpha) { outData[outIndex] = red;
outData[outIndex + 3] = alpha; outData[outIndex + 1] = green;
outData[outIndex + 2] = blue;
if (outHasAlpha) {
outData[outIndex + 3] = alpha;
}
break;
case constants.COLORTYPE_ALPHA:
case constants.COLORTYPE_GRAYSCALE:
// Convert to grayscale and alpha
var grayscale = (red + green + blue) / 3;
outData[outIndex] = grayscale;
if (outHasAlpha) {
outData[outIndex + 1] = alpha;
}
break;
} }
inIndex += inBpp; inIndex += inBpp;

View file

@ -15,9 +15,16 @@ var Packer = module.exports = function(options) {
options.inputHasAlpha = options.inputHasAlpha != null ? options.inputHasAlpha : true; options.inputHasAlpha = options.inputHasAlpha != null ? options.inputHasAlpha : true;
options.deflateFactory = options.deflateFactory || zlib.createDeflate; options.deflateFactory = options.deflateFactory || zlib.createDeflate;
options.bitDepth = options.bitDepth || 8; options.bitDepth = options.bitDepth || 8;
// This is outputColorType
options.colorType = (typeof options.colorType === 'number') ? options.colorType : constants.COLORTYPE_COLOR_ALPHA; options.colorType = (typeof options.colorType === 'number') ? options.colorType : constants.COLORTYPE_COLOR_ALPHA;
options.inputColorType = options.inputColorType || constants.COLORTYPE_COLOR_ALPHA;
if (options.colorType !== constants.COLORTYPE_COLOR && options.colorType !== 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'); throw new Error('option color type:' + options.colorType + ' is not supported at present');
} }
if (options.bitDepth !== 8) { if (options.bitDepth !== 8) {
@ -74,7 +81,7 @@ Packer.prototype.packIHDR = function(width, height) {
var buf = new Buffer(13); var buf = new Buffer(13);
buf.writeUInt32BE(width, 0); buf.writeUInt32BE(width, 0);
buf.writeUInt32BE(height, 4); buf.writeUInt32BE(height, 4);
buf[8] = this._options.bitDepth; // Bit depth buf[8] = this._options.bitDepth; // Bit depth
buf[9] = this._options.colorType; // colorType buf[9] = this._options.colorType; // colorType
buf[10] = 0; // compression buf[10] = 0; // compression
buf[11] = 0; // filter buf[11] = 0; // filter

View file

@ -10,7 +10,7 @@ exports.read = function(buffer, options) {
return parse(buffer, options || {}); return parse(buffer, options || {});
}; };
exports.write = function(png) { exports.write = function(png, options) {
return pack(png); return pack(png, options);
}; };

1679
yarn.lock Normal file

File diff suppressed because it is too large Load diff