label-printer 0.10.0 → 0.12.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.
package/dist/index.mjs CHANGED
@@ -246,6 +246,19 @@ function dotToPoint(dots, dpi) {
246
246
  const inch = dots / dpi;
247
247
  return Math.round(inch * pointsPerInch);
248
248
  }
249
+ function inToDot(inches, dpi, round = false) {
250
+ const res = inches * dpi;
251
+ if (round) return Math.round(res);
252
+ else return res;
253
+ }
254
+ function mmToDot(mm, dpi, round = false) {
255
+ const res = mm / 25.4 * dpi;
256
+ if (round) return Math.round(res);
257
+ else return res;
258
+ }
259
+ function unitToDot(value, dpi, unitSystem, round = false) {
260
+ return unitSystem === "imperial" ? inToDot(value, dpi, round) : mmToDot(value, dpi, round);
261
+ }
249
262
 
250
263
  // src/helpers/ImageDataParser.ts
251
264
  function parsePNG(buffer2) {
@@ -496,7 +509,6 @@ var ImageProcessor = class {
496
509
  */
497
510
  static getImageDataNode(image2, _target) {
498
511
  return __async(this, null, function* () {
499
- console.log("Processing image in Node.js environment");
500
512
  if (image2 instanceof Blob) {
501
513
  throw new Error("Blob input not supported in Node.js environment. Use file path or data URL instead.");
502
514
  }
@@ -665,7 +677,6 @@ var ImageProcessor = class {
665
677
  */
666
678
  static parse(buffer2, extension) {
667
679
  const normalizedExtension = extension.startsWith(".") ? extension.slice(1) : extension;
668
- console.log(`Parsing image with extension: ${normalizedExtension}`);
669
680
  if (normalizedExtension === "png") {
670
681
  return parsePNG(buffer2);
671
682
  } else if (normalizedExtension === "jpeg" || normalizedExtension === "jpg") {
@@ -1079,6 +1090,54 @@ ${widthBits} ${height}
1079
1090
  fs.writeFileSync(filePath, bytes);
1080
1091
  });
1081
1092
  }
1093
+ /**
1094
+ * Rotate a BW bitmap by 90, 180 or 270 degrees clockwise.
1095
+ * The bitmap uses 0=black, 1=white with MSB-first packing.
1096
+ */
1097
+ static rotateBWBitmap(bitmap2, rotation) {
1098
+ const srcWidthBytes = bitmap2.width;
1099
+ const srcWidthBits = srcWidthBytes * 8;
1100
+ const srcHeight = bitmap2.height;
1101
+ const src = bitmap2.bytes;
1102
+ const getBit = (col, row) => {
1103
+ const byteIndex = row * srcWidthBytes + (col >> 3);
1104
+ const bitIndex = 7 - (col & 7);
1105
+ return src[byteIndex] >> bitIndex & 1;
1106
+ };
1107
+ let dstWidthBits;
1108
+ let dstHeight;
1109
+ let getNewPixel;
1110
+ if (rotation === 90) {
1111
+ dstWidthBits = srcHeight;
1112
+ dstHeight = srcWidthBits;
1113
+ getNewPixel = (col, row) => getBit(srcWidthBits - 1 - row, col);
1114
+ } else if (rotation === 270) {
1115
+ dstWidthBits = srcHeight;
1116
+ dstHeight = srcWidthBits;
1117
+ getNewPixel = (col, row) => getBit(row, srcHeight - 1 - col);
1118
+ } else {
1119
+ dstWidthBits = srcWidthBits;
1120
+ dstHeight = srcHeight;
1121
+ getNewPixel = (col, row) => getBit(srcWidthBits - 1 - col, srcHeight - 1 - row);
1122
+ }
1123
+ const dstPad = dstWidthBits % 8 === 0 ? 0 : 8 - dstWidthBits % 8;
1124
+ const dstWidthBitsPadded = dstWidthBits + dstPad;
1125
+ const dstWidthBytes = dstWidthBitsPadded / 8;
1126
+ const dst = new Uint8Array(dstWidthBytes * dstHeight).fill(255);
1127
+ for (let row = 0; row < dstHeight; row++) {
1128
+ for (let col = 0; col < dstWidthBits; col++) {
1129
+ const bit = getNewPixel(col, row);
1130
+ const byteIndex = row * dstWidthBytes + (col >> 3);
1131
+ const mask = 1 << 7 - (col & 7);
1132
+ if (bit === 1) {
1133
+ dst[byteIndex] |= mask;
1134
+ } else {
1135
+ dst[byteIndex] &= ~mask & 255;
1136
+ }
1137
+ }
1138
+ }
1139
+ return { width: dstWidthBytes, height: dstHeight, bytes: dst };
1140
+ }
1082
1141
  static dilateOnce(bitmap2) {
1083
1142
  const widthBytes = bitmap2.width;
1084
1143
  const widthBits = widthBytes * 8;
@@ -1180,20 +1239,6 @@ var TSPLBitmapCommand = class _TSPLBitmapCommand extends TSPLVisualCommand {
1180
1239
  }
1181
1240
  };
1182
1241
 
1183
- // src/commands/tspl/types.ts
1184
- var alignmentToNumber = (alignment) => {
1185
- switch (alignment) {
1186
- case void 0:
1187
- return 0;
1188
- case "left":
1189
- return 1;
1190
- case "center":
1191
- return 2;
1192
- case "right":
1193
- return 3;
1194
- }
1195
- };
1196
-
1197
1242
  // src/commands/tspl/commands/basic/TSPLTextCommand.ts
1198
1243
  var TSPLTextCommand = class extends TSPLVisualCommand {
1199
1244
  constructor(content, x, y, font, rotation, xMultiplication, yMultiplication, alignment) {
@@ -1484,9 +1529,9 @@ var TSPLCommandGenerator = class _TSPLCommandGenerator {
1484
1529
  print(sets, copiesPerSet) {
1485
1530
  return new TSPLPrintCommand(sets, copiesPerSet);
1486
1531
  }
1487
- text(content, x, y, font, size) {
1532
+ text(content, x, y, font, size, rotation) {
1488
1533
  const fontName = font == "default" ? "0" : font;
1489
- return new TSPLTextCommand(content, x, y, fontName, 0, size, size, "left");
1534
+ return new TSPLTextCommand(content, x, y, fontName, rotation != null ? rotation : 0, size, size, "left");
1490
1535
  }
1491
1536
  upload(name, data) {
1492
1537
  return new TSPLDownload(name, data);
@@ -1513,10 +1558,10 @@ var TSPLCommandGenerator = class _TSPLCommandGenerator {
1513
1558
  image(image2, x, y, mode) {
1514
1559
  return new TSPLBitmapCommand(image2, x, y, mode);
1515
1560
  }
1516
- qrCode(content, width, x, y) {
1561
+ qrCode(content, width, x, y, rotation) {
1517
1562
  const cellCount = this.cellCount(content);
1518
1563
  const cellWidth = Math.round(width / cellCount);
1519
- return new TSPLQRCommand(`A${content}`, x, y, cellWidth, "H", "M");
1564
+ return new TSPLQRCommand(`A${content}`, x, y, cellWidth, "H", "M", rotation != null ? rotation : 0);
1520
1565
  }
1521
1566
  barCode(content, x, y, type, height, rotation, humanReadable, alignment, barWidth = 2) {
1522
1567
  const { narrow, wide } = _TSPLCommandGenerator.narrowWideFor(type, barWidth);
@@ -1566,6 +1611,20 @@ var TSPLCommandGenerator = class _TSPLCommandGenerator {
1566
1611
  };
1567
1612
  var TSPLCommandGenerator_default = new TSPLCommandGenerator();
1568
1613
 
1614
+ // src/commands/tspl/types.ts
1615
+ var alignmentToNumber = (alignment) => {
1616
+ switch (alignment) {
1617
+ case void 0:
1618
+ return 0;
1619
+ case "left":
1620
+ return 1;
1621
+ case "center":
1622
+ return 2;
1623
+ case "right":
1624
+ return 3;
1625
+ }
1626
+ };
1627
+
1569
1628
  // src/printers/index.ts
1570
1629
  var printers_exports = {};
1571
1630
  __export(printers_exports, {
@@ -2393,7 +2452,7 @@ var Printable = class {
2393
2452
  /**
2394
2453
  * Generates printable command for the given printer. Can be used to obtain a command for fields supported by the package then customizing it before printing
2395
2454
  * @param printer Printer to generate the command. Important because the command is printer language specific
2396
- * @returns A promise for a command. Most commands are syncronouse but some may require to access async resources
2455
+ * @returns A promise for a command. Most commands are synchronous but some may require to access async resources
2397
2456
  */
2398
2457
  commandForPrinter(printer, config) {
2399
2458
  return __async(this, null, function* () {
@@ -2412,8 +2471,105 @@ var Printable = class {
2412
2471
  }
2413
2472
  };
2414
2473
 
2474
+ // src/labels/types.ts
2475
+ var rotationForOrientation = (orientation) => {
2476
+ switch (orientation) {
2477
+ case "normal":
2478
+ return 0;
2479
+ case "left":
2480
+ return 90;
2481
+ case "upside-down":
2482
+ return 180;
2483
+ case "right":
2484
+ return 270;
2485
+ }
2486
+ };
2487
+
2415
2488
  // src/labels/Label.ts
2416
2489
  import * as fontkit from "fontkit";
2490
+
2491
+ // src/labels/fields/superClasses/LabelField.ts
2492
+ var LabelField = class extends Printable {
2493
+ };
2494
+
2495
+ // src/labels/fields/superClasses/RotatableLabelField.ts
2496
+ var RotatableLabelField = class extends LabelField {
2497
+ constructor() {
2498
+ super(...arguments);
2499
+ this.rotation = 0;
2500
+ }
2501
+ setRotation(rotation) {
2502
+ this.rotation = rotation;
2503
+ }
2504
+ getRotation() {
2505
+ return this.rotation;
2506
+ }
2507
+ };
2508
+
2509
+ // src/labels/RotatableContainer.ts
2510
+ var RotatableContainer = class extends RotatableLabelField {
2511
+ /**
2512
+ * @param size Size in dots
2513
+ */
2514
+ constructor(size) {
2515
+ super();
2516
+ this.fields = [];
2517
+ this.size = size;
2518
+ }
2519
+ /**
2520
+ * Place fields in the container
2521
+ * @param fields
2522
+ */
2523
+ add(...fields) {
2524
+ this.fields.push(...fields);
2525
+ }
2526
+ commandForLanguage(language, config) {
2527
+ return __async(this, null, function* () {
2528
+ const commandList = yield Promise.all(this.fields.map((field) => this.rotationAdjustedCommand(field, language, config)));
2529
+ return this.commandGeneratorFor(language).commandGroup(commandList);
2530
+ });
2531
+ }
2532
+ rotationAdjustedCommand(field, language, config) {
2533
+ return __async(this, null, function* () {
2534
+ let originalRotation = void 0;
2535
+ let originalPosition = void 0;
2536
+ if (field.hasOwnProperty("rotation")) {
2537
+ const rotatableField = field;
2538
+ originalRotation = rotatableField.getRotation();
2539
+ rotatableField.setRotation((originalRotation + this.rotation) % 360);
2540
+ }
2541
+ if (typeof field.getPosition === "function" && typeof field.setPosition === "function") {
2542
+ const positionedField = field;
2543
+ originalPosition = positionedField.getPosition();
2544
+ positionedField.setPosition(this.adjustPosition(originalPosition));
2545
+ }
2546
+ const command = yield field.commandForLanguage(language, config);
2547
+ if (originalRotation !== void 0) {
2548
+ const rotatableField = field;
2549
+ rotatableField.setRotation(originalRotation);
2550
+ }
2551
+ if (originalPosition !== void 0) {
2552
+ const positionedField = field;
2553
+ positionedField.setPosition(originalPosition);
2554
+ }
2555
+ return command;
2556
+ });
2557
+ }
2558
+ adjustPosition(position) {
2559
+ switch (this.rotation) {
2560
+ case 90:
2561
+ return { x: this.size.height - position.y, y: position.x };
2562
+ case 180:
2563
+ return { x: this.size.width - position.x, y: this.size.height - position.y };
2564
+ case 270:
2565
+ return { x: position.y, y: this.size.width - position.x };
2566
+ default:
2567
+ return position;
2568
+ }
2569
+ }
2570
+ };
2571
+
2572
+ // src/labels/Label.ts
2417
2573
  var DEFAULT_FONT_WEIGHT = 400;
2418
2574
  var DEFAULT_FONT_STYLE = "normal";
2419
2575
  var FONT_PREFIX = "f";
@@ -2422,10 +2578,7 @@ var Label = class extends Printable {
2422
2578
  super();
2423
2579
  this.fonts = {};
2424
2580
  this.density = 8;
2425
- /**
2426
- * List of fields on the label
2427
- */
2428
- this.fields = [];
2581
+ this.orientation = "normal";
2429
2582
  this.fontCounter = 0;
2430
2583
  this._textWidthCorrectionFactor = 0.935;
2431
2584
  this.width = width;
@@ -2433,6 +2586,9 @@ var Label = class extends Printable {
2433
2586
  this.unitSystem = dimensionUnit;
2434
2587
  this.dpi = dpi;
2435
2588
  this.density = density;
2589
+ const widthInDots = unitToDot(width, dpi, dimensionUnit);
2590
+ const heightInDots = unitToDot(height, dpi, dimensionUnit);
2591
+ this.container = new RotatableContainer({ width: widthInDots, height: heightInDots });
2436
2592
  }
2437
2593
  /**
2438
2594
  * Configuration used when generating commands
@@ -2463,11 +2619,17 @@ var Label = class extends Printable {
2463
2619
  setTextWidthCorrectionFactor(factor) {
2464
2620
  this._textWidthCorrectionFactor = factor;
2465
2621
  }
2622
+ /**
2623
+ * Change the orientation the label is printed in. This will rotate all fields in the container
2624
+ * @param orientation
2625
+ */
2626
+ setOrientation(orientation) {
2627
+ this.orientation = orientation;
2628
+ this.container.setRotation(rotationForOrientation(orientation));
2629
+ }
2466
2630
  commandForLanguage(language, config) {
2467
2631
  return __async(this, null, function* () {
2468
- const configuration = config != null ? config : this.printConfig;
2469
- const commandList = yield Promise.all(this.fields.map((field) => field.commandForLanguage(language, configuration)));
2470
- return this.commandGeneratorFor(language).commandGroup(commandList);
2632
+ return yield this.container.commandForLanguage(language, config);
2471
2633
  });
2472
2634
  }
2473
2635
  /**
@@ -2475,7 +2637,7 @@ var Label = class extends Printable {
2475
2637
  * @param fields
2476
2638
  */
2477
2639
  add(...fields) {
2478
- this.fields.push(...fields);
2640
+ this.container.add(...fields);
2479
2641
  }
2480
2642
  /**
2481
2643
  * Register a font to be used. Use the name provided in components to use the font.
@@ -2541,11 +2703,17 @@ var Label = class extends Printable {
2541
2703
  */
2542
2704
  fullCommand(language, gap, direction, mirror = false, gapOffset = 0, generator) {
2543
2705
  return __async(this, null, function* () {
2706
+ let finalDimations;
2707
+ if (this.orientation == "normal" || this.orientation == "upside-down") {
2708
+ finalDimations = { width: this.width, height: this.height };
2709
+ } else {
2710
+ finalDimations = { width: this.height, height: this.width };
2711
+ }
2544
2712
  const commands = [
2545
2713
  this.fontUploadCommands(generator),
2546
2714
  generator.setUp(
2547
- this.width,
2548
- this.height,
2715
+ finalDimations.width,
2716
+ finalDimations.height,
2549
2717
  gap,
2550
2718
  gapOffset,
2551
2719
  direction,
@@ -2576,10 +2744,10 @@ var Label = class extends Printable {
2576
2744
  const family = this.fonts[font.name];
2577
2745
  if (!family) return null;
2578
2746
  const style = (_a = font.style) != null ? _a : DEFAULT_FONT_STYLE;
2579
- const weigth = (_b = font.weight) != null ? _b : DEFAULT_FONT_WEIGHT;
2747
+ const weight = (_b = font.weight) != null ? _b : DEFAULT_FONT_WEIGHT;
2580
2748
  const fontKeys = Object.keys(family.fonts);
2581
2749
  const exactMatch = fontKeys.find(
2582
- (key) => family.fonts[key].style == style && family.fonts[key].weight == weigth
2750
+ (key) => family.fonts[key].style == style && family.fonts[key].weight == weight
2583
2751
  );
2584
2752
  if (exactMatch) {
2585
2753
  return family.fonts[exactMatch];
@@ -2589,7 +2757,7 @@ var Label = class extends Printable {
2589
2757
  let weigthDiff = 99999999;
2590
2758
  let selectedKey = "";
2591
2759
  sameStyleKeys.forEach((key) => {
2592
- const diff = Math.abs(weigth - family.fonts[key].weight);
2760
+ const diff = Math.abs(weight - family.fonts[key].weight);
2593
2761
  if (diff < weigthDiff) {
2594
2762
  weigthDiff = diff;
2595
2763
  selectedKey = key;
@@ -2617,10 +2785,6 @@ var Label = class extends Printable {
2617
2785
  }
2618
2786
  };
2619
2787
 
2620
- // src/labels/fields/LabelField.ts
2621
- var LabelField = class extends Printable {
2622
- };
2623
-
2624
2788
  // src/labels/fields/Line.ts
2625
2789
  var Line = class extends LabelField {
2626
2790
  /**
@@ -2649,7 +2813,7 @@ var UNDERLINE_TAG = "u";
2649
2813
  var STRIKE_TAG = ["s", "del", "strike"];
2650
2814
  var PARAGRAPH_TAG = "p";
2651
2815
  var BREAK_TAG = "br";
2652
- var Text = class extends LabelField {
2816
+ var Text = class extends RotatableLabelField {
2653
2817
  constructor(content, x, y, formatted = true) {
2654
2818
  super();
2655
2819
  this.font = { name: "default", size: 10 };
@@ -2679,6 +2843,13 @@ var Text = class extends LabelField {
2679
2843
  }
2680
2844
  return false;
2681
2845
  }
2846
+ setPosition(position) {
2847
+ this.x = position.x;
2848
+ this.y = position.y;
2849
+ }
2850
+ getPosition() {
2851
+ return { x: this.x, y: this.y };
2852
+ }
2682
2853
  /**
2683
2854
  * Sets the field to single line
2684
2855
  * @param width Max width of the text. Leave it undefined to allow the field to grow
@@ -2699,13 +2870,81 @@ var Text = class extends LabelField {
2699
2870
  this.height = height;
2700
2871
  }
2701
2872
  /**
2702
- * Set a font to use as a base. If no formatting is set on the text with a html tag, this will be used
2873
+ * Set a font to use as a base. If no formatting is set on the text with a html tag, this will be used
2703
2874
  * Note: The font name either has to be a built in font on your printer or a font
2704
2875
  * that is registered on the label using 'registerFont'.
2705
2876
  */
2706
2877
  setFont(font) {
2707
2878
  this.font = font;
2708
2879
  }
2880
+ // --- Rotation-aware position helpers ---
2881
+ /** Advance cursor by `amount` along the character direction */
2882
+ advanceChar(x, y, amount) {
2883
+ switch (this.rotation) {
2884
+ case 0:
2885
+ return { x: x + amount, y };
2886
+ case 90:
2887
+ return { x, y: y + amount };
2888
+ // 90° CW: chars go downward
2889
+ case 180:
2890
+ return { x: x - amount, y };
2891
+ case 270:
2892
+ return { x, y: y - amount };
2893
+ }
2894
+ }
2895
+ /** Advance to the next line (reset char axis, advance in line direction) */
2896
+ advanceLine(x, y, lineHeight) {
2897
+ switch (this.rotation) {
2898
+ case 0:
2899
+ return { x: this.x, y: y + lineHeight };
2900
+ case 90:
2901
+ return { x: x - lineHeight, y: this.y };
2902
+ // 90° CW: lines stack leftward (-x)
2903
+ case 180:
2904
+ return { x: this.x, y: y - lineHeight };
2905
+ case 270:
2906
+ return { x: x + lineHeight, y: this.y };
2907
+ }
2908
+ }
2909
+ /** How far into the current line the cursor is (for width constraint calc) */
2910
+ charOffset(x, y) {
2911
+ switch (this.rotation) {
2912
+ case 0:
2913
+ return x - this.x;
2914
+ case 90:
2915
+ return y - this.y;
2916
+ // 90° CW: char axis is +y
2917
+ case 180:
2918
+ return this.x - x;
2919
+ case 270:
2920
+ return this.y - y;
2921
+ }
2922
+ }
2923
+ /** How many lines deep we are (for height constraint calc) */
2924
+ lineOffset(x, y) {
2925
+ switch (this.rotation) {
2926
+ case 0:
2927
+ return y - this.y;
2928
+ case 90:
2929
+ return this.x - x;
2930
+ // 90° CW: line axis is -x
2931
+ case 180:
2932
+ return this.y - y;
2933
+ case 270:
2934
+ return x - this.x;
2935
+ }
2936
+ }
2937
+ /** Whether the cursor is at the start of its line (char axis at origin) */
2938
+ atLineStart(x, y) {
2939
+ switch (this.rotation) {
2940
+ case 0:
2941
+ case 180:
2942
+ return x === this.x;
2943
+ case 90:
2944
+ case 270:
2945
+ return y === this.y;
2946
+ }
2947
+ }
2709
2948
  commandForLanguage(language, config) {
2710
2949
  return __async(this, null, function* () {
2711
2950
  this.context = {
@@ -2752,9 +2991,10 @@ var Text = class extends LabelField {
2752
2991
  const elementNode = rootNode;
2753
2992
  const tag = elementNode.rawTagName;
2754
2993
  if (tag == BREAK_TAG) {
2994
+ const linePos = this.advanceLine(initialX, initialY, font.size + this.lineSpacing);
2755
2995
  return {
2756
- x: this.x,
2757
- y: initialY + font.size + this.lineSpacing,
2996
+ x: linePos.x,
2997
+ y: linePos.y,
2758
2998
  command: this.context.generator.commandGroup([])
2759
2999
  };
2760
3000
  }
@@ -2773,9 +3013,10 @@ var Text = class extends LabelField {
2773
3013
  baseFont.style = "italic";
2774
3014
  }
2775
3015
  if (tag == PARAGRAPH_TAG) {
2776
- if (initialX != this.x) {
2777
- currentX = this.x;
2778
- currentY = initialY + baseFont.size + this.lineSpacing;
3016
+ if (!this.atLineStart(initialX, initialY)) {
3017
+ const linePos = this.advanceLine(initialX, initialY, baseFont.size + this.lineSpacing);
3018
+ currentX = linePos.x;
3019
+ currentY = linePos.y;
2779
3020
  }
2780
3021
  }
2781
3022
  elementNode.childNodes.forEach((node) => {
@@ -2786,8 +3027,9 @@ var Text = class extends LabelField {
2786
3027
  });
2787
3028
  if (tag == PARAGRAPH_TAG) {
2788
3029
  if (!this.endsWithBreak(elementNode)) {
2789
- currentX = this.x;
2790
- currentY += baseFont.size + this.lineSpacing;
3030
+ const linePos = this.advanceLine(currentX, currentY, baseFont.size + this.lineSpacing);
3031
+ currentX = linePos.x;
3032
+ currentY = linePos.y;
2791
3033
  }
2792
3034
  }
2793
3035
  return {
@@ -2807,21 +3049,23 @@ var Text = class extends LabelField {
2807
3049
  const textWidhtFunction = this.textWidthFunction;
2808
3050
  let fullWidth = textWidhtFunction(content, font);
2809
3051
  if (this.width) {
2810
- const initialPadding = initialX - this.x;
3052
+ const initialPadding = this.charOffset(initialX, initialY);
2811
3053
  let rowWidth = this.width - initialPadding;
2812
3054
  if (rowWidth <= 0) {
2813
3055
  rowWidth = this.width;
2814
- initialX = this.x;
2815
- initialY += font.size + this.lineSpacing;
3056
+ const linePos = this.advanceLine(initialX, initialY, font.size + this.lineSpacing);
3057
+ initialX = linePos.x;
3058
+ initialY = linePos.y;
2816
3059
  }
2817
- if (initialX == this.x) {
3060
+ if (this.atLineStart(initialX, initialY)) {
2818
3061
  content = content.trimStart();
2819
3062
  fullWidth = textWidhtFunction(content, font);
2820
3063
  }
2821
3064
  if (fullWidth <= rowWidth) {
3065
+ const end = this.advanceChar(initialX, initialY, fullWidth);
2822
3066
  return {
2823
- x: initialX + fullWidth,
2824
- y: initialY,
3067
+ x: end.x,
3068
+ y: end.y,
2825
3069
  command: this.textCommand(content, initialX, initialY, font, features)
2826
3070
  };
2827
3071
  } else {
@@ -2835,8 +3079,9 @@ var Text = class extends LabelField {
2835
3079
  let finalY = y;
2836
3080
  do {
2837
3081
  if (remainingWidth < rowWidth) {
2838
- finalX = x + remainingWidth;
2839
- finalY = y;
3082
+ const end = this.advanceChar(x, y, remainingWidth);
3083
+ finalX = end.x;
3084
+ finalY = end.y;
2840
3085
  commands.push(this.textCommand(remainingContent, x, y, font, features));
2841
3086
  remainingContent = "";
2842
3087
  } else {
@@ -2854,8 +3099,9 @@ var Text = class extends LabelField {
2854
3099
  let originalRowEndIndex = rowEndIndex;
2855
3100
  rowWidth = this.width;
2856
3101
  if (rowEndIndex < 0) {
2857
- x = this.x;
2858
- y += font.size + this.lineSpacing;
3102
+ const linePos2 = this.advanceLine(x, y, font.size + this.lineSpacing);
3103
+ x = linePos2.x;
3104
+ y = linePos2.y;
2859
3105
  continue;
2860
3106
  }
2861
3107
  while (!(!isWhitespace(remainingContent.charAt(rowEndIndex)) && (rowEndIndex == remainingContent.length - 1 || isWhitespace(remainingContent.charAt(rowEndIndex + 1))) || isBreakAfterChar(remainingContent.charAt(rowEndIndex))) && rowEndIndex > 0) {
@@ -2933,12 +3179,14 @@ var Text = class extends LabelField {
2933
3179
  const thisRow = remainingContent.substring(0, rowEndIndex + 1);
2934
3180
  commands.push(this.textCommand(thisRow, x, y, font, features));
2935
3181
  if (nextRowStartIndex == remainingContent.length) {
2936
- finalX = x + remainingWidth;
2937
- finalY = y;
3182
+ const end = this.advanceChar(x, y, remainingWidth);
3183
+ finalX = end.x;
3184
+ finalY = end.y;
2938
3185
  }
2939
- x = this.x;
2940
- y += font.size + this.lineSpacing;
2941
- currentHeight = y - this.y;
3186
+ const linePos = this.advanceLine(x, y, font.size + this.lineSpacing);
3187
+ x = linePos.x;
3188
+ y = linePos.y;
3189
+ currentHeight = this.lineOffset(x, y);
2942
3190
  remainingContent = remainingContent.substring(nextRowStartIndex);
2943
3191
  remainingWidth = textWidhtFunction(remainingContent, font);
2944
3192
  }
@@ -2955,9 +3203,10 @@ var Text = class extends LabelField {
2955
3203
  };
2956
3204
  }
2957
3205
  } else {
3206
+ const end = this.advanceChar(initialX, initialY, fullWidth);
2958
3207
  return {
2959
- x: initialX + fullWidth,
2960
- y: initialY,
3208
+ x: end.x,
3209
+ y: end.y,
2961
3210
  command: this.textCommand(content, initialX, initialY, font, features)
2962
3211
  };
2963
3212
  }
@@ -2970,7 +3219,7 @@ var Text = class extends LabelField {
2970
3219
  const finalX = Math.round(x);
2971
3220
  const finalY = Math.round(y);
2972
3221
  let commands = [];
2973
- const textCommand = this.context.generator.text(text, finalX, finalY, finalFont, finalFontSize);
3222
+ const textCommand = this.context.generator.text(text, finalX, finalY, finalFont, finalFontSize, this.rotation);
2974
3223
  if (features.length == 0) {
2975
3224
  return textCommand;
2976
3225
  } else {
@@ -2987,13 +3236,28 @@ var Text = class extends LabelField {
2987
3236
  return this.context.generator.commandGroup(commands);
2988
3237
  }
2989
3238
  textLineCommand(width, x, y, lineHeight, linePercentage, fontSize) {
2990
- const sy = Math.round(y + fontSize * linePercentage - lineHeight / 2);
2991
- const sx = Math.round(x);
2992
- return this.context.generator.line(
2993
- { x: sx, y: sy },
2994
- { x: sx + width, y: sy },
2995
- lineHeight
2996
- );
3239
+ const offset = Math.round(fontSize * linePercentage - lineHeight / 2);
3240
+ let start;
3241
+ let end;
3242
+ switch (this.rotation) {
3243
+ case 0:
3244
+ start = { x: Math.round(x), y: Math.round(y) + offset };
3245
+ end = { x: Math.round(x) + Math.round(width), y: start.y };
3246
+ break;
3247
+ case 90:
3248
+ start = { x: Math.round(x) - offset, y: Math.round(y) };
3249
+ end = { x: start.x, y: Math.round(y) + Math.round(width) };
3250
+ break;
3251
+ case 180:
3252
+ start = { x: Math.round(x), y: Math.round(y) - offset };
3253
+ end = { x: Math.round(x) - Math.round(width), y: start.y };
3254
+ break;
3255
+ case 270:
3256
+ start = { x: Math.round(x) + offset, y: Math.round(y) };
3257
+ end = { x: start.x, y: Math.round(y) - Math.round(width) };
3258
+ break;
3259
+ }
3260
+ return this.context.generator.line(start, end, lineHeight);
2997
3261
  }
2998
3262
  getFontName(font) {
2999
3263
  var _a;
@@ -3007,22 +3271,25 @@ var Text = class extends LabelField {
3007
3271
  get textWidthFunction() {
3008
3272
  var _a, _b, _c;
3009
3273
  if (this.font.name == "default") {
3010
- return this.defaultTextWidth;
3274
+ return (text, font) => this.defaultTextWidth(text, font);
3011
3275
  } else {
3012
- return (_c = (_b = (_a = this.context) == null ? void 0 : _a.config) == null ? void 0 : _b.textWidth) != null ? _c : this.defaultTextWidth;
3276
+ return (_c = (_b = (_a = this.context) == null ? void 0 : _a.config) == null ? void 0 : _b.textWidth) != null ? _c : (text, font) => this.defaultTextWidth(text, font);
3013
3277
  }
3014
3278
  }
3015
3279
  /**
3016
- * This function is used to calculate the font size if no
3017
- * print config is provided. This will asume that the font has square characters
3280
+ * Fallback width estimate when no font metrics are available.
3281
+ * Uses the TSPL x-multiplication value (dotToPoint of the dot size) as
3282
+ * the per-character width, which matches the rendered width of font "0".
3018
3283
  */
3019
3284
  defaultTextWidth(text, font) {
3020
- return text.length * font.size;
3285
+ var _a, _b, _c;
3286
+ const dpi = (_c = (_b = (_a = this.context) == null ? void 0 : _a.config) == null ? void 0 : _b.dpi) != null ? _c : 203;
3287
+ return text.length * dotToPoint(font.size, dpi);
3021
3288
  }
3022
3289
  };
3023
3290
 
3024
3291
  // src/labels/fields/BarCode.ts
3025
- var BarCode = class extends LabelField {
3292
+ var BarCode = class extends RotatableLabelField {
3026
3293
  /**
3027
3294
  * @param content Content to encode
3028
3295
  * @param x X coordinate in dots
@@ -3040,16 +3307,19 @@ var BarCode = class extends LabelField {
3040
3307
  this.type = type;
3041
3308
  this.height = height;
3042
3309
  this.barWidth = barWidth;
3043
- this.rotation = 0;
3044
3310
  this.humanReadable = "none";
3045
3311
  this.alignment = "left";
3046
3312
  }
3047
- setRotation(rotation) {
3048
- this.rotation = rotation;
3049
- }
3050
3313
  setHumanReadable(humanReadable) {
3051
3314
  this.humanReadable = humanReadable;
3052
3315
  }
3316
+ setPosition(position) {
3317
+ this.x = position.x;
3318
+ this.y = position.y;
3319
+ }
3320
+ getPosition() {
3321
+ return { x: this.x, y: this.y };
3322
+ }
3053
3323
  commandForLanguage(language, _config) {
3054
3324
  return __async(this, null, function* () {
3055
3325
  return yield this.commandGeneratorFor(language).barCode(this.content, this.x, this.y, this.type, this.height, this.rotation, this.humanReadable, this.alignment, this.barWidth);
@@ -3058,16 +3328,43 @@ var BarCode = class extends LabelField {
3058
3328
  };
3059
3329
 
3060
3330
  // src/labels/fields/Image.ts
3061
- var Image2 = class _Image extends LabelField {
3331
+ var Image2 = class _Image extends RotatableLabelField {
3062
3332
  constructor(x, y, image2) {
3063
3333
  super();
3064
3334
  this.x = x;
3065
3335
  this.y = y;
3066
3336
  this.image = image2;
3067
3337
  }
3338
+ setPosition(position) {
3339
+ this.x = position.x;
3340
+ this.y = position.y;
3341
+ }
3342
+ getPosition() {
3343
+ return { x: this.x, y: this.y };
3344
+ }
3068
3345
  commandForLanguage(language, _config) {
3069
3346
  return __async(this, null, function* () {
3070
- return yield this.commandGeneratorFor(language).image(this.image, this.x, this.y);
3347
+ if (this.rotation === 0) {
3348
+ return yield this.commandGeneratorFor(language).image(this.image, this.x, this.y);
3349
+ }
3350
+ const srcW = this.image.width * 8;
3351
+ const srcH = this.image.height;
3352
+ const bitmap2 = ImageUtils.rotateBWBitmap(this.image, 360 - this.rotation);
3353
+ let dx = this.x;
3354
+ let dy = this.y;
3355
+ switch (this.rotation) {
3356
+ case 90:
3357
+ dx = this.x - srcH;
3358
+ break;
3359
+ case 180:
3360
+ dx = this.x - srcW;
3361
+ dy = this.y - srcH;
3362
+ break;
3363
+ case 270:
3364
+ dy = this.y - srcW;
3365
+ break;
3366
+ }
3367
+ return yield this.commandGeneratorFor(language).image(bitmap2, dx, dy);
3071
3368
  });
3072
3369
  }
3073
3370
  /**
@@ -3088,7 +3385,7 @@ var Image2 = class _Image extends LabelField {
3088
3385
  };
3089
3386
 
3090
3387
  // src/labels/fields/QRCode.ts
3091
- var QRCode = class extends LabelField {
3388
+ var QRCode = class extends RotatableLabelField {
3092
3389
  constructor(content, x, y, width) {
3093
3390
  super();
3094
3391
  this.content = content;
@@ -3096,9 +3393,16 @@ var QRCode = class extends LabelField {
3096
3393
  this.y = y;
3097
3394
  this.width = width;
3098
3395
  }
3396
+ setPosition(position) {
3397
+ this.x = position.x;
3398
+ this.y = position.y;
3399
+ }
3400
+ getPosition() {
3401
+ return { x: this.x, y: this.y };
3402
+ }
3099
3403
  commandForLanguage(language, config) {
3100
3404
  return __async(this, null, function* () {
3101
- return yield this.commandGeneratorFor(language).qrCode(this.content, this.width, this.x, this.y);
3405
+ return yield this.commandGeneratorFor(language).qrCode(this.content, this.width, this.x, this.y, this.rotation);
3102
3406
  });
3103
3407
  }
3104
3408
  };