# All files packer.js

94.74% Statements 54/57
67.86% Branches 19/28
100% Functions 9/9
94.74% Lines 54/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130

    1x
    1x
    1x
    1x
    1x

    1x
    353x

    353x
    353x

    353x

    353x

    353x
    353x

    353x

    353x

    353x

    353x

    353x

    1x
    353x

    1x
    353x

    1x

    325x

    325x
    325x
    325x

    1x
    1592x
    1592x

    1592x
    1592x

    1592x
    1267x

    1592x

    1592x

    1x
    290x
    290x
    290x

    1x
    325x
    325x
    325x
    325x
    325x
    325x
    325x
    325x

    325x

    1x
    652x

    1x
    325x

     "use strict";

    let constants = require("./constants");
    let CrcStream = require("./crc");
    let bitPacker = require("./bitpacker");
    let filter = require("./filter-pack");
    let zlib = require("zlib");

    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.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;

      Iif (
        [
          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"
        );
      }
      Iif (
        [
          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"
        );
      }
      Iif (options.bitDepth !== 8 && options.bitDepth !== 16) {
        throw new Error(
          "option bit depth:" + options.bitDepth + " is not supported at present"
        );
      }
    });

    Packer.prototype.getDeflateOptions = function () {
      return {
        chunkSize: this._options.deflateChunkSize,
        level: this._options.deflateLevel,
        strategy: this._options.deflateStrategy,
      };
    };

    Packer.prototype.createDeflate = function () {
      return this._options.deflateFactory(this.getDeflateOptions());
    };

    Packer.prototype.filterData = function (data, width, height) {
      // convert to correct format for filtering (e.g. right bpp and bit depth)
      let packedData = bitPacker(data, width, height, this._options);

      // filter pixel data
      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) {
      let len = data ? data.length : 0;
      let buf = Buffer.alloc(len + 12);

      buf.writeUInt32BE(len, 0);
      buf.writeUInt32BE(type, 4);

      if (data) {
        data.copy(buf, 8);
      }

      buf.writeInt32BE(
        CrcStream.crc32(buf.slice(4, buf.length - 4)),
        buf.length - 4
      );
      return buf;
    };

    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) {
      let buf = Buffer.alloc(13);
      buf.writeUInt32BE(width, 0);
      buf.writeUInt32BE(height, 4);
      buf[8] = this._options.bitDepth; // Bit depth
      buf[9] = this._options.colorType; // colorType
      buf[10] = 0; // compression
      buf[11] = 0; // filter
      buf[12] = 0; // interlace

      return this._packChunk(constants.TYPE_IHDR, buf);
    };

    Packer.prototype.packIDAT = function (data) {
      return this._packChunk(constants.TYPE_IDAT, data);
    };

    Packer.prototype.packIEND = function () {
      return this._packChunk(constants.TYPE_IEND, null);
    };