Home Reference Source Test

src/pureimage.js

const Bitmap = require('./bitmap');
const fs     = require('fs');
const JPEG   = require('jpeg-js');
const PNG_LIB    = require('pngjs')
const PNG = PNG_LIB.PNG;
const text   = require('./text');
const uint32 = require('./uint32');

/**
 * Create a new bitmap image
 *
 * @param {number} w       Image width
 * @param {number} h       Image height
 * @param {object} options Options to be passed to {@link Bitmap}
 *
 * @returns {Bitmap}
 */
exports.make = function(w,h,options) {
    return new Bitmap(w,h,options);
};

/**
 * Encode the PNG image to output stream
 *
 * @param {Bitmap} bitmap    An instance of {@link Bitmap} to be encoded to PNG, `bitmap.data` must be a buffer of raw PNG data
 * @param {Stream} outstream The stream to write the PNG file to
 *
 * @returns {Promise<void>}
 */
exports.encodePNGToStream = function(bitmap, outstream) {
    return new Promise((res,rej)=>{
        if(!bitmap.hasOwnProperty('data') || !bitmap.hasOwnProperty('width') || !bitmap.hasOwnProperty('height')) {
            rej(new TypeError('Invalid bitmap image provided'));
        }
        var png = new PNG({
            width:bitmap.width,
            height:bitmap.height
        });

        for(var i=0; i<bitmap.width; i++) {
            for(var j=0; j<bitmap.height; j++) {
                var rgba = bitmap.getPixelRGBA(i,j);
                var n = (j*bitmap.width+i)*4;
                var bytes = uint32.getBytesBigEndian(rgba);
                for(var k=0; k<4; k++) {
                    png.data[n+k] = bytes[k];
                }
            }
        }

        png
            .on('error', (err) => { rej(err); })
            .pack()
            .pipe(outstream)
            .on('finish', () => { res(); })
            .on('error', (err) => { rej(err); });
    });
}

/**
 * Encode JPEG To Stream
 *
 * Encode the JPEG image to output stream
 *
 * @param {Bitmap} img       An instance of {@link Bitmap} to be encoded to JPEG, `img.data` must be a buffer of raw JPEG data
 * @param {Stream} outstream The stream to write the raw JPEG buffer to
 * @param {Int} Number between 0 and 100 setting the JPEG quality
 * @returns {Promise<void>}
 */
exports.encodeJPEGToStream = function(img, outstream, quality) {
    quality = quality || 90;
    return new Promise((res,rej)=> {
        if(!img.hasOwnProperty('data') || !img.hasOwnProperty('width') || !img.hasOwnProperty('height')) {
            rej(new TypeError('Invalid bitmap image provided'));
        }
        var data = {
            data: img.data,
            width: img.width,
            height: img.height
        };
        outstream.on('error', (err) => rej(err));
        outstream.write(JPEG.encode(data, quality).data, () => {
            outstream.end();
            res();
        });
    });
};

/**
 * Decode JPEG From Stream
 *
 * Decode a JPEG image from an incoming stream of data
 *
 * @param {Stream} data A readable stream to decode JPEG data from
 *
 * @returns {Promise<Bitmap>}
 */
exports.decodeJPEGFromStream = function(data) {
    return new Promise((res,rej)=>{
        try {
            var chunks = [];
            data.on('data', chunk => chunks.push(chunk));
            data.on('end',() => {
                var buf = Buffer.concat(chunks);
                var rawImageData = JPEG.decode(buf);
                var bitmap = new Bitmap(rawImageData.width, rawImageData.height);
                for (var x_axis = 0; x_axis < rawImageData.width; x_axis++) {
                    for (var y_axis = 0; y_axis < rawImageData.height; y_axis++) {
                        var n = (y_axis * rawImageData.width + x_axis) * 4;
                        bitmap.setPixelRGBA_i(x_axis, y_axis,
                            rawImageData.data[n + 0],
                            rawImageData.data[n + 1],
                            rawImageData.data[n + 2],
                            rawImageData.data[n + 3]
                        );
                    }
                }
                res(bitmap);
            });
            data.on("error", (err) => {
                rej(err);
            });
        } catch (e) {
            console.log(e);
            rej(e);
        }
    });
};

/**
 * Decode PNG From Stream
 *
 * Decode a PNG file from an incoming readable stream
 *
 * @param {Stream} instream A readable stream containing raw PNG data
 *
 * @returns {Promise<Bitmap>}
 */
exports.decodePNGFromStream = function(instream) {
    return new Promise((res,rej)=>{
        instream.pipe(new PNG())
            .on("parsed", function() {
                var bitmap =  new Bitmap(this.width,this.height);
                for(var i=0; i<bitmap.data.length; i++) {
                    bitmap.data[i] = this.data[i];
                };
                res(bitmap);
            }).on("error", function(err) {
                rej(err);
            });
    })
};

/**@ignore */
exports.registerFont = text.registerFont;