diff --git a/README.md b/README.md index faf2c313..3bb753ab 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,14 @@ bwip-js is a translation to native JavaScript of the amazing code provided in [Barcode Writer in Pure PostScript](https://github.com/bwipp/postscriptbarcode). The translated code can run on any browser that natively supports the HTML canvas element or any JavaScript-based server framework that can implement a minimal bitmap graphics interface. -* Current bwipjs version is 0.10.4 +* Current bwipjs version is 0.10.5 * Current BWIPP version is 2015-03-24. +> +> 6-April-2015: The Node.js module is compatible with versions 0.10 and 0.12. +> + + bwip-js links: * [Home Page](http://metafloor.github.io/bwip-js/) diff --git a/node-bwipjs b/node-bwipjs index 320137ce..0e523c7c 100644 --- a/node-bwipjs +++ b/node-bwipjs @@ -58,14 +58,23 @@ var url = require('url'), zlibPNG = require(__dirname + '/node-zlibPNG') ; +// The global inside a sandboxed context appears almost useless. None of +// the goodies available in a primary context. // Emscripten uses the existence of require() and process to decide whether it is // running in node. And console is really nice to have. +// And it cannot run without all of the TypedArray constructors. var sandbox = vm.createContext({ require:require, process:process, console:console, - - // Emscripten makes it really hard to use as a library module + ArrayBuffer:ArrayBuffer, DataView:DataView, + Int8Array:Int8Array, Uint8Array:Uint8Array, + Uint8ClampedArray:Uint8ClampedArray, + Int16Array:Int16Array, Uint16Array:Uint16Array, + Int32Array:Int32Array, Uint32Array:Uint32Array, + Float32Array:Float32Array, Float64Array:Float64Array, + + // The .mem image makes it really hard to use as a library module Module:{ memoryInitializerPrefixURL : __dirname + '/' } }); diff --git a/node-zlibPNG b/node-zlibPNG index 2080c3ad..24643d89 100644 --- a/node-zlibPNG +++ b/node-zlibPNG @@ -56,14 +56,26 @@ module.exports = function (width, height) { height = height | 0; var TEXT = "Software\0bwip-js.metafloor.com"; - var _buffer = []; - var _palette = { 0:0 }; // palette[0] is always argb(0,0,0,0) + var _pixels = []; + var _palette = { 0:0 }; // Palette-0 is always black/background-color var _ncolors = 1; - var _cmap = []; // only if ncolors <= 256 + var _cmap = []; // Only if ncolors <= 256 + var _trans = false; // Has transparency? + var _ngray = 0; // Number of gray-set pixels + var _nset = 0; // Number of set pixels + // Set a pixel to the given RGB color + this.setRGB = function(x, y, c) { + this.set(x, y, (255<<24)|c); + } // Set a pixel to the given ARGB color this.set = function(x, y, c) { - _buffer[y * width + x] = c; + _pixels[y * width + x] = c; + + _nset++; + if (((c >> 16) & 0xff) == (c & 0xff) && ((c >> 8) & 0xff) == (c & 0xff)) + _ngray++; + _trans = _trans || (c >>> 24) < 255; // If we exceed 256 unique colors, we automatically switch to 32-bit // PNG (TrueColor with alpha) @@ -71,7 +83,7 @@ module.exports = function (width, height) { _palette[c] = _ncolors++; } this.get = function(x, y) { - return _buffer[y * width + x] || 0; + return _pixels[y * width + x] || 0; } // Return a PNG in a Buffer @@ -79,30 +91,46 @@ module.exports = function (width, height) { this.render = function(callback) { // DEFLATE the image data based on color depth var image; - if (_ncolors <= 256) + if (_ngray == _nset && !_trans) { + image = toGrayScale(); + } else if (_ncolors <= 256) { image = toPalette(); - else - image = toTrueColor(); + } else if (_ngray == _nset) { + image = toGrayAlpha(); + } else { + image = _trans ? toTrueAlpha() : toTrueColor(); + } + // v0.12 only... + //zlib.deflate(image, { + // chunkSize: 32 * 1024, + // level : zlib.Z_DEFAULT_COMPRESSION, + // strategy: zlib.Z_DEFAULT_STRATEGY + // }, returnPNG); - zlib.deflate(image, { + // v0.10+ compatible + var bufs = []; + var blen = 0; + var deflator = zlib.createDeflate({ chunkSize: 32 * 1024, level : zlib.Z_DEFAULT_COMPRESSION, - strategy: zlib.Z_DEFAULT_STRATEGY - }, returnPNG); - - function returnPNG(e, data) { - if (e) { - return callback(e, null); - } + strategy: zlib.Z_DEFAULT_STRATEGY }); + deflator.on('error', callback); + deflator.on('data', function(data) { bufs.push(data); blen += data.length; }); + deflator.on('end', function() { returnPNG(Buffer.concat(bufs, blen)); }); + deflator.end(image); + function returnPNG(data) { var length = 8 + 12 + 13 + // PNG Header + IDHR chunk 12 + TEXT.length + // tEXt 12 + data.length + // IDAT 12; // IEND - if (_ncolors <= 256) - length += 12 + 3*_ncolors + // PLTE - 12 + _ncolors; // tRNS - + if (_ngray == _nset && !_trans) { + // no extra chunks + } else if (_ncolors <= 256) { + length += 12 + 3*_ncolors; // PLTE + if (_trans) + length += 12 + _ncolors; // tRNS + } // Emulate a byte-stream var png = new Buffer(length); @@ -111,9 +139,12 @@ module.exports = function (width, height) { write('\x89PNG\x0d\x0a\x1a\x0a'); // PNG file header writeIHDR(); writeTEXT(); - if (_ncolors <= 256) { + if (_ngray == _nset && !_trans) { + // no extra chunks + } else if (_ncolors <= 256) { writePLTE(); - writeTRNS(); + if (_trans) + writeTRNS(); } writeIDAT(); writeIEND(); @@ -129,10 +160,17 @@ module.exports = function (width, height) { write32(width); write32(height); write8(8); // bit depth - if (_ncolors <= 256) - write8(3); // palette used, rgb used - else - write8(6); // rgb used, alpha used + if (_ngray == _nset && !_trans) { + write8(0); // grayscale + } else if (_ncolors <= 256) { + write8(3); // rgb palette + } else if (_ngrap == _nset) { + write8(4); // grayscale with alpha + } else if (_trans) { + write8(6); // truecolor with alpha + } else { + write8(2); // truecolor + } write8(0); // compression default write8(0); // filter default write8(0); // no interlace @@ -212,7 +250,36 @@ module.exports = function (width, height) { } } - + // Convert the image to grayscale + function toGrayScale() { + // One extra byte per row for the filter type + var buf = new Buffer((width + 1) * height); + var pos = 0; + for (var y = 0; y < height; y++) { + var row = y * width; + buf[pos++] = 0; // Row filters not implemented + for (var x = 0; x < width; x++) { + buf[pos++] = (_pixels[row + x] || 0) & 0xff; + } + } + return buf; + } + // Convert the image to grayscale with alpha + function toGrayAlpha() { + // One extra byte per row for the filter type + var buf = new Buffer((width * 2 + 1) * height); + var pos = 0; + for (var y = 0; y < height; y++) { + var row = y * width; + buf[pos++] = 0; // Row filters not implemented + for (var x = 0; x < width; x++) { + var c = _pixels[row + x] || 0; + buf[pos++] = c & 0xff; // gray + buf[pos++] = (c >>> 24) & 0xff; // alpha + } + } + return buf; + } // Convert the image data to indexed palette function toPalette() { // Convert the palette object to the color map @@ -227,13 +294,30 @@ module.exports = function (width, height) { var row = y * width; buf[pos++] = 0; // Row filters not implemented for (var x = 0; x < width; x++) { - buf[pos++] = _palette[_buffer[row + x] || 0]; + buf[pos++] = _palette[_pixels[row + x] || 0]; } } return buf; } - // Convert the image data to TrueColor with alpha + // Convert the image data to TrueColor function toTrueColor() { + // One extra byte per row for the filter type + var buf = new Buffer((width * 3 + 1) * height); + var pos = 0; + for (var y = 0; y < height; y++) { + var row = y * width; + buf[pos++] = 0; // Row filters not implemented + for (var x = 0; x < width; x++) { + var c = _pixels[row + x] || 0; + buf[pos++] = (c >>> 16) & 0xff; // red + buf[pos++] = (c >>> 8) & 0xff; // green + buf[pos++] = c & 0xff; // blue + } + } + return buf; + } + // Convert the image data to TrueColor with alpha + function toTrueAlpha() { // One extra byte per row for the filter type var buf = new Buffer((width * 4 + 1) * height); var pos = 0; @@ -241,7 +325,7 @@ module.exports = function (width, height) { var row = y * width; buf[pos++] = 0; // Row filters not implemented for (var x = 0; x < width; x++) { - var c = _buffer[row + x] || 0; + var c = _pixels[row + x] || 0; buf[pos++] = (c >>> 16) & 0xff; // red buf[pos++] = (c >>> 8) & 0xff; // green buf[pos++] = c & 0xff; // blue diff --git a/package.json b/package.json index a7948702..c19a0a08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bwip-js", - "version": "0.10.4", + "version": "0.10.5", "description": "Barcode Writer in Pure JavaScript", "main": "node-bwipjs", "scripts": {