@dereekb/firebase-server 13.25.1 → 13.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,8 @@ import { Optional, Inject, Injectable, Module, Global } from '@nestjs/common';
7
7
  import { ConfigModule } from '@nestjs/config';
8
8
  import { BaseError } from 'make-error';
9
9
  import sharp from 'sharp';
10
- import { PDFName, PDFDocument, PDFRawStream, PDFArray } from '@cantoo/pdf-lib';
10
+ import { inflateSync } from 'node:zlib';
11
+ import { PDFName, PDFDocument, PDFRawStream, PDFArray, PDFNumber, PDFStream, PDFDict, PDFRef } from '@cantoo/pdf-lib';
11
12
  import archiver from 'archiver';
12
13
 
13
14
  function _array_like_to_array$a(arr, len) {
@@ -8243,7 +8244,7 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8243
8244
  * ```
8244
8245
  */ function compressImageBufferToTargetSize(input, config) {
8245
8246
  return _async_to_generator$6(function() {
8246
- var _config_maxDimension, _config_initialQuality, _config_minQuality, _config_qualityStep, _config_format, _metadata_width, _metadata_height, targetSizeBytes, maxDimension, initialQuality, minQuality, qualityStep, format, metadata, originalWidth, originalHeight, originalSizeBytes, longestSide, resizeNeeded, scale, workingWidth, workingHeight, bestBuffer, bestSize, bestQuality, bestWidth, bestHeight, hitTarget, qualities, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, quality, encoded, err, result;
8247
+ var _config_maxDimension, _config_initialQuality, _config_minQuality, _config_qualityStep, _config_format, _config_rawPixelInput, _ref, _ref1, _ref2, _ref3, targetSizeBytes, maxDimension, initialQuality, minQuality, qualityStep, format, rawPixelInput, inputMetadata, _tmp, originalWidth, originalHeight, originalSizeBytes, longestSide, resizeNeeded, scale, workingWidth, workingHeight, bestBuffer, bestSize, bestQuality, bestWidth, bestHeight, hitTarget, qualities, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, quality, encoded, err, finalChannels, _ref4, _ref5, _channels, result;
8247
8248
  return _ts_generator$6(this, function(_state) {
8248
8249
  switch(_state.label){
8249
8250
  case 0:
@@ -8253,14 +8254,28 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8253
8254
  minQuality = (_config_minQuality = config.minQuality) !== null && _config_minQuality !== void 0 ? _config_minQuality : DEFAULT_COMPRESS_IMAGE_MIN_QUALITY;
8254
8255
  qualityStep = (_config_qualityStep = config.qualityStep) !== null && _config_qualityStep !== void 0 ? _config_qualityStep : DEFAULT_COMPRESS_IMAGE_QUALITY_STEP;
8255
8256
  format = (_config_format = config.format) !== null && _config_format !== void 0 ? _config_format : DEFAULT_COMPRESS_IMAGE_FORMAT;
8257
+ rawPixelInput = (_config_rawPixelInput = config.rawPixelInput) !== null && _config_rawPixelInput !== void 0 ? _config_rawPixelInput : undefined;
8258
+ if (!(rawPixelInput == null)) return [
8259
+ 3,
8260
+ 2
8261
+ ];
8256
8262
  return [
8257
8263
  4,
8258
8264
  sharp(input).metadata()
8259
8265
  ];
8260
8266
  case 1:
8261
- metadata = _state.sent();
8262
- originalWidth = (_metadata_width = metadata.width) !== null && _metadata_width !== void 0 ? _metadata_width : 0;
8263
- originalHeight = (_metadata_height = metadata.height) !== null && _metadata_height !== void 0 ? _metadata_height : 0;
8267
+ _tmp = _state.sent();
8268
+ return [
8269
+ 3,
8270
+ 3
8271
+ ];
8272
+ case 2:
8273
+ _tmp = undefined;
8274
+ _state.label = 3;
8275
+ case 3:
8276
+ inputMetadata = _tmp;
8277
+ originalWidth = (_ref = (_ref1 = rawPixelInput === null || rawPixelInput === void 0 ? void 0 : rawPixelInput.width) !== null && _ref1 !== void 0 ? _ref1 : inputMetadata === null || inputMetadata === void 0 ? void 0 : inputMetadata.width) !== null && _ref !== void 0 ? _ref : 0;
8278
+ originalHeight = (_ref2 = (_ref3 = rawPixelInput === null || rawPixelInput === void 0 ? void 0 : rawPixelInput.height) !== null && _ref3 !== void 0 ? _ref3 : inputMetadata === null || inputMetadata === void 0 ? void 0 : inputMetadata.height) !== null && _ref2 !== void 0 ? _ref2 : 0;
8264
8279
  originalSizeBytes = input.byteLength;
8265
8280
  longestSide = Math.max(originalWidth, originalHeight);
8266
8281
  resizeNeeded = longestSide > maxDimension && longestSide > 0;
@@ -8268,14 +8283,15 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8268
8283
  workingWidth = Math.max(1, Math.round(originalWidth * scale));
8269
8284
  workingHeight = Math.max(1, Math.round(originalHeight * scale));
8270
8285
  bestBuffer = input;
8271
- bestSize = originalSizeBytes;
8286
+ // raw input must always be re-encoded, so no encoding is compared against the raw byte size
8287
+ bestSize = rawPixelInput == null ? originalSizeBytes : Number.MAX_SAFE_INTEGER;
8272
8288
  bestQuality = 100;
8273
8289
  bestWidth = originalWidth;
8274
8290
  bestHeight = originalHeight;
8275
- hitTarget = bestSize <= targetSizeBytes && !resizeNeeded;
8291
+ hitTarget = rawPixelInput == null && bestSize <= targetSizeBytes && !resizeNeeded;
8276
8292
  if (!!hitTarget) return [
8277
8293
  3,
8278
- 9
8294
+ 11
8279
8295
  ];
8280
8296
  qualities = qualityIterationSteps({
8281
8297
  format: format,
@@ -8284,20 +8300,20 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8284
8300
  qualityStep: qualityStep
8285
8301
  });
8286
8302
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
8287
- _state.label = 2;
8288
- case 2:
8303
+ _state.label = 4;
8304
+ case 4:
8289
8305
  _state.trys.push([
8290
- 2,
8291
- 7,
8292
- 8,
8293
- 9
8306
+ 4,
8307
+ 9,
8308
+ 10,
8309
+ 11
8294
8310
  ]);
8295
8311
  _iterator = qualities[Symbol.iterator]();
8296
- _state.label = 3;
8297
- case 3:
8312
+ _state.label = 5;
8313
+ case 5:
8298
8314
  if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
8299
8315
  3,
8300
- 6
8316
+ 8
8301
8317
  ];
8302
8318
  quality = _step.value;
8303
8319
  return [
@@ -8308,10 +8324,11 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8308
8324
  quality: quality,
8309
8325
  resizeNeeded: resizeNeeded,
8310
8326
  workingWidth: workingWidth,
8311
- workingHeight: workingHeight
8327
+ workingHeight: workingHeight,
8328
+ rawPixelInput: rawPixelInput
8312
8329
  })
8313
8330
  ];
8314
- case 4:
8331
+ case 6:
8315
8332
  encoded = _state.sent();
8316
8333
  if (encoded.byteLength < bestSize) {
8317
8334
  bestBuffer = encoded;
@@ -8324,30 +8341,30 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8324
8341
  hitTarget = true;
8325
8342
  return [
8326
8343
  3,
8327
- 6
8344
+ 8
8328
8345
  ];
8329
8346
  }
8330
- _state.label = 5;
8331
- case 5:
8347
+ _state.label = 7;
8348
+ case 7:
8332
8349
  _iteratorNormalCompletion = true;
8333
8350
  return [
8334
8351
  3,
8335
- 3
8352
+ 5
8336
8353
  ];
8337
- case 6:
8354
+ case 8:
8338
8355
  return [
8339
8356
  3,
8340
- 9
8357
+ 11
8341
8358
  ];
8342
- case 7:
8359
+ case 9:
8343
8360
  err = _state.sent();
8344
8361
  _didIteratorError = true;
8345
8362
  _iteratorError = err;
8346
8363
  return [
8347
8364
  3,
8348
- 9
8365
+ 11
8349
8366
  ];
8350
- case 8:
8367
+ case 10:
8351
8368
  try {
8352
8369
  if (!_iteratorNormalCompletion && _iterator.return != null) {
8353
8370
  _iterator.return();
@@ -8360,14 +8377,33 @@ var DEFAULT_COMPRESS_IMAGE_FORMAT = 'jpeg';
8360
8377
  return [
8361
8378
  7
8362
8379
  ];
8363
- case 9:
8380
+ case 11:
8381
+ if (!(bestBuffer === input)) return [
8382
+ 3,
8383
+ 12
8384
+ ];
8385
+ finalChannels = (_ref4 = (_ref5 = rawPixelInput === null || rawPixelInput === void 0 ? void 0 : rawPixelInput.channels) !== null && _ref5 !== void 0 ? _ref5 : inputMetadata === null || inputMetadata === void 0 ? void 0 : inputMetadata.channels) !== null && _ref4 !== void 0 ? _ref4 : 0;
8386
+ return [
8387
+ 3,
8388
+ 14
8389
+ ];
8390
+ case 12:
8391
+ return [
8392
+ 4,
8393
+ sharp(bestBuffer).metadata()
8394
+ ];
8395
+ case 13:
8396
+ finalChannels = (_channels = _state.sent().channels) !== null && _channels !== void 0 ? _channels : 0;
8397
+ _state.label = 14;
8398
+ case 14:
8364
8399
  result = {
8365
8400
  buffer: bestBuffer,
8366
8401
  originalSizeBytes: originalSizeBytes,
8367
- compressedSizeBytes: bestSize,
8402
+ compressedSizeBytes: bestBuffer.byteLength,
8368
8403
  finalQuality: bestQuality,
8369
8404
  finalWidth: bestWidth,
8370
8405
  finalHeight: bestHeight,
8406
+ finalChannels: finalChannels,
8371
8407
  hitTarget: hitTarget
8372
8408
  };
8373
8409
  return [
@@ -8393,11 +8429,17 @@ function qualityIterationSteps(input) {
8393
8429
  }
8394
8430
  function encodeImage(input) {
8395
8431
  return _async_to_generator$6(function() {
8396
- var pipeline, result, _;
8432
+ var _input_rawPixelInput, pipeline, result, _;
8397
8433
  return _ts_generator$6(this, function(_state) {
8398
8434
  switch(_state.label){
8399
8435
  case 0:
8400
- pipeline = sharp(input.input);
8436
+ pipeline = input.rawPixelInput == null ? sharp(input.input) : sharp(input.input, {
8437
+ raw: input.rawPixelInput
8438
+ });
8439
+ // grayscale raw input stays grayscale — sharp otherwise converts raw pipelines to sRGB on encode
8440
+ if (((_input_rawPixelInput = input.rawPixelInput) === null || _input_rawPixelInput === void 0 ? void 0 : _input_rawPixelInput.channels) === 1) {
8441
+ pipeline.toColourspace('b-w');
8442
+ }
8401
8443
  if (input.resizeNeeded) {
8402
8444
  pipeline.resize({
8403
8445
  width: input.workingWidth,
@@ -8666,10 +8708,15 @@ var DEFAULT_COMPRESS_PDF_IMAGE_SIZE_THRESHOLD_BYTES = 100 * 1024;
8666
8708
  /**
8667
8709
  * Recompresses image XObjects embedded in a PDF to shrink its overall size.
8668
8710
  *
8669
- * Only DCTDecode (JPEG) image streams are touched in this implementation — the
8670
- * dominant case for "phone photo PDFs". Images using other filters (FlateDecode,
8671
- * CCITTFax, JBIG2, JPEG2000), indexed/CMYK color spaces, or that carry a
8672
- * `/SMask` (soft mask) are skipped and counted in `imagesSkipped`.
8711
+ * Two stream kinds are recompressed to JPEG (DCTDecode):
8712
+ * - DCTDecode (JPEG) image streams — the dominant case for "phone photo PDFs".
8713
+ * - FlateDecode raster image streams (zlib-deflated raw pixels, 8 bits per
8714
+ * component, DeviceRGB/DeviceGray/CalRGB/CalGray/ICCBased color spaces, with
8715
+ * optional PNG/TIFF predictors) — the dominant case for scanner-produced PDFs.
8716
+ *
8717
+ * Images using other filters (CCITTFax, JBIG2, JPEG2000), indexed/CMYK/other
8718
+ * color spaces, non-8-bit rasters, or that carry a `/SMask` or `/Mask` are
8719
+ * skipped and counted in `imagesSkipped`.
8673
8720
  *
8674
8721
  * Throws on a malformed PDF — callers should catch and fall back to the original
8675
8722
  * bytes.
@@ -8826,7 +8873,7 @@ var DEFAULT_COMPRESS_PDF_IMAGE_SIZE_THRESHOLD_BYTES = 100 * 1024;
8826
8873
  }
8827
8874
  function processPdfStream(input) {
8828
8875
  return _async_to_generator$5(function() {
8829
- var pdfDoc, ref, obj, counters, imageMaxDimension, imageQuality, imageSizeThresholdBytes, _counters_imageStreamsByFilter_filterKey, filterKey, compressedImage;
8876
+ var pdfDoc, ref, obj, counters, imageMaxDimension, imageQuality, imageSizeThresholdBytes, _counters_imageStreamsByFilter_filterKey, filterKey, streamType, compressedImage, decoded;
8830
8877
  return _ts_generator$5(this, function(_state) {
8831
8878
  switch(_state.label){
8832
8879
  case 0:
@@ -8836,7 +8883,8 @@ function processPdfStream(input) {
8836
8883
  filterKey = imageStreamFilterKey(obj);
8837
8884
  counters.imageStreamsByFilter[filterKey] = ((_counters_imageStreamsByFilter_filterKey = counters.imageStreamsByFilter[filterKey]) !== null && _counters_imageStreamsByFilter_filterKey !== void 0 ? _counters_imageStreamsByFilter_filterKey : 0) + 1;
8838
8885
  }
8839
- if (!isCompressibleImageStream(obj)) {
8886
+ streamType = compressibleImageStreamType(obj);
8887
+ if (streamType == null) {
8840
8888
  return [
8841
8889
  2
8842
8890
  ];
@@ -8850,10 +8898,14 @@ function processPdfStream(input) {
8850
8898
  case 1:
8851
8899
  _state.trys.push([
8852
8900
  1,
8853
- 3,
8901
+ 7,
8854
8902
  ,
8855
- 4
8903
+ 8
8856
8904
  ]);
8905
+ if (!(streamType === 'jpeg')) return [
8906
+ 3,
8907
+ 3
8908
+ ];
8857
8909
  return [
8858
8910
  4,
8859
8911
  compressImageBufferToTargetSize(Buffer.from(obj.contents), {
@@ -8865,7 +8917,41 @@ function processPdfStream(input) {
8865
8917
  ];
8866
8918
  case 2:
8867
8919
  compressedImage = _state.sent();
8868
- if (compressedImage.compressedSizeBytes >= obj.contents.byteLength) {
8920
+ return [
8921
+ 3,
8922
+ 6
8923
+ ];
8924
+ case 3:
8925
+ decoded = decodeFlateRasterImage(pdfDoc, obj);
8926
+ if (!(decoded == null)) return [
8927
+ 3,
8928
+ 4
8929
+ ];
8930
+ counters.imagesSkipped += 1; // unsupported raster layout (color space, bit depth, predictor, or decode array)
8931
+ return [
8932
+ 3,
8933
+ 6
8934
+ ];
8935
+ case 4:
8936
+ return [
8937
+ 4,
8938
+ compressImageBufferToTargetSize(decoded.data, {
8939
+ targetSizeBytes: obj.contents.byteLength,
8940
+ maxDimension: imageMaxDimension,
8941
+ initialQuality: imageQuality,
8942
+ format: 'jpeg',
8943
+ rawPixelInput: {
8944
+ width: decoded.width,
8945
+ height: decoded.height,
8946
+ channels: decoded.channels
8947
+ }
8948
+ })
8949
+ ];
8950
+ case 5:
8951
+ compressedImage = _state.sent();
8952
+ _state.label = 6;
8953
+ case 6:
8954
+ if (compressedImage == null || compressedImage.compressedSizeBytes >= obj.contents.byteLength) {
8869
8955
  return [
8870
8956
  2
8871
8957
  ]; // no gain — leave it alone
@@ -8875,21 +8961,22 @@ function processPdfStream(input) {
8875
8961
  ref: ref,
8876
8962
  newImageBytes: compressedImage.buffer,
8877
8963
  newWidth: compressedImage.finalWidth,
8878
- newHeight: compressedImage.finalHeight
8964
+ newHeight: compressedImage.finalHeight,
8965
+ colorSpace: compressedImage.finalChannels === 1 ? 'DeviceGray' : 'DeviceRGB'
8879
8966
  });
8880
8967
  counters.imagesCompressed += 1;
8881
8968
  return [
8882
8969
  3,
8883
- 4
8970
+ 8
8884
8971
  ];
8885
- case 3:
8972
+ case 7:
8886
8973
  _state.sent();
8887
8974
  counters.imagesSkipped += 1;
8888
8975
  return [
8889
8976
  3,
8890
- 4
8977
+ 8
8891
8978
  ];
8892
- case 4:
8979
+ case 8:
8893
8980
  return [
8894
8981
  2
8895
8982
  ];
@@ -8933,11 +9020,28 @@ var PDF_NAME_SUBTYPE = PDFName.of('Subtype');
8933
9020
  var PDF_NAME_IMAGE = PDFName.of('Image');
8934
9021
  var PDF_NAME_FILTER = PDFName.of('Filter');
8935
9022
  var PDF_NAME_DCTDECODE = PDFName.of('DCTDecode');
9023
+ var PDF_NAME_FLATEDECODE = PDFName.of('FlateDecode');
8936
9024
  var PDF_NAME_SMASK = PDFName.of('SMask');
8937
9025
  var PDF_NAME_MASK = PDFName.of('Mask');
8938
- function isCompressibleImageStream(stream) {
9026
+ var PDF_NAME_WIDTH = PDFName.of('Width');
9027
+ var PDF_NAME_HEIGHT = PDFName.of('Height');
9028
+ var PDF_NAME_BITS_PER_COMPONENT = PDFName.of('BitsPerComponent');
9029
+ var PDF_NAME_COLOR_SPACE = PDFName.of('ColorSpace');
9030
+ var PDF_NAME_DECODE = PDFName.of('Decode');
9031
+ var PDF_NAME_IMAGE_MASK = PDFName.of('ImageMask');
9032
+ var PDF_NAME_DECODE_PARMS = PDFName.of('DecodeParms');
9033
+ var PDF_NAME_PREDICTOR = PDFName.of('Predictor');
9034
+ var PDF_NAME_COLORS = PDFName.of('Colors');
9035
+ var PDF_NAME_COLUMNS = PDFName.of('Columns');
9036
+ var PDF_NAME_DEVICE_RGB = PDFName.of('DeviceRGB');
9037
+ var PDF_NAME_DEVICE_GRAY = PDFName.of('DeviceGray');
9038
+ var PDF_NAME_CAL_RGB = PDFName.of('CalRGB');
9039
+ var PDF_NAME_CAL_GRAY = PDFName.of('CalGray');
9040
+ var PDF_NAME_ICC_BASED = PDFName.of('ICCBased');
9041
+ var PDF_NAME_N = PDFName.of('N');
9042
+ function compressibleImageStreamType(stream) {
8939
9043
  var dict = stream.dict;
8940
- var result = false;
9044
+ var result;
8941
9045
  // Must be Type /XObject (when present) and Subtype /Image
8942
9046
  var type = dict.get(PDF_NAME_TYPE);
8943
9047
  var typeOk = type === undefined || pdfNameEquals(type, PDF_NAME_XOBJECT);
@@ -8947,13 +9051,15 @@ function isCompressibleImageStream(stream) {
8947
9051
  // Skip images with masks; replacing them risks breaking the mask alignment.
8948
9052
  var hasMask = dict.get(PDF_NAME_SMASK) !== undefined || dict.get(PDF_NAME_MASK) !== undefined;
8949
9053
  if (subtypeOk && !hasMask) {
8950
- // Only DCTDecode (JPEG) streams in v1.
8951
9054
  var filter = dict.get(PDF_NAME_FILTER);
8952
- if (filter !== undefined) {
8953
- if (_instanceof$1(filter, PDFArray)) {
8954
- result = filter.size() === 1 && pdfNameEquals(filter.get(0), PDF_NAME_DCTDECODE);
8955
- } else {
8956
- result = pdfNameEquals(filter, PDF_NAME_DCTDECODE);
9055
+ if (_instanceof$1(filter, PDFArray) && filter.size() === 1) {
9056
+ filter = filter.get(0);
9057
+ }
9058
+ if (_instanceof$1(filter, PDFName)) {
9059
+ if (pdfNameEquals(filter, PDF_NAME_DCTDECODE)) {
9060
+ result = 'jpeg';
9061
+ } else if (pdfNameEquals(filter, PDF_NAME_FLATEDECODE)) {
9062
+ result = 'flateRaster';
8957
9063
  }
8958
9064
  }
8959
9065
  }
@@ -8963,15 +9069,217 @@ function isCompressibleImageStream(stream) {
8963
9069
  function pdfNameEquals(candidate, name) {
8964
9070
  return _instanceof$1(candidate, PDFName) && candidate.asString() === name.asString();
8965
9071
  }
9072
+ function lookupPdfObject(pdfDoc, value) {
9073
+ return _instanceof$1(value, PDFRef) ? pdfDoc.context.lookup(value) : value;
9074
+ }
9075
+ function dictNumber(dict, name) {
9076
+ var value = dict.get(name);
9077
+ return _instanceof$1(value, PDFNumber) ? value.asNumber() : undefined;
9078
+ }
9079
+ function resolveImageColorSpaceChannels(pdfDoc, colorSpaceValue) {
9080
+ var colorSpace = lookupPdfObject(pdfDoc, colorSpaceValue);
9081
+ var result;
9082
+ if (_instanceof$1(colorSpace, PDFName)) {
9083
+ if (pdfNameEquals(colorSpace, PDF_NAME_DEVICE_RGB) || pdfNameEquals(colorSpace, PDF_NAME_CAL_RGB)) {
9084
+ result = 3;
9085
+ } else if (pdfNameEquals(colorSpace, PDF_NAME_DEVICE_GRAY) || pdfNameEquals(colorSpace, PDF_NAME_CAL_GRAY)) {
9086
+ result = 1;
9087
+ }
9088
+ } else if (_instanceof$1(colorSpace, PDFArray) && colorSpace.size() > 0) {
9089
+ var family = colorSpace.get(0);
9090
+ if (pdfNameEquals(family, PDF_NAME_ICC_BASED) && colorSpace.size() > 1) {
9091
+ var iccStream = lookupPdfObject(pdfDoc, colorSpace.get(1));
9092
+ if (_instanceof$1(iccStream, PDFStream)) {
9093
+ var componentCount = dictNumber(iccStream.dict, PDF_NAME_N);
9094
+ if (componentCount === 3) {
9095
+ result = 3;
9096
+ } else if (componentCount === 1) {
9097
+ result = 1;
9098
+ }
9099
+ }
9100
+ } else if (pdfNameEquals(family, PDF_NAME_CAL_RGB)) {
9101
+ result = 3;
9102
+ } else if (pdfNameEquals(family, PDF_NAME_CAL_GRAY)) {
9103
+ result = 1;
9104
+ }
9105
+ }
9106
+ return result;
9107
+ }
9108
+ function readFlatePredictorParams(pdfDoc, dict) {
9109
+ var _ref, _ref1, _ref2, _ref3;
9110
+ var parmsValue = lookupPdfObject(pdfDoc, dict.get(PDF_NAME_DECODE_PARMS));
9111
+ // A filter array pairs with a DecodeParms array; a single flate filter uses the first entry.
9112
+ if (_instanceof$1(parmsValue, PDFArray)) {
9113
+ parmsValue = lookupPdfObject(pdfDoc, parmsValue.size() > 0 ? parmsValue.get(0) : undefined);
9114
+ }
9115
+ var parms = _instanceof$1(parmsValue, PDFDict) ? parmsValue : undefined;
9116
+ var result = {
9117
+ predictor: (_ref = parms ? dictNumber(parms, PDF_NAME_PREDICTOR) : undefined) !== null && _ref !== void 0 ? _ref : 1,
9118
+ colors: (_ref1 = parms ? dictNumber(parms, PDF_NAME_COLORS) : undefined) !== null && _ref1 !== void 0 ? _ref1 : 1,
9119
+ columns: (_ref2 = parms ? dictNumber(parms, PDF_NAME_COLUMNS) : undefined) !== null && _ref2 !== void 0 ? _ref2 : 1,
9120
+ bitsPerComponent: (_ref3 = parms ? dictNumber(parms, PDF_NAME_BITS_PER_COMPONENT) : undefined) !== null && _ref3 !== void 0 ? _ref3 : 8
9121
+ };
9122
+ return result;
9123
+ }
9124
+ function unpredictFlateImageData(data, params) {
9125
+ var predictor = params.predictor, colors = params.colors, columns = params.columns, bitsPerComponent = params.bitsPerComponent;
9126
+ var result;
9127
+ if (predictor === 1) {
9128
+ result = data;
9129
+ } else if (bitsPerComponent !== 8) {
9130
+ result = undefined; // only 8-bit predictor data is supported
9131
+ } else if (predictor === 2) {
9132
+ result = unpredictTiffImageData(data, colors, columns);
9133
+ } else if (predictor >= 10 && predictor <= 15) {
9134
+ result = unpredictPngImageData(data, colors, columns);
9135
+ }
9136
+ return result;
9137
+ }
9138
+ /**
9139
+ * Reverses TIFF Predictor 2 (horizontal differencing) on 8-bit sample data, in place.
9140
+ *
9141
+ * @param data - Predictor-encoded sample bytes.
9142
+ * @param colors - Samples per pixel.
9143
+ * @param columns - Pixels per row.
9144
+ * @returns The same buffer with the differencing undone, or `undefined` when the length is not a whole number of rows.
9145
+ */ function unpredictTiffImageData(data, colors, columns) {
9146
+ var rowLength = colors * columns;
9147
+ var result;
9148
+ if (rowLength > 0 && data.byteLength % rowLength === 0) {
9149
+ for(var rowStart = 0; rowStart < data.byteLength; rowStart += rowLength){
9150
+ for(var i = colors; i < rowLength; i += 1){
9151
+ data[rowStart + i] = data[rowStart + i] + data[rowStart + i - colors] & 0xff;
9152
+ }
9153
+ }
9154
+ result = data;
9155
+ }
9156
+ return result;
9157
+ }
9158
+ /**
9159
+ * Reverses PNG row filters (predictors 10–15) on 8-bit sample data.
9160
+ *
9161
+ * @param data - Predictor-encoded bytes: each row is one filter-type byte followed by `colors * columns` filtered bytes.
9162
+ * @param colors - Samples per pixel.
9163
+ * @param columns - Pixels per row.
9164
+ * @returns The unfiltered raster bytes, or `undefined` for a malformed length or an unknown filter type.
9165
+ */ function unpredictPngImageData(data, colors, columns) {
9166
+ var rowLength = colors * columns;
9167
+ var encodedRowLength = rowLength + 1;
9168
+ var result;
9169
+ if (rowLength > 0 && data.byteLength % encodedRowLength === 0) {
9170
+ var rows = data.byteLength / encodedRowLength;
9171
+ var output = Buffer.alloc(rows * rowLength);
9172
+ var valid = true;
9173
+ for(var row = 0; row < rows && valid; row += 1){
9174
+ valid = unpredictPngRow({
9175
+ filterType: data[row * encodedRowLength],
9176
+ rowIn: data.subarray(row * encodedRowLength + 1, (row + 1) * encodedRowLength),
9177
+ output: output,
9178
+ outStart: row * rowLength,
9179
+ prevStart: (row - 1) * rowLength,
9180
+ colors: colors,
9181
+ isFirstRow: row === 0
9182
+ });
9183
+ }
9184
+ result = valid ? output : undefined;
9185
+ }
9186
+ return result;
9187
+ }
9188
+ function unpredictPngRow(input) {
9189
+ var filterType = input.filterType, rowIn = input.rowIn, output = input.output, outStart = input.outStart, prevStart = input.prevStart, colors = input.colors, isFirstRow = input.isFirstRow;
9190
+ var valid = true;
9191
+ for(var i = 0; i < rowIn.length && valid; i += 1){
9192
+ var left = i >= colors ? output[outStart + i - colors] : 0;
9193
+ var up = isFirstRow ? 0 : output[prevStart + i];
9194
+ var value = 0;
9195
+ switch(filterType){
9196
+ case 0:
9197
+ value = rowIn[i];
9198
+ break;
9199
+ case 1:
9200
+ value = rowIn[i] + left;
9201
+ break;
9202
+ case 2:
9203
+ value = rowIn[i] + up;
9204
+ break;
9205
+ case 3:
9206
+ value = rowIn[i] + (left + up >> 1);
9207
+ break;
9208
+ case 4:
9209
+ {
9210
+ // Paeth
9211
+ var upLeft = !isFirstRow && i >= colors ? output[prevStart + i - colors] : 0;
9212
+ value = rowIn[i] + paethPredictor(left, up, upLeft);
9213
+ break;
9214
+ }
9215
+ default:
9216
+ valid = false;
9217
+ }
9218
+ output[outStart + i] = value & 0xff;
9219
+ }
9220
+ return valid;
9221
+ }
9222
+ function paethPredictor(left, up, upLeft) {
9223
+ var initial = left + up - upLeft;
9224
+ var distanceLeft = Math.abs(initial - left);
9225
+ var distanceUp = Math.abs(initial - up);
9226
+ var distanceUpLeft = Math.abs(initial - upLeft);
9227
+ var result;
9228
+ if (distanceLeft <= distanceUp && distanceLeft <= distanceUpLeft) {
9229
+ result = left;
9230
+ } else if (distanceUp <= distanceUpLeft) {
9231
+ result = up;
9232
+ } else {
9233
+ result = upLeft;
9234
+ }
9235
+ return result;
9236
+ }
9237
+ /**
9238
+ * Inflates a FlateDecode image stream into raw interleaved 8-bit pixel data.
9239
+ *
9240
+ * @param pdfDoc - Document the stream belongs to, used to resolve indirect references.
9241
+ * @param stream - The FlateDecode image XObject stream.
9242
+ * @returns The decoded raster, or `undefined` when the stream's raster layout is
9243
+ * unsupported: a non-8-bit depth, an image mask, a custom `/Decode` array, an
9244
+ * unresolvable or non-gray/RGB color space, an unsupported predictor, or a decoded
9245
+ * length that does not match the declared dimensions.
9246
+ */ function decodeFlateRasterImage(pdfDoc, stream) {
9247
+ var dict = stream.dict;
9248
+ var width = dictNumber(dict, PDF_NAME_WIDTH);
9249
+ var height = dictNumber(dict, PDF_NAME_HEIGHT);
9250
+ var bitsPerComponent = dictNumber(dict, PDF_NAME_BITS_PER_COMPONENT);
9251
+ var hasDecodeArray = dict.get(PDF_NAME_DECODE) !== undefined;
9252
+ var isImageMask = dict.get(PDF_NAME_IMAGE_MASK) !== undefined;
9253
+ var channels = resolveImageColorSpaceChannels(pdfDoc, dict.get(PDF_NAME_COLOR_SPACE));
9254
+ var result;
9255
+ if (width != null && width > 0 && height != null && height > 0 && bitsPerComponent === 8 && !hasDecodeArray && !isImageMask && channels != null) {
9256
+ var predictorParams = readFlatePredictorParams(pdfDoc, dict);
9257
+ // when a predictor is in play its params must describe the same raster layout the image dict declares
9258
+ var predictorParamsOk = predictorParams.predictor === 1 || predictorParams.colors === channels && predictorParams.columns === width && predictorParams.bitsPerComponent === 8;
9259
+ if (predictorParamsOk) {
9260
+ var inflated = inflateSync(stream.contents);
9261
+ var data = unpredictFlateImageData(inflated, predictorParams);
9262
+ if ((data === null || data === void 0 ? void 0 : data.byteLength) === width * height * channels) {
9263
+ result = {
9264
+ data: data,
9265
+ width: width,
9266
+ height: height,
9267
+ channels: channels
9268
+ };
9269
+ }
9270
+ }
9271
+ }
9272
+ return result;
9273
+ }
8966
9274
  function replaceImageStream(input) {
8967
- var pdfDoc = input.pdfDoc, ref = input.ref, newImageBytes = input.newImageBytes, newWidth = input.newWidth, newHeight = input.newHeight;
9275
+ var pdfDoc = input.pdfDoc, ref = input.ref, newImageBytes = input.newImageBytes, newWidth = input.newWidth, newHeight = input.newHeight, colorSpace = input.colorSpace;
8968
9276
  var context = pdfDoc.context;
8969
9277
  var newDict = context.obj({
8970
9278
  Type: 'XObject',
8971
9279
  Subtype: 'Image',
8972
9280
  Width: newWidth,
8973
9281
  Height: newHeight,
8974
- ColorSpace: 'DeviceRGB',
9282
+ ColorSpace: colorSpace,
8975
9283
  BitsPerComponent: 8,
8976
9284
  Filter: 'DCTDecode',
8977
9285
  Length: newImageBytes.length
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/model",
3
- "version": "13.25.1",
3
+ "version": "13.27.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.25.1",
6
- "@dereekb/date": "13.25.1",
7
- "@dereekb/firebase": "13.25.1",
8
- "@dereekb/firebase-server": "13.25.1",
9
- "@dereekb/model": "13.25.1",
10
- "@dereekb/nestjs": "13.25.1",
11
- "@dereekb/rxjs": "13.25.1",
12
- "@dereekb/util": "13.25.1",
5
+ "@dereekb/analytics": "13.27.0",
6
+ "@dereekb/date": "13.27.0",
7
+ "@dereekb/firebase": "13.27.0",
8
+ "@dereekb/firebase-server": "13.27.0",
9
+ "@dereekb/model": "13.27.0",
10
+ "@dereekb/nestjs": "13.27.0",
11
+ "@dereekb/rxjs": "13.27.0",
12
+ "@dereekb/util": "13.27.0",
13
13
  "@nestjs/common": "^11.1.19",
14
14
  "@nestjs/config": "^4.0.4",
15
15
  "archiver": "^7.0.1",