label-printer 0.7.5 → 0.7.7

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.
package/dist/index.mjs CHANGED
@@ -305,12 +305,13 @@ function parsePNG(buffer2) {
305
305
  }
306
306
  const scanlineLength = width * bytesPerPixel;
307
307
  const data = new Uint8Array(width * height * outputChannels);
308
+ let prevUnfilteredScanline = Buffer.alloc(scanlineLength);
308
309
  for (let y = 0; y < height; y++) {
309
310
  const scanlineStart = y * (scanlineLength + 1);
310
311
  const filterType = decompressedData[scanlineStart];
311
312
  const scanline = decompressedData.subarray(scanlineStart + 1, scanlineStart + 1 + scanlineLength);
312
- const prevScanline = y > 0 ? decompressedData.subarray((y - 1) * (scanlineLength + 1) + 1, (y - 1) * (scanlineLength + 1) + 1 + scanlineLength) : Buffer.alloc(scanlineLength);
313
- const unfilteredScanline = applyPNGFilter(filterType, scanline, prevScanline, bytesPerPixel);
313
+ const unfilteredScanline = applyPNGFilter(filterType, scanline, prevUnfilteredScanline, bytesPerPixel);
314
+ prevUnfilteredScanline = unfilteredScanline;
314
315
  for (let x = 0; x < width; x++) {
315
316
  const outIdx = (y * width + x) * outputChannels;
316
317
  if (colorType === 0) {
@@ -804,7 +805,8 @@ var ImageProcessor_default = ImageProcessor;
804
805
  // src/helpers/ImageUtils.ts
805
806
  var BLACK_PIXEL = 0;
806
807
  var WHITE_PIXEL = 1;
807
- var DEFAULT_THRESHOLD = 200;
808
+ var DEFAULT_THRESHOLD = 240;
809
+ var DEFAULT_CROP_ALPHA_THRESHOLD = 16;
808
810
  var ImageUtils = class {
809
811
  /**
810
812
  * Get pixel information about an image
@@ -823,11 +825,11 @@ var ImageUtils = class {
823
825
  * input size as only downscaling is performed
824
826
  *
825
827
  * @param image Image to process
826
- * @param destinationWidth Width of the ouput bitmap
828
+ * @param destinationWidth Width of the output bitmap
827
829
  * @param destinationHeight Height of the output bitmap
828
830
  * @returns
829
831
  */
830
- static getBWBitmap(image2, destinationWidth, destinationHeight) {
832
+ static getBWBitmap(image2, destinationWidth, destinationHeight, threshold, lsbFirst = false) {
831
833
  return __async(this, null, function* () {
832
834
  const {
833
835
  data,
@@ -838,43 +840,103 @@ var ImageUtils = class {
838
840
  image2,
839
841
  destinationWidth != null && destinationHeight != null ? { width: destinationWidth, height: destinationHeight } : void 0
840
842
  );
841
- const dim = getSizePreserveAspect(width, height, destinationWidth, destinationHeight);
843
+ let cropX0 = 0;
844
+ let cropY0 = 0;
845
+ let cropX1 = width - 1;
846
+ let cropY1 = height - 1;
847
+ if (bitsPerPixel > 3) {
848
+ let found = false;
849
+ let minX = width;
850
+ let minY = height;
851
+ let maxX = -1;
852
+ let maxY = -1;
853
+ for (let y = 0; y < height; y++) {
854
+ for (let x = 0; x < width; x++) {
855
+ const a = data[y * width * bitsPerPixel + x * bitsPerPixel + 3];
856
+ if (a >= DEFAULT_CROP_ALPHA_THRESHOLD) {
857
+ found = true;
858
+ if (x < minX) minX = x;
859
+ if (y < minY) minY = y;
860
+ if (x > maxX) maxX = x;
861
+ if (y > maxY) maxY = y;
862
+ }
863
+ }
864
+ }
865
+ if (found) {
866
+ cropX0 = minX;
867
+ cropY0 = minY;
868
+ cropX1 = maxX;
869
+ cropY1 = maxY;
870
+ }
871
+ }
872
+ const cropWidth = cropX1 - cropX0 + 1;
873
+ const cropHeight = cropY1 - cropY0 + 1;
874
+ const dim = getSizePreserveAspect(cropWidth, cropHeight, destinationWidth, destinationHeight);
842
875
  const dWidth = dim.width;
843
876
  const dHeight = dim.height;
844
877
  const differenceToDividable = dWidth % 8 == 0 ? 0 : 8 - dWidth % 8;
845
878
  const dividableDWidth = dWidth + differenceToDividable;
846
- const bitmapData = new Uint8Array(dividableDWidth * dHeight);
879
+ const luminances = new Uint8Array(dividableDWidth * dHeight);
847
880
  let destinationIndex = 0;
848
881
  for (let h = 0; h < dHeight; h++) {
849
- const originalHeight = Math.round(h * (height - 1) / (dHeight - 1));
882
+ const srcY0 = cropY0 + Math.floor(h * cropHeight / dHeight);
883
+ const srcY1 = Math.max(srcY0, cropY0 + Math.floor((h + 1) * cropHeight / dHeight) - 1);
850
884
  for (let w = 0; w < dWidth; w++) {
851
- const originalWidth = Math.round(w * (width - 1) / (dWidth - 1));
852
- const baseIndex = originalHeight * width * bitsPerPixel + originalWidth * bitsPerPixel;
853
- const r = data[baseIndex];
854
- const g = data[baseIndex + 1];
855
- const b = data[baseIndex + 2];
856
- const a = bitsPerPixel > 3 ? data[baseIndex + 3] : 255;
857
- const alpha = a / 255;
858
- const rC = r * alpha + 255 * (1 - alpha);
859
- const gC = g * alpha + 255 * (1 - alpha);
860
- const bC = b * alpha + 255 * (1 - alpha);
861
- const luminance = 0.299 * rC + 0.587 * gC + 0.114 * bC;
862
- if (luminance > DEFAULT_THRESHOLD) {
863
- bitmapData[destinationIndex] = WHITE_PIXEL;
864
- } else {
865
- bitmapData[destinationIndex] = BLACK_PIXEL;
885
+ const srcX0 = cropX0 + Math.floor(w * cropWidth / dWidth);
886
+ const srcX1 = Math.max(srcX0, cropX0 + Math.floor((w + 1) * cropWidth / dWidth) - 1);
887
+ let lumSum = 0;
888
+ let count = 0;
889
+ let opaqueCount = 0;
890
+ let opaqueLumSum = 0;
891
+ let opaqueWeightSum = 0;
892
+ let minOpaqueLum = 255;
893
+ for (let sy = srcY0; sy <= srcY1; sy++) {
894
+ for (let sx = srcX0; sx <= srcX1; sx++) {
895
+ const baseIndex = sy * width * bitsPerPixel + sx * bitsPerPixel;
896
+ const r = data[baseIndex];
897
+ const g = data[baseIndex + 1];
898
+ const b = data[baseIndex + 2];
899
+ const a = bitsPerPixel > 3 ? data[baseIndex + 3] : 255;
900
+ const alpha = a / 255;
901
+ const rC = r * alpha + 255 * (1 - alpha);
902
+ const gC = g * alpha + 255 * (1 - alpha);
903
+ const bC = b * alpha + 255 * (1 - alpha);
904
+ lumSum += 0.299 * rC + 0.587 * gC + 0.114 * bC;
905
+ count += 1;
906
+ if (a > 0) {
907
+ opaqueCount += 1;
908
+ const lum = 0.299 * r + 0.587 * g + 0.114 * b;
909
+ opaqueLumSum += lum * alpha;
910
+ opaqueWeightSum += alpha;
911
+ if (lum < minOpaqueLum) minOpaqueLum = lum;
912
+ }
913
+ }
866
914
  }
915
+ const avgLum = count > 0 ? lumSum / count : 255;
916
+ const avgOpaqueLum = opaqueWeightSum > 0 ? opaqueLumSum / opaqueWeightSum : 255;
917
+ const opaqueRatio = count > 0 ? opaqueCount / count : 0;
918
+ const luminance = opaqueCount === 0 ? 255 : opaqueRatio < 0.25 ? minOpaqueLum : avgOpaqueLum;
919
+ luminances[destinationIndex] = Math.max(0, Math.min(255, Math.round(luminance)));
867
920
  destinationIndex += 1;
868
921
  }
869
922
  for (let i = 0; i < differenceToDividable; i++) {
870
- bitmapData[destinationIndex] = WHITE_PIXEL;
923
+ luminances[destinationIndex] = 255;
871
924
  destinationIndex += 1;
872
925
  }
873
926
  }
927
+ const thresholdValue = threshold != null ? threshold : this.otsuThreshold(luminances, dWidth, dividableDWidth, dHeight);
928
+ const bitmapData = new Uint8Array(dividableDWidth * dHeight);
929
+ for (let h = 0; h < dHeight; h++) {
930
+ const rowOffset = h * dividableDWidth;
931
+ for (let w = 0; w < dividableDWidth; w++) {
932
+ const idx = rowOffset + w;
933
+ bitmapData[idx] = luminances[idx] > thresholdValue ? WHITE_PIXEL : BLACK_PIXEL;
934
+ }
935
+ }
874
936
  const byteArrays = this.chunk(bitmapData, 8);
875
937
  const widthInBytes = dividableDWidth / 8;
876
- const bytes = byteArrays.map(this.bitsToByte);
877
- const finalBytes = new Uint8Array(bytes);
938
+ const bytes2 = byteArrays.map((b) => this.bitsToByte(b, lsbFirst));
939
+ const finalBytes = new Uint8Array(bytes2);
878
940
  return {
879
941
  width: widthInBytes,
880
942
  height: dHeight,
@@ -882,6 +944,40 @@ var ImageUtils = class {
882
944
  };
883
945
  });
884
946
  }
947
+ static otsuThreshold(luminances, contentWidth, rowWidth, height) {
948
+ const hist = new Uint32Array(256);
949
+ let total = 0;
950
+ for (let y = 0; y < height; y++) {
951
+ const rowOffset = y * rowWidth;
952
+ for (let x = 0; x < contentWidth; x++) {
953
+ hist[luminances[rowOffset + x]] += 1;
954
+ total += 1;
955
+ }
956
+ }
957
+ if (total === 0) return DEFAULT_THRESHOLD;
958
+ let sum = 0;
959
+ for (let t = 0; t < 256; t++) sum += t * hist[t];
960
+ let sumB = 0;
961
+ let wB = 0;
962
+ let wF = 0;
963
+ let maxBetween = -1;
964
+ let threshold = DEFAULT_THRESHOLD;
965
+ for (let t = 0; t < 256; t++) {
966
+ wB += hist[t];
967
+ if (wB === 0) continue;
968
+ wF = total - wB;
969
+ if (wF === 0) break;
970
+ sumB += t * hist[t];
971
+ const mB = sumB / wB;
972
+ const mF = (sum - sumB) / wF;
973
+ const between = wB * wF * (mB - mF) * (mB - mF);
974
+ if (between > maxBetween) {
975
+ maxBetween = between;
976
+ threshold = t;
977
+ }
978
+ }
979
+ return threshold;
980
+ }
885
981
  /**
886
982
  * Splits an array into chunks.
887
983
  * @param originalArray
@@ -901,13 +997,95 @@ var ImageUtils = class {
901
997
  * @param bits
902
998
  * @returns
903
999
  */
904
- static bitsToByte(bits) {
1000
+ static bitsToByte(bits, lsbFirst) {
905
1001
  let byteValue = 0;
1002
+ if (lsbFirst) {
1003
+ for (let i = 0; i < bits.length; i++) {
1004
+ byteValue |= (bits[i] & 1) << i;
1005
+ }
1006
+ return byteValue;
1007
+ }
906
1008
  for (let i = 0; i < bits.length; i++) {
907
- byteValue = byteValue << 1 | bits[i];
1009
+ byteValue = byteValue << 1 | bits[i] & 1;
908
1010
  }
909
1011
  return byteValue;
910
1012
  }
1013
+ static dilateBWBitmap(bitmap2, iterations = 1) {
1014
+ let current = bitmap2;
1015
+ for (let i = 0; i < iterations; i++) {
1016
+ current = this.dilateOnce(current);
1017
+ }
1018
+ return current;
1019
+ }
1020
+ static bwBitmapToPBM(bitmap2, widthDots2) {
1021
+ var _a;
1022
+ const widthBytes = bitmap2.width;
1023
+ const height = bitmap2.height;
1024
+ const widthBits = widthDots2 != null ? widthDots2 : widthBytes * 8;
1025
+ const header = `P4
1026
+ ${widthBits} ${height}
1027
+ `;
1028
+ const headerBytes = new TextEncoder().encode(header);
1029
+ const rowBytes = Math.ceil(widthBits / 8);
1030
+ const out = new Uint8Array(headerBytes.length + rowBytes * height);
1031
+ out.set(headerBytes, 0);
1032
+ const src = bitmap2.bytes;
1033
+ let offset = headerBytes.length;
1034
+ for (let y = 0; y < height; y++) {
1035
+ const rowStart = y * widthBytes;
1036
+ for (let xb = 0; xb < rowBytes; xb++) {
1037
+ const b = (_a = src[rowStart + xb]) != null ? _a : 255;
1038
+ out[offset++] = ~b & 255;
1039
+ }
1040
+ const extraBits = rowBytes * 8 - widthBits;
1041
+ if (extraBits > 0) {
1042
+ const mask = 255 << extraBits;
1043
+ out[offset - 1] = out[offset - 1] & mask;
1044
+ }
1045
+ }
1046
+ return out;
1047
+ }
1048
+ static saveBWBitmapAsPBM(bitmap, filePath, widthDots) {
1049
+ return __async(this, null, function* () {
1050
+ if (typeof window !== "undefined") {
1051
+ throw new Error("pbm-export-not-supported-in-browser");
1052
+ }
1053
+ const fs = yield eval("require")("fs");
1054
+ const bytes = this.bwBitmapToPBM(bitmap, widthDots);
1055
+ fs.writeFileSync(filePath, bytes);
1056
+ });
1057
+ }
1058
+ static dilateOnce(bitmap2) {
1059
+ const widthBytes = bitmap2.width;
1060
+ const widthBits = widthBytes * 8;
1061
+ const height = bitmap2.height;
1062
+ const src = bitmap2.bytes;
1063
+ const dst = new Uint8Array(src.length);
1064
+ const getBit = (x, y) => {
1065
+ if (x < 0 || y < 0 || x >= widthBits || y >= height) return 1;
1066
+ const byteIndex = y * widthBytes + (x >> 3);
1067
+ const bitIndex = 7 - (x & 7);
1068
+ return src[byteIndex] >> bitIndex & 1;
1069
+ };
1070
+ const setBit = (x, y, value) => {
1071
+ if (x < 0 || y < 0 || x >= widthBits || y >= height) return;
1072
+ const byteIndex = y * widthBytes + (x >> 3);
1073
+ const mask = 1 << 7 - (x & 7);
1074
+ if (value === 1) dst[byteIndex] |= mask;
1075
+ else dst[byteIndex] &= ~mask & 255;
1076
+ };
1077
+ for (let y = 0; y < height; y++) {
1078
+ for (let x = 0; x < widthBits; x++) {
1079
+ const isBlack = getBit(x, y) === 0 || getBit(x - 1, y) === 0 || getBit(x + 1, y) === 0 || getBit(x, y - 1) === 0 || getBit(x, y + 1) === 0 || getBit(x - 1, y - 1) === 0 || getBit(x + 1, y - 1) === 0 || getBit(x - 1, y + 1) === 0 || getBit(x + 1, y + 1) === 0;
1080
+ setBit(x, y, isBlack ? 0 : 1);
1081
+ }
1082
+ }
1083
+ return {
1084
+ width: widthBytes,
1085
+ height,
1086
+ bytes: dst
1087
+ };
1088
+ }
911
1089
  };
912
1090
 
913
1091
  // src/commands/tspl/commands/basic/TSPLBitmapCommand.ts
@@ -919,9 +1097,9 @@ var TSPLBitmapCommand = class _TSPLBitmapCommand extends TSPLVisualCommand {
919
1097
  * @param mode Represents the strategy to use when two bitmaps overlap. The final value will be determined by
920
1098
  * either overwriting the first bitmap's value with the second one or performing an 'or' or 'xor' operation on the values
921
1099
  */
922
- constructor(bitmap, x, y, mode) {
1100
+ constructor(bitmap2, x, y, mode) {
923
1101
  super(x, y);
924
- this.bitmap = bitmap;
1102
+ this.bitmap = bitmap2;
925
1103
  this.mode = mode != null ? mode : "overwrite";
926
1104
  }
927
1105
  get commandString() {
@@ -962,8 +1140,8 @@ var TSPLBitmapCommand = class _TSPLBitmapCommand extends TSPLVisualCommand {
962
1140
  */
963
1141
  static forImageUrl(image2, x, y, imageWidth, imageHeight, mode) {
964
1142
  return __async(this, null, function* () {
965
- const bitmap = yield ImageUtils.getBWBitmap(image2, imageWidth, imageHeight);
966
- return new _TSPLBitmapCommand(bitmap, x, y, mode);
1143
+ const bitmap2 = yield ImageUtils.getBWBitmap(image2, imageWidth, imageHeight);
1144
+ return new _TSPLBitmapCommand(bitmap2, x, y, mode);
967
1145
  });
968
1146
  }
969
1147
  };
@@ -1382,9 +1560,9 @@ var StringUtils = class {
1382
1560
  * @param bytes Bytes to decode
1383
1561
  * @returns A string
1384
1562
  */
1385
- toString(bytes) {
1563
+ toString(bytes2) {
1386
1564
  let decoder = new TextDecoder();
1387
- return decoder.decode(bytes);
1565
+ return decoder.decode(bytes2);
1388
1566
  }
1389
1567
  };
1390
1568
  var isWhitespace = (text) => text.trim() === "";
@@ -1457,6 +1635,10 @@ var UsbDevice = class {
1457
1635
  var _a;
1458
1636
  return (_a = this.endpoints.find((e) => e.direction == "out")) == null ? void 0 : _a.endpointNumber;
1459
1637
  }
1638
+ get outEndpointPacketSize() {
1639
+ var _a;
1640
+ return (_a = this.endpoints.find((e) => e.direction == "out")) == null ? void 0 : _a.packetSize;
1641
+ }
1460
1642
  /**
1461
1643
  * Endpoint for reading
1462
1644
  */
@@ -1505,8 +1687,8 @@ var UsbDevice = class {
1505
1687
  */
1506
1688
  writeString(text) {
1507
1689
  return __async(this, null, function* () {
1508
- const bytes = stringHelper.toUTF8Array(text);
1509
- yield this.writeData(bytes);
1690
+ const bytes2 = stringHelper.toUTF8Array(text);
1691
+ yield this.writeData(bytes2);
1510
1692
  });
1511
1693
  }
1512
1694
  /**
@@ -1534,8 +1716,8 @@ var UsbDevice = class {
1534
1716
  */
1535
1717
  readString(length) {
1536
1718
  return __async(this, null, function* () {
1537
- const bytes = yield this.readData(length);
1538
- if (bytes) return stringHelper.toString(bytes);
1719
+ const bytes2 = yield this.readData(length);
1720
+ if (bytes2) return stringHelper.toString(bytes2);
1539
1721
  return void 0;
1540
1722
  });
1541
1723
  }
@@ -1646,8 +1828,8 @@ var NetworkDevice = class {
1646
1828
  }
1647
1829
  writeString(text) {
1648
1830
  return __async(this, null, function* () {
1649
- const bytes = stringHelper2.toUTF8Array(text);
1650
- yield this.writeData(bytes);
1831
+ const bytes2 = stringHelper2.toUTF8Array(text);
1832
+ yield this.writeData(bytes2);
1651
1833
  });
1652
1834
  }
1653
1835
  readData(length) {
@@ -1691,8 +1873,8 @@ var NetworkDevice = class {
1691
1873
  }
1692
1874
  readString(length) {
1693
1875
  return __async(this, null, function* () {
1694
- const bytes = yield this.readData(length);
1695
- if (bytes) return stringHelper2.toString(bytes);
1876
+ const bytes2 = yield this.readData(length);
1877
+ if (bytes2) return stringHelper2.toString(bytes2);
1696
1878
  return void 0;
1697
1879
  });
1698
1880
  }
@@ -2340,7 +2522,9 @@ var BOLD_WEIGTH = 700;
2340
2522
  var BOLD_TAG = "b";
2341
2523
  var ITALIC_TAG = "i";
2342
2524
  var UNDERLINE_TAG = "u";
2343
- var STRIKE_TAG = "s";
2525
+ var STRIKE_TAG = ["s", "del", "strike"];
2526
+ var PARAGRAPH_TAG = "p";
2527
+ var BREAK_TAG = "br";
2344
2528
  var Text = class extends LabelField {
2345
2529
  constructor(content, x, y, formatted = true) {
2346
2530
  super();
@@ -2425,6 +2609,13 @@ var Text = class extends LabelField {
2425
2609
  } else {
2426
2610
  const elementNode = rootNode;
2427
2611
  const tag = elementNode.rawTagName;
2612
+ if (tag == BREAK_TAG) {
2613
+ return {
2614
+ x: this.x,
2615
+ y: initialY + font.size + this.lineSpacing,
2616
+ command: this.context.generator.commandGroup([])
2617
+ };
2618
+ }
2428
2619
  let commands = [];
2429
2620
  let currentX = initialX;
2430
2621
  let currentY = initialY;
@@ -2432,19 +2623,45 @@ var Text = class extends LabelField {
2432
2623
  let baseFeatures = [...features];
2433
2624
  if (tag == UNDERLINE_TAG) {
2434
2625
  baseFeatures.push("underline");
2435
- } else if (tag == STRIKE_TAG) {
2626
+ } else if (STRIKE_TAG.includes(tag)) {
2436
2627
  baseFeatures.push("strike");
2437
2628
  } else if (tag == BOLD_TAG) {
2438
2629
  baseFont.weight = BOLD_WEIGTH;
2439
2630
  } else if (tag == ITALIC_TAG) {
2440
2631
  baseFont.style = "italic";
2441
2632
  }
2633
+ if (tag == PARAGRAPH_TAG) {
2634
+ const isAtFieldOrigin = initialX == this.x && initialY == this.y;
2635
+ if (!isAtFieldOrigin) {
2636
+ currentX = this.x;
2637
+ currentY = initialY + baseFont.size + this.lineSpacing;
2638
+ }
2639
+ }
2442
2640
  elementNode.childNodes.forEach((node) => {
2443
2641
  const { x, y, command } = this.generateFormattedRecursive(currentX, currentY, node, baseFont, baseFeatures);
2444
2642
  currentX = x;
2445
2643
  currentY = y;
2446
2644
  commands.push(command);
2447
2645
  });
2646
+ if (tag == PARAGRAPH_TAG) {
2647
+ let paragraphEndsWithBreak = false;
2648
+ for (let i = elementNode.childNodes.length - 1; i >= 0; i--) {
2649
+ const node = elementNode.childNodes[i];
2650
+ if (node.nodeType == NodeType.TEXT_NODE) {
2651
+ if (node.innerText.trim() == "") continue;
2652
+ break;
2653
+ }
2654
+ const childElement = node;
2655
+ if (childElement.rawTagName == BREAK_TAG) {
2656
+ paragraphEndsWithBreak = true;
2657
+ }
2658
+ break;
2659
+ }
2660
+ if (!paragraphEndsWithBreak) {
2661
+ currentX = this.x;
2662
+ currentY += baseFont.size + this.lineSpacing;
2663
+ }
2664
+ }
2448
2665
  return {
2449
2666
  x: currentX,
2450
2667
  y: currentY,
@@ -2657,8 +2874,8 @@ var Image2 = class _Image extends LabelField {
2657
2874
  */
2658
2875
  static create(image2, x, y, width, height) {
2659
2876
  return __async(this, null, function* () {
2660
- const bitmap = yield ImageUtils.getBWBitmap(image2, width, height);
2661
- return new _Image(x, y, bitmap);
2877
+ const bitmap2 = yield ImageUtils.getBWBitmap(image2, width, height);
2878
+ return new _Image(x, y, bitmap2);
2662
2879
  });
2663
2880
  }
2664
2881
  };