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.js CHANGED
@@ -330,12 +330,13 @@ function parsePNG(buffer2) {
330
330
  }
331
331
  const scanlineLength = width * bytesPerPixel;
332
332
  const data = new Uint8Array(width * height * outputChannels);
333
+ let prevUnfilteredScanline = Buffer.alloc(scanlineLength);
333
334
  for (let y = 0; y < height; y++) {
334
335
  const scanlineStart = y * (scanlineLength + 1);
335
336
  const filterType = decompressedData[scanlineStart];
336
337
  const scanline = decompressedData.subarray(scanlineStart + 1, scanlineStart + 1 + scanlineLength);
337
- const prevScanline = y > 0 ? decompressedData.subarray((y - 1) * (scanlineLength + 1) + 1, (y - 1) * (scanlineLength + 1) + 1 + scanlineLength) : Buffer.alloc(scanlineLength);
338
- const unfilteredScanline = applyPNGFilter(filterType, scanline, prevScanline, bytesPerPixel);
338
+ const unfilteredScanline = applyPNGFilter(filterType, scanline, prevUnfilteredScanline, bytesPerPixel);
339
+ prevUnfilteredScanline = unfilteredScanline;
339
340
  for (let x = 0; x < width; x++) {
340
341
  const outIdx = (y * width + x) * outputChannels;
341
342
  if (colorType === 0) {
@@ -829,7 +830,8 @@ var ImageProcessor_default = ImageProcessor;
829
830
  // src/helpers/ImageUtils.ts
830
831
  var BLACK_PIXEL = 0;
831
832
  var WHITE_PIXEL = 1;
832
- var DEFAULT_THRESHOLD = 200;
833
+ var DEFAULT_THRESHOLD = 240;
834
+ var DEFAULT_CROP_ALPHA_THRESHOLD = 16;
833
835
  var ImageUtils = class {
834
836
  /**
835
837
  * Get pixel information about an image
@@ -848,11 +850,11 @@ var ImageUtils = class {
848
850
  * input size as only downscaling is performed
849
851
  *
850
852
  * @param image Image to process
851
- * @param destinationWidth Width of the ouput bitmap
853
+ * @param destinationWidth Width of the output bitmap
852
854
  * @param destinationHeight Height of the output bitmap
853
855
  * @returns
854
856
  */
855
- static getBWBitmap(image2, destinationWidth, destinationHeight) {
857
+ static getBWBitmap(image2, destinationWidth, destinationHeight, threshold, lsbFirst = false) {
856
858
  return __async(this, null, function* () {
857
859
  const {
858
860
  data,
@@ -863,43 +865,103 @@ var ImageUtils = class {
863
865
  image2,
864
866
  destinationWidth != null && destinationHeight != null ? { width: destinationWidth, height: destinationHeight } : void 0
865
867
  );
866
- const dim = getSizePreserveAspect(width, height, destinationWidth, destinationHeight);
868
+ let cropX0 = 0;
869
+ let cropY0 = 0;
870
+ let cropX1 = width - 1;
871
+ let cropY1 = height - 1;
872
+ if (bitsPerPixel > 3) {
873
+ let found = false;
874
+ let minX = width;
875
+ let minY = height;
876
+ let maxX = -1;
877
+ let maxY = -1;
878
+ for (let y = 0; y < height; y++) {
879
+ for (let x = 0; x < width; x++) {
880
+ const a = data[y * width * bitsPerPixel + x * bitsPerPixel + 3];
881
+ if (a >= DEFAULT_CROP_ALPHA_THRESHOLD) {
882
+ found = true;
883
+ if (x < minX) minX = x;
884
+ if (y < minY) minY = y;
885
+ if (x > maxX) maxX = x;
886
+ if (y > maxY) maxY = y;
887
+ }
888
+ }
889
+ }
890
+ if (found) {
891
+ cropX0 = minX;
892
+ cropY0 = minY;
893
+ cropX1 = maxX;
894
+ cropY1 = maxY;
895
+ }
896
+ }
897
+ const cropWidth = cropX1 - cropX0 + 1;
898
+ const cropHeight = cropY1 - cropY0 + 1;
899
+ const dim = getSizePreserveAspect(cropWidth, cropHeight, destinationWidth, destinationHeight);
867
900
  const dWidth = dim.width;
868
901
  const dHeight = dim.height;
869
902
  const differenceToDividable = dWidth % 8 == 0 ? 0 : 8 - dWidth % 8;
870
903
  const dividableDWidth = dWidth + differenceToDividable;
871
- const bitmapData = new Uint8Array(dividableDWidth * dHeight);
904
+ const luminances = new Uint8Array(dividableDWidth * dHeight);
872
905
  let destinationIndex = 0;
873
906
  for (let h = 0; h < dHeight; h++) {
874
- const originalHeight = Math.round(h * (height - 1) / (dHeight - 1));
907
+ const srcY0 = cropY0 + Math.floor(h * cropHeight / dHeight);
908
+ const srcY1 = Math.max(srcY0, cropY0 + Math.floor((h + 1) * cropHeight / dHeight) - 1);
875
909
  for (let w = 0; w < dWidth; w++) {
876
- const originalWidth = Math.round(w * (width - 1) / (dWidth - 1));
877
- const baseIndex = originalHeight * width * bitsPerPixel + originalWidth * bitsPerPixel;
878
- const r = data[baseIndex];
879
- const g = data[baseIndex + 1];
880
- const b = data[baseIndex + 2];
881
- const a = bitsPerPixel > 3 ? data[baseIndex + 3] : 255;
882
- const alpha = a / 255;
883
- const rC = r * alpha + 255 * (1 - alpha);
884
- const gC = g * alpha + 255 * (1 - alpha);
885
- const bC = b * alpha + 255 * (1 - alpha);
886
- const luminance = 0.299 * rC + 0.587 * gC + 0.114 * bC;
887
- if (luminance > DEFAULT_THRESHOLD) {
888
- bitmapData[destinationIndex] = WHITE_PIXEL;
889
- } else {
890
- bitmapData[destinationIndex] = BLACK_PIXEL;
910
+ const srcX0 = cropX0 + Math.floor(w * cropWidth / dWidth);
911
+ const srcX1 = Math.max(srcX0, cropX0 + Math.floor((w + 1) * cropWidth / dWidth) - 1);
912
+ let lumSum = 0;
913
+ let count = 0;
914
+ let opaqueCount = 0;
915
+ let opaqueLumSum = 0;
916
+ let opaqueWeightSum = 0;
917
+ let minOpaqueLum = 255;
918
+ for (let sy = srcY0; sy <= srcY1; sy++) {
919
+ for (let sx = srcX0; sx <= srcX1; sx++) {
920
+ const baseIndex = sy * width * bitsPerPixel + sx * bitsPerPixel;
921
+ const r = data[baseIndex];
922
+ const g = data[baseIndex + 1];
923
+ const b = data[baseIndex + 2];
924
+ const a = bitsPerPixel > 3 ? data[baseIndex + 3] : 255;
925
+ const alpha = a / 255;
926
+ const rC = r * alpha + 255 * (1 - alpha);
927
+ const gC = g * alpha + 255 * (1 - alpha);
928
+ const bC = b * alpha + 255 * (1 - alpha);
929
+ lumSum += 0.299 * rC + 0.587 * gC + 0.114 * bC;
930
+ count += 1;
931
+ if (a > 0) {
932
+ opaqueCount += 1;
933
+ const lum = 0.299 * r + 0.587 * g + 0.114 * b;
934
+ opaqueLumSum += lum * alpha;
935
+ opaqueWeightSum += alpha;
936
+ if (lum < minOpaqueLum) minOpaqueLum = lum;
937
+ }
938
+ }
891
939
  }
940
+ const avgLum = count > 0 ? lumSum / count : 255;
941
+ const avgOpaqueLum = opaqueWeightSum > 0 ? opaqueLumSum / opaqueWeightSum : 255;
942
+ const opaqueRatio = count > 0 ? opaqueCount / count : 0;
943
+ const luminance = opaqueCount === 0 ? 255 : opaqueRatio < 0.25 ? minOpaqueLum : avgOpaqueLum;
944
+ luminances[destinationIndex] = Math.max(0, Math.min(255, Math.round(luminance)));
892
945
  destinationIndex += 1;
893
946
  }
894
947
  for (let i = 0; i < differenceToDividable; i++) {
895
- bitmapData[destinationIndex] = WHITE_PIXEL;
948
+ luminances[destinationIndex] = 255;
896
949
  destinationIndex += 1;
897
950
  }
898
951
  }
952
+ const thresholdValue = threshold != null ? threshold : this.otsuThreshold(luminances, dWidth, dividableDWidth, dHeight);
953
+ const bitmapData = new Uint8Array(dividableDWidth * dHeight);
954
+ for (let h = 0; h < dHeight; h++) {
955
+ const rowOffset = h * dividableDWidth;
956
+ for (let w = 0; w < dividableDWidth; w++) {
957
+ const idx = rowOffset + w;
958
+ bitmapData[idx] = luminances[idx] > thresholdValue ? WHITE_PIXEL : BLACK_PIXEL;
959
+ }
960
+ }
899
961
  const byteArrays = this.chunk(bitmapData, 8);
900
962
  const widthInBytes = dividableDWidth / 8;
901
- const bytes = byteArrays.map(this.bitsToByte);
902
- const finalBytes = new Uint8Array(bytes);
963
+ const bytes2 = byteArrays.map((b) => this.bitsToByte(b, lsbFirst));
964
+ const finalBytes = new Uint8Array(bytes2);
903
965
  return {
904
966
  width: widthInBytes,
905
967
  height: dHeight,
@@ -907,6 +969,40 @@ var ImageUtils = class {
907
969
  };
908
970
  });
909
971
  }
972
+ static otsuThreshold(luminances, contentWidth, rowWidth, height) {
973
+ const hist = new Uint32Array(256);
974
+ let total = 0;
975
+ for (let y = 0; y < height; y++) {
976
+ const rowOffset = y * rowWidth;
977
+ for (let x = 0; x < contentWidth; x++) {
978
+ hist[luminances[rowOffset + x]] += 1;
979
+ total += 1;
980
+ }
981
+ }
982
+ if (total === 0) return DEFAULT_THRESHOLD;
983
+ let sum = 0;
984
+ for (let t = 0; t < 256; t++) sum += t * hist[t];
985
+ let sumB = 0;
986
+ let wB = 0;
987
+ let wF = 0;
988
+ let maxBetween = -1;
989
+ let threshold = DEFAULT_THRESHOLD;
990
+ for (let t = 0; t < 256; t++) {
991
+ wB += hist[t];
992
+ if (wB === 0) continue;
993
+ wF = total - wB;
994
+ if (wF === 0) break;
995
+ sumB += t * hist[t];
996
+ const mB = sumB / wB;
997
+ const mF = (sum - sumB) / wF;
998
+ const between = wB * wF * (mB - mF) * (mB - mF);
999
+ if (between > maxBetween) {
1000
+ maxBetween = between;
1001
+ threshold = t;
1002
+ }
1003
+ }
1004
+ return threshold;
1005
+ }
910
1006
  /**
911
1007
  * Splits an array into chunks.
912
1008
  * @param originalArray
@@ -926,13 +1022,95 @@ var ImageUtils = class {
926
1022
  * @param bits
927
1023
  * @returns
928
1024
  */
929
- static bitsToByte(bits) {
1025
+ static bitsToByte(bits, lsbFirst) {
930
1026
  let byteValue = 0;
1027
+ if (lsbFirst) {
1028
+ for (let i = 0; i < bits.length; i++) {
1029
+ byteValue |= (bits[i] & 1) << i;
1030
+ }
1031
+ return byteValue;
1032
+ }
931
1033
  for (let i = 0; i < bits.length; i++) {
932
- byteValue = byteValue << 1 | bits[i];
1034
+ byteValue = byteValue << 1 | bits[i] & 1;
933
1035
  }
934
1036
  return byteValue;
935
1037
  }
1038
+ static dilateBWBitmap(bitmap2, iterations = 1) {
1039
+ let current = bitmap2;
1040
+ for (let i = 0; i < iterations; i++) {
1041
+ current = this.dilateOnce(current);
1042
+ }
1043
+ return current;
1044
+ }
1045
+ static bwBitmapToPBM(bitmap2, widthDots2) {
1046
+ var _a;
1047
+ const widthBytes = bitmap2.width;
1048
+ const height = bitmap2.height;
1049
+ const widthBits = widthDots2 != null ? widthDots2 : widthBytes * 8;
1050
+ const header = `P4
1051
+ ${widthBits} ${height}
1052
+ `;
1053
+ const headerBytes = new TextEncoder().encode(header);
1054
+ const rowBytes = Math.ceil(widthBits / 8);
1055
+ const out = new Uint8Array(headerBytes.length + rowBytes * height);
1056
+ out.set(headerBytes, 0);
1057
+ const src = bitmap2.bytes;
1058
+ let offset = headerBytes.length;
1059
+ for (let y = 0; y < height; y++) {
1060
+ const rowStart = y * widthBytes;
1061
+ for (let xb = 0; xb < rowBytes; xb++) {
1062
+ const b = (_a = src[rowStart + xb]) != null ? _a : 255;
1063
+ out[offset++] = ~b & 255;
1064
+ }
1065
+ const extraBits = rowBytes * 8 - widthBits;
1066
+ if (extraBits > 0) {
1067
+ const mask = 255 << extraBits;
1068
+ out[offset - 1] = out[offset - 1] & mask;
1069
+ }
1070
+ }
1071
+ return out;
1072
+ }
1073
+ static saveBWBitmapAsPBM(bitmap, filePath, widthDots) {
1074
+ return __async(this, null, function* () {
1075
+ if (typeof window !== "undefined") {
1076
+ throw new Error("pbm-export-not-supported-in-browser");
1077
+ }
1078
+ const fs = yield eval("require")("fs");
1079
+ const bytes = this.bwBitmapToPBM(bitmap, widthDots);
1080
+ fs.writeFileSync(filePath, bytes);
1081
+ });
1082
+ }
1083
+ static dilateOnce(bitmap2) {
1084
+ const widthBytes = bitmap2.width;
1085
+ const widthBits = widthBytes * 8;
1086
+ const height = bitmap2.height;
1087
+ const src = bitmap2.bytes;
1088
+ const dst = new Uint8Array(src.length);
1089
+ const getBit = (x, y) => {
1090
+ if (x < 0 || y < 0 || x >= widthBits || y >= height) return 1;
1091
+ const byteIndex = y * widthBytes + (x >> 3);
1092
+ const bitIndex = 7 - (x & 7);
1093
+ return src[byteIndex] >> bitIndex & 1;
1094
+ };
1095
+ const setBit = (x, y, value) => {
1096
+ if (x < 0 || y < 0 || x >= widthBits || y >= height) return;
1097
+ const byteIndex = y * widthBytes + (x >> 3);
1098
+ const mask = 1 << 7 - (x & 7);
1099
+ if (value === 1) dst[byteIndex] |= mask;
1100
+ else dst[byteIndex] &= ~mask & 255;
1101
+ };
1102
+ for (let y = 0; y < height; y++) {
1103
+ for (let x = 0; x < widthBits; x++) {
1104
+ 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;
1105
+ setBit(x, y, isBlack ? 0 : 1);
1106
+ }
1107
+ }
1108
+ return {
1109
+ width: widthBytes,
1110
+ height,
1111
+ bytes: dst
1112
+ };
1113
+ }
936
1114
  };
937
1115
 
938
1116
  // src/commands/tspl/commands/basic/TSPLBitmapCommand.ts
@@ -944,9 +1122,9 @@ var TSPLBitmapCommand = class _TSPLBitmapCommand extends TSPLVisualCommand {
944
1122
  * @param mode Represents the strategy to use when two bitmaps overlap. The final value will be determined by
945
1123
  * either overwriting the first bitmap's value with the second one or performing an 'or' or 'xor' operation on the values
946
1124
  */
947
- constructor(bitmap, x, y, mode) {
1125
+ constructor(bitmap2, x, y, mode) {
948
1126
  super(x, y);
949
- this.bitmap = bitmap;
1127
+ this.bitmap = bitmap2;
950
1128
  this.mode = mode != null ? mode : "overwrite";
951
1129
  }
952
1130
  get commandString() {
@@ -987,8 +1165,8 @@ var TSPLBitmapCommand = class _TSPLBitmapCommand extends TSPLVisualCommand {
987
1165
  */
988
1166
  static forImageUrl(image2, x, y, imageWidth, imageHeight, mode) {
989
1167
  return __async(this, null, function* () {
990
- const bitmap = yield ImageUtils.getBWBitmap(image2, imageWidth, imageHeight);
991
- return new _TSPLBitmapCommand(bitmap, x, y, mode);
1168
+ const bitmap2 = yield ImageUtils.getBWBitmap(image2, imageWidth, imageHeight);
1169
+ return new _TSPLBitmapCommand(bitmap2, x, y, mode);
992
1170
  });
993
1171
  }
994
1172
  };
@@ -1407,9 +1585,9 @@ var StringUtils = class {
1407
1585
  * @param bytes Bytes to decode
1408
1586
  * @returns A string
1409
1587
  */
1410
- toString(bytes) {
1588
+ toString(bytes2) {
1411
1589
  let decoder = new TextDecoder();
1412
- return decoder.decode(bytes);
1590
+ return decoder.decode(bytes2);
1413
1591
  }
1414
1592
  };
1415
1593
  var isWhitespace = (text) => text.trim() === "";
@@ -1482,6 +1660,10 @@ var UsbDevice = class {
1482
1660
  var _a;
1483
1661
  return (_a = this.endpoints.find((e) => e.direction == "out")) == null ? void 0 : _a.endpointNumber;
1484
1662
  }
1663
+ get outEndpointPacketSize() {
1664
+ var _a;
1665
+ return (_a = this.endpoints.find((e) => e.direction == "out")) == null ? void 0 : _a.packetSize;
1666
+ }
1485
1667
  /**
1486
1668
  * Endpoint for reading
1487
1669
  */
@@ -1530,8 +1712,8 @@ var UsbDevice = class {
1530
1712
  */
1531
1713
  writeString(text) {
1532
1714
  return __async(this, null, function* () {
1533
- const bytes = stringHelper.toUTF8Array(text);
1534
- yield this.writeData(bytes);
1715
+ const bytes2 = stringHelper.toUTF8Array(text);
1716
+ yield this.writeData(bytes2);
1535
1717
  });
1536
1718
  }
1537
1719
  /**
@@ -1559,8 +1741,8 @@ var UsbDevice = class {
1559
1741
  */
1560
1742
  readString(length) {
1561
1743
  return __async(this, null, function* () {
1562
- const bytes = yield this.readData(length);
1563
- if (bytes) return stringHelper.toString(bytes);
1744
+ const bytes2 = yield this.readData(length);
1745
+ if (bytes2) return stringHelper.toString(bytes2);
1564
1746
  return void 0;
1565
1747
  });
1566
1748
  }
@@ -1671,8 +1853,8 @@ var NetworkDevice = class {
1671
1853
  }
1672
1854
  writeString(text) {
1673
1855
  return __async(this, null, function* () {
1674
- const bytes = stringHelper2.toUTF8Array(text);
1675
- yield this.writeData(bytes);
1856
+ const bytes2 = stringHelper2.toUTF8Array(text);
1857
+ yield this.writeData(bytes2);
1676
1858
  });
1677
1859
  }
1678
1860
  readData(length) {
@@ -1716,8 +1898,8 @@ var NetworkDevice = class {
1716
1898
  }
1717
1899
  readString(length) {
1718
1900
  return __async(this, null, function* () {
1719
- const bytes = yield this.readData(length);
1720
- if (bytes) return stringHelper2.toString(bytes);
1901
+ const bytes2 = yield this.readData(length);
1902
+ if (bytes2) return stringHelper2.toString(bytes2);
1721
1903
  return void 0;
1722
1904
  });
1723
1905
  }
@@ -2365,7 +2547,9 @@ var BOLD_WEIGTH = 700;
2365
2547
  var BOLD_TAG = "b";
2366
2548
  var ITALIC_TAG = "i";
2367
2549
  var UNDERLINE_TAG = "u";
2368
- var STRIKE_TAG = "s";
2550
+ var STRIKE_TAG = ["s", "del", "strike"];
2551
+ var PARAGRAPH_TAG = "p";
2552
+ var BREAK_TAG = "br";
2369
2553
  var Text = class extends LabelField {
2370
2554
  constructor(content, x, y, formatted = true) {
2371
2555
  super();
@@ -2450,6 +2634,13 @@ var Text = class extends LabelField {
2450
2634
  } else {
2451
2635
  const elementNode = rootNode;
2452
2636
  const tag = elementNode.rawTagName;
2637
+ if (tag == BREAK_TAG) {
2638
+ return {
2639
+ x: this.x,
2640
+ y: initialY + font.size + this.lineSpacing,
2641
+ command: this.context.generator.commandGroup([])
2642
+ };
2643
+ }
2453
2644
  let commands = [];
2454
2645
  let currentX = initialX;
2455
2646
  let currentY = initialY;
@@ -2457,19 +2648,45 @@ var Text = class extends LabelField {
2457
2648
  let baseFeatures = [...features];
2458
2649
  if (tag == UNDERLINE_TAG) {
2459
2650
  baseFeatures.push("underline");
2460
- } else if (tag == STRIKE_TAG) {
2651
+ } else if (STRIKE_TAG.includes(tag)) {
2461
2652
  baseFeatures.push("strike");
2462
2653
  } else if (tag == BOLD_TAG) {
2463
2654
  baseFont.weight = BOLD_WEIGTH;
2464
2655
  } else if (tag == ITALIC_TAG) {
2465
2656
  baseFont.style = "italic";
2466
2657
  }
2658
+ if (tag == PARAGRAPH_TAG) {
2659
+ const isAtFieldOrigin = initialX == this.x && initialY == this.y;
2660
+ if (!isAtFieldOrigin) {
2661
+ currentX = this.x;
2662
+ currentY = initialY + baseFont.size + this.lineSpacing;
2663
+ }
2664
+ }
2467
2665
  elementNode.childNodes.forEach((node) => {
2468
2666
  const { x, y, command } = this.generateFormattedRecursive(currentX, currentY, node, baseFont, baseFeatures);
2469
2667
  currentX = x;
2470
2668
  currentY = y;
2471
2669
  commands.push(command);
2472
2670
  });
2671
+ if (tag == PARAGRAPH_TAG) {
2672
+ let paragraphEndsWithBreak = false;
2673
+ for (let i = elementNode.childNodes.length - 1; i >= 0; i--) {
2674
+ const node = elementNode.childNodes[i];
2675
+ if (node.nodeType == import_node_html_parser.NodeType.TEXT_NODE) {
2676
+ if (node.innerText.trim() == "") continue;
2677
+ break;
2678
+ }
2679
+ const childElement = node;
2680
+ if (childElement.rawTagName == BREAK_TAG) {
2681
+ paragraphEndsWithBreak = true;
2682
+ }
2683
+ break;
2684
+ }
2685
+ if (!paragraphEndsWithBreak) {
2686
+ currentX = this.x;
2687
+ currentY += baseFont.size + this.lineSpacing;
2688
+ }
2689
+ }
2473
2690
  return {
2474
2691
  x: currentX,
2475
2692
  y: currentY,
@@ -2682,8 +2899,8 @@ var Image2 = class _Image extends LabelField {
2682
2899
  */
2683
2900
  static create(image2, x, y, width, height) {
2684
2901
  return __async(this, null, function* () {
2685
- const bitmap = yield ImageUtils.getBWBitmap(image2, width, height);
2686
- return new _Image(x, y, bitmap);
2902
+ const bitmap2 = yield ImageUtils.getBWBitmap(image2, width, height);
2903
+ return new _Image(x, y, bitmap2);
2687
2904
  });
2688
2905
  }
2689
2906
  };