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 interlace files
* 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
* API compatible with pngjs and node-pngjs
Known lack of support for:
* Extended PNG e.g. Animation
* Writing in different formats, colortype 0 (greyscale), colortype 3 (indexed color), colortype 4 (greyscale with alpha)
* Synchronous write
* Writing in colortype 3 (indexed color)
# 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
============
@ -63,6 +73,14 @@ Installation
$ 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
==========
```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)
- `deflateFactory` - deflate stream factory (default: `zlib.createDeflate`)
- `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).
- `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)
@ -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 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);
```

View file

@ -3,15 +3,19 @@
var constants = require('./constants');
module.exports = function(data, width, height, options) {
var outHasAlpha = options.colorType === constants.COLORTYPE_COLOR_ALPHA;
if (options.inputHasAlpha && outHasAlpha) {
return data;
}
if (!options.inputHasAlpha && !outHasAlpha) {
return data;
var outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(options.colorType) !== -1;
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) {
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 inBpp = options.inputHasAlpha ? 4 : 3;
var inIndex = 0;
@ -48,11 +52,25 @@ module.exports = function(data, width, height, options) {
alpha = 255;
}
outData[outIndex] = red;
outData[outIndex + 1] = green;
outData[outIndex + 2] = blue;
if (outHasAlpha) {
outData[outIndex + 3] = alpha;
switch (options.colorType) {
case constants.COLORTYPE_COLOR_ALPHA:
case constants.COLORTYPE_COLOR:
outData[outIndex] = red;
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;

View file

@ -15,9 +15,16 @@ var Packer = module.exports = function(options) {
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 = 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');
}
if (options.bitDepth !== 8) {
@ -74,7 +81,7 @@ Packer.prototype.packIHDR = function(width, height) {
var buf = new Buffer(13);
buf.writeUInt32BE(width, 0);
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[10] = 0; // compression
buf[11] = 0; // filter
@ -89,4 +96,4 @@ Packer.prototype.packIDAT = function(data) {
Packer.prototype.packIEND = function() {
return this._packChunk(constants.TYPE_IEND, null);
};
};

View file

@ -10,7 +10,7 @@ exports.read = function(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