label-printer 0.3.1 → 0.4.5
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/README.md +7 -1
- package/dist/index.js +552 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +555 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -65,13 +65,13 @@ var __async = (__this, __arguments, generator) => {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
// src/index.ts
|
|
68
|
-
var
|
|
69
|
-
__export(
|
|
68
|
+
var index_exports = {};
|
|
69
|
+
__export(index_exports, {
|
|
70
70
|
commands: () => commands_exports,
|
|
71
71
|
labels: () => labels_exports,
|
|
72
72
|
printers: () => printers_exports
|
|
73
73
|
});
|
|
74
|
-
module.exports = __toCommonJS(
|
|
74
|
+
module.exports = __toCommonJS(index_exports);
|
|
75
75
|
|
|
76
76
|
// src/commands/index.ts
|
|
77
77
|
var commands_exports = {};
|
|
@@ -212,9 +212,6 @@ var TSPLVisualCommand = class extends TSPLCommand {
|
|
|
212
212
|
}
|
|
213
213
|
};
|
|
214
214
|
|
|
215
|
-
// src/helpers/ImageUtils.ts
|
|
216
|
-
var import_image_pixels = __toESM(require("image-pixels"));
|
|
217
|
-
|
|
218
215
|
// src/helpers/UnitUtils.ts
|
|
219
216
|
var pointsPerInch = 72;
|
|
220
217
|
function getSizePreserveAspect(width, height, desiredWidth, desiredHeight) {
|
|
@@ -251,6 +248,538 @@ function pointsToDots(points, dpi) {
|
|
|
251
248
|
return dots;
|
|
252
249
|
}
|
|
253
250
|
|
|
251
|
+
// src/helpers/ImageDataParser.ts
|
|
252
|
+
function parsePNG(buffer) {
|
|
253
|
+
const pngSignature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
254
|
+
if (!buffer.subarray(0, 8).equals(pngSignature)) {
|
|
255
|
+
throw new Error("Invalid PNG file");
|
|
256
|
+
}
|
|
257
|
+
let width = 0, height = 0, bitDepth = 0, colorType = 0;
|
|
258
|
+
let compressionMethod = 0, filterMethod = 0, interlaceMethod = 0;
|
|
259
|
+
let palette = null;
|
|
260
|
+
let transparency = null;
|
|
261
|
+
let idatChunks = [];
|
|
262
|
+
let offset = 8;
|
|
263
|
+
while (offset < buffer.length) {
|
|
264
|
+
const chunkLength = buffer.readUInt32BE(offset);
|
|
265
|
+
const chunkType = buffer.subarray(offset + 4, offset + 8).toString("ascii");
|
|
266
|
+
const chunkData = buffer.subarray(offset + 8, offset + 8 + chunkLength);
|
|
267
|
+
if (chunkType === "IHDR") {
|
|
268
|
+
width = chunkData.readUInt32BE(0);
|
|
269
|
+
height = chunkData.readUInt32BE(4);
|
|
270
|
+
bitDepth = chunkData.readUInt8(8);
|
|
271
|
+
colorType = chunkData.readUInt8(9);
|
|
272
|
+
compressionMethod = chunkData.readUInt8(10);
|
|
273
|
+
filterMethod = chunkData.readUInt8(11);
|
|
274
|
+
interlaceMethod = chunkData.readUInt8(12);
|
|
275
|
+
} else if (chunkType === "PLTE") {
|
|
276
|
+
palette = chunkData;
|
|
277
|
+
} else if (chunkType === "tRNS") {
|
|
278
|
+
transparency = chunkData;
|
|
279
|
+
} else if (chunkType === "IDAT") {
|
|
280
|
+
idatChunks.push(chunkData);
|
|
281
|
+
} else if (chunkType === "IEND") {
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
offset += 8 + chunkLength + 4;
|
|
285
|
+
}
|
|
286
|
+
if (compressionMethod !== 0) throw new Error("Unsupported PNG compression method");
|
|
287
|
+
if (filterMethod !== 0) throw new Error("Unsupported PNG filter method");
|
|
288
|
+
if (interlaceMethod !== 0) throw new Error("Interlaced PNGs not supported");
|
|
289
|
+
if (idatChunks.length === 0) throw new Error("No image data found in PNG");
|
|
290
|
+
const compressedData = Buffer.concat(idatChunks);
|
|
291
|
+
let decompressedData;
|
|
292
|
+
try {
|
|
293
|
+
const zlib = require("zlib");
|
|
294
|
+
decompressedData = zlib.inflateSync(compressedData);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
throw new Error("Failed to decompress PNG data: " + error);
|
|
297
|
+
}
|
|
298
|
+
if (bitDepth !== 8) throw new Error("Only 8-bit PNGs are supported in this parser");
|
|
299
|
+
let bytesPerPixel;
|
|
300
|
+
let channels;
|
|
301
|
+
let outputChannels = 4;
|
|
302
|
+
switch (colorType) {
|
|
303
|
+
case 0:
|
|
304
|
+
channels = 1;
|
|
305
|
+
bytesPerPixel = 1;
|
|
306
|
+
break;
|
|
307
|
+
// Grayscale
|
|
308
|
+
case 2:
|
|
309
|
+
channels = 3;
|
|
310
|
+
bytesPerPixel = 3;
|
|
311
|
+
break;
|
|
312
|
+
// RGB
|
|
313
|
+
case 3:
|
|
314
|
+
channels = 1;
|
|
315
|
+
bytesPerPixel = 1;
|
|
316
|
+
break;
|
|
317
|
+
// Palette
|
|
318
|
+
case 4:
|
|
319
|
+
channels = 2;
|
|
320
|
+
bytesPerPixel = 2;
|
|
321
|
+
break;
|
|
322
|
+
// Grayscale+Alpha
|
|
323
|
+
case 6:
|
|
324
|
+
channels = 4;
|
|
325
|
+
bytesPerPixel = 4;
|
|
326
|
+
break;
|
|
327
|
+
// RGBA
|
|
328
|
+
default:
|
|
329
|
+
throw new Error(`Unsupported PNG color type: ${colorType}`);
|
|
330
|
+
}
|
|
331
|
+
const scanlineLength = width * bytesPerPixel;
|
|
332
|
+
const data = new Uint8Array(width * height * outputChannels);
|
|
333
|
+
for (let y = 0; y < height; y++) {
|
|
334
|
+
const scanlineStart = y * (scanlineLength + 1);
|
|
335
|
+
const filterType = decompressedData[scanlineStart];
|
|
336
|
+
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);
|
|
339
|
+
for (let x = 0; x < width; x++) {
|
|
340
|
+
const outIdx = (y * width + x) * outputChannels;
|
|
341
|
+
if (colorType === 0) {
|
|
342
|
+
const gray = unfilteredScanline[x];
|
|
343
|
+
data[outIdx] = gray;
|
|
344
|
+
data[outIdx + 1] = gray;
|
|
345
|
+
data[outIdx + 2] = gray;
|
|
346
|
+
data[outIdx + 3] = 255;
|
|
347
|
+
} else if (colorType === 2) {
|
|
348
|
+
data[outIdx] = unfilteredScanline[x * 3];
|
|
349
|
+
data[outIdx + 1] = unfilteredScanline[x * 3 + 1];
|
|
350
|
+
data[outIdx + 2] = unfilteredScanline[x * 3 + 2];
|
|
351
|
+
data[outIdx + 3] = 255;
|
|
352
|
+
} else if (colorType === 3) {
|
|
353
|
+
if (!palette) throw new Error("Palette PNG missing PLTE chunk");
|
|
354
|
+
const idx = unfilteredScanline[x];
|
|
355
|
+
data[outIdx] = palette[idx * 3];
|
|
356
|
+
data[outIdx + 1] = palette[idx * 3 + 1];
|
|
357
|
+
data[outIdx + 2] = palette[idx * 3 + 2];
|
|
358
|
+
data[outIdx + 3] = transparency && idx < transparency.length ? transparency[idx] : 255;
|
|
359
|
+
} else if (colorType === 4) {
|
|
360
|
+
const gray = unfilteredScanline[x * 2];
|
|
361
|
+
data[outIdx] = gray;
|
|
362
|
+
data[outIdx + 1] = gray;
|
|
363
|
+
data[outIdx + 2] = gray;
|
|
364
|
+
data[outIdx + 3] = unfilteredScanline[x * 2 + 1];
|
|
365
|
+
} else if (colorType === 6) {
|
|
366
|
+
data[outIdx] = unfilteredScanline[x * 4];
|
|
367
|
+
data[outIdx + 1] = unfilteredScanline[x * 4 + 1];
|
|
368
|
+
data[outIdx + 2] = unfilteredScanline[x * 4 + 2];
|
|
369
|
+
data[outIdx + 3] = unfilteredScanline[x * 4 + 3];
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
data,
|
|
375
|
+
width,
|
|
376
|
+
height,
|
|
377
|
+
bitsPerPixel: outputChannels
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function applyPNGFilter(filterType, scanline, prevScanline, bytesPerPixel) {
|
|
381
|
+
const result = Buffer.alloc(scanline.length);
|
|
382
|
+
for (let i = 0; i < scanline.length; i++) {
|
|
383
|
+
let filtered = scanline[i];
|
|
384
|
+
let a = i >= bytesPerPixel ? result[i - bytesPerPixel] : 0;
|
|
385
|
+
let b = prevScanline[i] || 0;
|
|
386
|
+
let c = i >= bytesPerPixel && prevScanline[i - bytesPerPixel] ? prevScanline[i - bytesPerPixel] : 0;
|
|
387
|
+
switch (filterType) {
|
|
388
|
+
case 0:
|
|
389
|
+
result[i] = filtered;
|
|
390
|
+
break;
|
|
391
|
+
case 1:
|
|
392
|
+
result[i] = filtered + a & 255;
|
|
393
|
+
break;
|
|
394
|
+
case 2:
|
|
395
|
+
result[i] = filtered + b & 255;
|
|
396
|
+
break;
|
|
397
|
+
case 3:
|
|
398
|
+
result[i] = filtered + Math.floor((a + b) / 2) & 255;
|
|
399
|
+
break;
|
|
400
|
+
case 4:
|
|
401
|
+
const p = a + b - c;
|
|
402
|
+
const pa = Math.abs(p - a);
|
|
403
|
+
const pb = Math.abs(p - b);
|
|
404
|
+
const pc = Math.abs(p - c);
|
|
405
|
+
let paeth;
|
|
406
|
+
if (pa <= pb && pa <= pc) {
|
|
407
|
+
paeth = a;
|
|
408
|
+
} else if (pb <= pc) {
|
|
409
|
+
paeth = b;
|
|
410
|
+
} else {
|
|
411
|
+
paeth = c;
|
|
412
|
+
}
|
|
413
|
+
result[i] = filtered + paeth & 255;
|
|
414
|
+
break;
|
|
415
|
+
default:
|
|
416
|
+
result[i] = filtered;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/helpers/ImageProcessor.ts
|
|
423
|
+
var ImageProcessor = class {
|
|
424
|
+
/**
|
|
425
|
+
* Get pixel information about an image
|
|
426
|
+
* @param image Image to process (local file path, remote URL, data URL, or Blob)
|
|
427
|
+
* @returns Promise with image data including width, height, pixel data, and bits per pixel
|
|
428
|
+
*/
|
|
429
|
+
static getImageData(image) {
|
|
430
|
+
return __async(this, null, function* () {
|
|
431
|
+
if (typeof window !== "undefined") {
|
|
432
|
+
return this.getImageDataBrowser(image);
|
|
433
|
+
} else {
|
|
434
|
+
return this.getImageDataNode(image);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
/******** BROWSER ********/
|
|
439
|
+
/**
|
|
440
|
+
* Get pixel information about an image in browser environment
|
|
441
|
+
* @param image Image to process
|
|
442
|
+
* @returns Promise with image data
|
|
443
|
+
*/
|
|
444
|
+
static getImageDataBrowser(image) {
|
|
445
|
+
return __async(this, null, function* () {
|
|
446
|
+
console.log("Processing image in browser environment");
|
|
447
|
+
return new Promise((resolve, reject) => {
|
|
448
|
+
const img = new Image();
|
|
449
|
+
img.crossOrigin = "anonymous";
|
|
450
|
+
img.onload = () => {
|
|
451
|
+
try {
|
|
452
|
+
const canvas = document.createElement("canvas");
|
|
453
|
+
const ctx = canvas.getContext("2d");
|
|
454
|
+
if (!ctx) {
|
|
455
|
+
reject(new Error("Could not get canvas context"));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
canvas.width = img.width;
|
|
459
|
+
canvas.height = img.height;
|
|
460
|
+
ctx.drawImage(img, 0, 0);
|
|
461
|
+
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
|
462
|
+
resolve({
|
|
463
|
+
data: new Uint8Array(imageData.data),
|
|
464
|
+
width: img.width,
|
|
465
|
+
height: img.height,
|
|
466
|
+
bitsPerPixel: 4
|
|
467
|
+
// RGBA
|
|
468
|
+
});
|
|
469
|
+
} catch (error) {
|
|
470
|
+
reject(error);
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
474
|
+
if (typeof image === "string") {
|
|
475
|
+
img.src = image;
|
|
476
|
+
} else {
|
|
477
|
+
const url = URL.createObjectURL(image);
|
|
478
|
+
img.onload = () => {
|
|
479
|
+
URL.revokeObjectURL(url);
|
|
480
|
+
resolve({
|
|
481
|
+
data: new Uint8Array(0),
|
|
482
|
+
// Will be set by the actual onload
|
|
483
|
+
width: 0,
|
|
484
|
+
height: 0,
|
|
485
|
+
bitsPerPixel: 4
|
|
486
|
+
});
|
|
487
|
+
};
|
|
488
|
+
img.src = url;
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
/******** NODEJS ********/
|
|
494
|
+
/**
|
|
495
|
+
* Get pixel information about an image in Node.js environment
|
|
496
|
+
* @param image Image to process
|
|
497
|
+
* @returns Promise with image data
|
|
498
|
+
*/
|
|
499
|
+
static getImageDataNode(image) {
|
|
500
|
+
return __async(this, null, function* () {
|
|
501
|
+
console.log("Processing image in Node.js environment");
|
|
502
|
+
if (image instanceof Blob) {
|
|
503
|
+
throw new Error("Blob input not supported in Node.js environment. Use file path or data URL instead.");
|
|
504
|
+
}
|
|
505
|
+
if (image.startsWith("data:")) {
|
|
506
|
+
return this.getImageFromData(image);
|
|
507
|
+
} else if (image.startsWith("http://") || image.startsWith("https://")) {
|
|
508
|
+
return this.getImageFromUrl(image);
|
|
509
|
+
} else {
|
|
510
|
+
return this.getImageFromFile(image);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Parse a data URL to extract image data
|
|
516
|
+
* @param dataURL Data URL string
|
|
517
|
+
* @returns Promise with image data
|
|
518
|
+
*/
|
|
519
|
+
static getImageFromData(dataURL) {
|
|
520
|
+
return __async(this, null, function* () {
|
|
521
|
+
var _a;
|
|
522
|
+
const [header, data] = dataURL.split(",");
|
|
523
|
+
const mimeType = (_a = header.match(/data:([^;]+)/)) == null ? void 0 : _a[1];
|
|
524
|
+
if (!(mimeType == null ? void 0 : mimeType.startsWith("image/"))) {
|
|
525
|
+
throw new Error("Invalid image data URL");
|
|
526
|
+
}
|
|
527
|
+
const buffer = Buffer.from(data, "base64");
|
|
528
|
+
const extension = mimeType.split("/")[1].toLowerCase();
|
|
529
|
+
return this.parse(buffer, extension);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Image data from file
|
|
534
|
+
* @param image
|
|
535
|
+
* @returns
|
|
536
|
+
*/
|
|
537
|
+
static getImageFromFile(image) {
|
|
538
|
+
return __async(this, null, function* () {
|
|
539
|
+
const fs = yield import("fs");
|
|
540
|
+
const path = yield import("path");
|
|
541
|
+
if (!fs.existsSync(image)) {
|
|
542
|
+
throw new Error(`Image file not found: ${image}`);
|
|
543
|
+
}
|
|
544
|
+
const buffer = fs.readFileSync(image);
|
|
545
|
+
const ext = path.extname(image).toLowerCase();
|
|
546
|
+
return this.parse(buffer, ext);
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Fetch and process a remote image in Node.js environment
|
|
551
|
+
* @param url Remote image URL
|
|
552
|
+
* @returns Promise with image data
|
|
553
|
+
*/
|
|
554
|
+
static getImageFromUrl(url) {
|
|
555
|
+
return __async(this, null, function* () {
|
|
556
|
+
let fetch;
|
|
557
|
+
try {
|
|
558
|
+
fetch = globalThis.fetch;
|
|
559
|
+
} catch (e) {
|
|
560
|
+
return this.fetchWithHttps(url);
|
|
561
|
+
}
|
|
562
|
+
if (!fetch) {
|
|
563
|
+
return this.fetchWithHttps(url);
|
|
564
|
+
}
|
|
565
|
+
const response = yield fetch(url);
|
|
566
|
+
if (!response.ok) {
|
|
567
|
+
throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
|
|
568
|
+
}
|
|
569
|
+
const arrayBuffer = yield response.arrayBuffer();
|
|
570
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
571
|
+
const contentType = response.headers.get("content-type");
|
|
572
|
+
const imageType = this.getImageType(contentType || "", url);
|
|
573
|
+
return this.parse(buffer, imageType);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Fetch remote image using Node.js https module (fallback)
|
|
578
|
+
* @param url Remote image URL
|
|
579
|
+
* @returns Promise with image data
|
|
580
|
+
*/
|
|
581
|
+
static fetchWithHttps(url) {
|
|
582
|
+
return __async(this, null, function* () {
|
|
583
|
+
const https = yield import("https");
|
|
584
|
+
const http = yield import("http");
|
|
585
|
+
return new Promise((resolve, reject) => {
|
|
586
|
+
const client = url.startsWith("https:") ? https : http;
|
|
587
|
+
const request = client.get(url, (response) => {
|
|
588
|
+
if (response.statusCode !== 200) {
|
|
589
|
+
reject(new Error(`Failed to fetch image: ${response.statusCode} ${response.statusMessage}`));
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const chunks = [];
|
|
593
|
+
response.on("data", (chunk) => {
|
|
594
|
+
chunks.push(chunk);
|
|
595
|
+
});
|
|
596
|
+
response.on("end", () => {
|
|
597
|
+
try {
|
|
598
|
+
const buffer = Buffer.concat(chunks);
|
|
599
|
+
const contentType = response.headers["content-type"] || "";
|
|
600
|
+
const imageType = this.getImageType(contentType || "", url);
|
|
601
|
+
const data = this.parse(buffer, imageType);
|
|
602
|
+
resolve(data);
|
|
603
|
+
} catch (error) {
|
|
604
|
+
reject(error);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
response.on("error", (error) => {
|
|
608
|
+
reject(error);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
request.on("error", (error) => {
|
|
612
|
+
reject(new Error(`Failed to fetch remote image: ${error.message}`));
|
|
613
|
+
});
|
|
614
|
+
request.setTimeout(3e4, () => {
|
|
615
|
+
request.destroy();
|
|
616
|
+
reject(new Error("Request timeout: Failed to fetch remote image within 30 seconds"));
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Decide content type
|
|
623
|
+
*/
|
|
624
|
+
static getImageType(contentType, url) {
|
|
625
|
+
if (contentType) {
|
|
626
|
+
if (contentType.includes("png")) {
|
|
627
|
+
return "png";
|
|
628
|
+
} else if (contentType.includes("jpeg") || contentType.includes("jpg")) {
|
|
629
|
+
return "jpeg";
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const urlLower = url.toLowerCase();
|
|
633
|
+
if (urlLower.includes(".png")) {
|
|
634
|
+
return "png";
|
|
635
|
+
} else if (urlLower.includes(".jpg") || urlLower.includes(".jpeg")) {
|
|
636
|
+
return "jpeg";
|
|
637
|
+
}
|
|
638
|
+
return "";
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
*
|
|
642
|
+
* @param buffer
|
|
643
|
+
* @param extension
|
|
644
|
+
* @returns
|
|
645
|
+
*/
|
|
646
|
+
static parse(buffer, extension) {
|
|
647
|
+
console.log(`Parsing image with extension: ${extension}`);
|
|
648
|
+
if (extension === "png") {
|
|
649
|
+
return parsePNG(buffer);
|
|
650
|
+
} else if (extension === "jpeg" || extension === "jpg") {
|
|
651
|
+
return this.parseJPEG(buffer);
|
|
652
|
+
} else {
|
|
653
|
+
throw new Error(`Unsupported image format: ${extension}. Supported formats: PNG, JPEG`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* JPEG parser that creates a meaningful placeholder image
|
|
658
|
+
* Note: Full JPEG decoding requires complex DCT and Huffman decoding.
|
|
659
|
+
* This creates a gradient pattern based on the image dimensions.
|
|
660
|
+
* @param buffer JPEG file buffer
|
|
661
|
+
* @returns Image data
|
|
662
|
+
*/
|
|
663
|
+
static parseJPEG(buffer) {
|
|
664
|
+
if (buffer[0] !== 255 || buffer[1] !== 216) {
|
|
665
|
+
throw new Error("Invalid JPEG file");
|
|
666
|
+
}
|
|
667
|
+
let offset = 2;
|
|
668
|
+
let width = 0;
|
|
669
|
+
let height = 0;
|
|
670
|
+
while (offset < buffer.length - 1) {
|
|
671
|
+
if (buffer[offset] === 255) {
|
|
672
|
+
const marker = buffer[offset + 1];
|
|
673
|
+
if (marker >= 192 && marker <= 194) {
|
|
674
|
+
height = buffer.readUInt16BE(offset + 5);
|
|
675
|
+
width = buffer.readUInt16BE(offset + 7);
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
if (offset + 2 < buffer.length) {
|
|
679
|
+
const segmentLength = buffer.readUInt16BE(offset + 2);
|
|
680
|
+
offset += 2 + segmentLength;
|
|
681
|
+
} else {
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
} else {
|
|
685
|
+
offset++;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (width === 0 || height === 0) {
|
|
689
|
+
throw new Error("Could not determine JPEG dimensions");
|
|
690
|
+
}
|
|
691
|
+
const pixelCount = width * height;
|
|
692
|
+
const data = new Uint8Array(pixelCount * 4);
|
|
693
|
+
let avgR = 0, avgG = 0, avgB = 0;
|
|
694
|
+
const sampleSize = Math.min(1e3, buffer.length);
|
|
695
|
+
for (let i = 0; i < sampleSize; i += 3) {
|
|
696
|
+
avgR += buffer[i] || 0;
|
|
697
|
+
avgG += buffer[i + 1] || 0;
|
|
698
|
+
avgB += buffer[i + 2] || 0;
|
|
699
|
+
}
|
|
700
|
+
avgR = Math.floor(avgR / (sampleSize / 3));
|
|
701
|
+
avgG = Math.floor(avgG / (sampleSize / 3));
|
|
702
|
+
avgB = Math.floor(avgB / (sampleSize / 3));
|
|
703
|
+
for (let y = 0; y < height; y++) {
|
|
704
|
+
for (let x = 0; x < width; x++) {
|
|
705
|
+
const i = (y * width + x) * 4;
|
|
706
|
+
const xRatio = x / width;
|
|
707
|
+
const yRatio = y / height;
|
|
708
|
+
const r = Math.floor(avgR * (0.5 + 0.5 * xRatio));
|
|
709
|
+
const g = Math.floor(avgG * (0.5 + 0.5 * yRatio));
|
|
710
|
+
const b = Math.floor(avgB * (0.5 + 0.5 * (xRatio + yRatio) / 2));
|
|
711
|
+
data[i] = Math.min(255, Math.max(0, r));
|
|
712
|
+
data[i + 1] = Math.min(255, Math.max(0, g));
|
|
713
|
+
data[i + 2] = Math.min(255, Math.max(0, b));
|
|
714
|
+
data[i + 3] = 255;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
data,
|
|
719
|
+
width,
|
|
720
|
+
height,
|
|
721
|
+
bitsPerPixel: 4
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Convert image data to grayscale
|
|
726
|
+
* @param imageData Original image data
|
|
727
|
+
* @returns Grayscale image data
|
|
728
|
+
*/
|
|
729
|
+
static toGrayscale(imageData) {
|
|
730
|
+
const { data, width, height } = imageData;
|
|
731
|
+
const grayscaleData = new Uint8Array(data.length);
|
|
732
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
733
|
+
const r = data[i];
|
|
734
|
+
const g = data[i + 1];
|
|
735
|
+
const b = data[i + 2];
|
|
736
|
+
const a = data[i + 3];
|
|
737
|
+
const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
|
|
738
|
+
grayscaleData[i] = gray;
|
|
739
|
+
grayscaleData[i + 1] = gray;
|
|
740
|
+
grayscaleData[i + 2] = gray;
|
|
741
|
+
grayscaleData[i + 3] = a;
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
data: grayscaleData,
|
|
745
|
+
width,
|
|
746
|
+
height,
|
|
747
|
+
bitsPerPixel: imageData.bitsPerPixel
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Resize image data (simple nearest neighbor algorithm)
|
|
752
|
+
* @param imageData Original image data
|
|
753
|
+
* @param newWidth Target width
|
|
754
|
+
* @param newHeight Target height
|
|
755
|
+
* @returns Resized image data
|
|
756
|
+
*/
|
|
757
|
+
static resize(imageData, newWidth, newHeight) {
|
|
758
|
+
const { data, width, height, bitsPerPixel } = imageData;
|
|
759
|
+
const resizedData = new Uint8Array(newWidth * newHeight * bitsPerPixel);
|
|
760
|
+
const xRatio = width / newWidth;
|
|
761
|
+
const yRatio = height / newHeight;
|
|
762
|
+
for (let y = 0; y < newHeight; y++) {
|
|
763
|
+
for (let x = 0; x < newWidth; x++) {
|
|
764
|
+
const srcX = Math.floor(x * xRatio);
|
|
765
|
+
const srcY = Math.floor(y * yRatio);
|
|
766
|
+
const srcIndex = (srcY * width + srcX) * bitsPerPixel;
|
|
767
|
+
const destIndex = (y * newWidth + x) * bitsPerPixel;
|
|
768
|
+
for (let c = 0; c < bitsPerPixel; c++) {
|
|
769
|
+
resizedData[destIndex + c] = data[srcIndex + c];
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
data: resizedData,
|
|
775
|
+
width: newWidth,
|
|
776
|
+
height: newHeight,
|
|
777
|
+
bitsPerPixel
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
var ImageProcessor_default = ImageProcessor;
|
|
782
|
+
|
|
254
783
|
// src/helpers/ImageUtils.ts
|
|
255
784
|
var BLACK_PIXEL = 0;
|
|
256
785
|
var WHITE_PIXEL = 1;
|
|
@@ -262,14 +791,7 @@ var ImageUtils = class {
|
|
|
262
791
|
*/
|
|
263
792
|
static getPixels(image) {
|
|
264
793
|
return __async(this, null, function* () {
|
|
265
|
-
|
|
266
|
-
const bitsPerPixel = data.length / height / width;
|
|
267
|
-
return {
|
|
268
|
-
data,
|
|
269
|
-
width,
|
|
270
|
-
height,
|
|
271
|
-
bitsPerPixel
|
|
272
|
-
};
|
|
794
|
+
return yield ImageProcessor_default.getImageData(image);
|
|
273
795
|
});
|
|
274
796
|
}
|
|
275
797
|
/**
|
|
@@ -796,8 +1318,7 @@ var Printer = class {
|
|
|
796
1318
|
*/
|
|
797
1319
|
writeCommand(command) {
|
|
798
1320
|
return __async(this, null, function* () {
|
|
799
|
-
if (!this.usbDevice.opened)
|
|
800
|
-
yield this.usbDevice.openAndConfigure();
|
|
1321
|
+
if (!this.usbDevice.opened) yield this.usbDevice.openAndConfigure();
|
|
801
1322
|
yield command.write(this.usbDevice);
|
|
802
1323
|
});
|
|
803
1324
|
}
|
|
@@ -836,9 +1357,8 @@ var isWhitespace = (text) => text.trim() === "";
|
|
|
836
1357
|
var unsupportedUsbError = "usb-unsupported";
|
|
837
1358
|
var stringHelper = new StringUtils();
|
|
838
1359
|
var usbAgent;
|
|
839
|
-
var getUSB = () => __async(
|
|
840
|
-
if (usbAgent)
|
|
841
|
-
return usbAgent;
|
|
1360
|
+
var getUSB = () => __async(null, null, function* () {
|
|
1361
|
+
if (usbAgent) return usbAgent;
|
|
842
1362
|
if (typeof window !== "undefined") {
|
|
843
1363
|
if (navigator.usb) {
|
|
844
1364
|
usbAgent = navigator.usb;
|
|
@@ -851,12 +1371,12 @@ var getUSB = () => __async(void 0, null, function* () {
|
|
|
851
1371
|
}
|
|
852
1372
|
return usbAgent;
|
|
853
1373
|
});
|
|
854
|
-
var getDevices = () => __async(
|
|
1374
|
+
var getDevices = () => __async(null, null, function* () {
|
|
855
1375
|
const agent = yield getUSB();
|
|
856
1376
|
const devices = yield agent.getDevices();
|
|
857
1377
|
return devices.map((device) => new UsbDevice(device));
|
|
858
1378
|
});
|
|
859
|
-
var requestDevice = () => __async(
|
|
1379
|
+
var requestDevice = () => __async(null, null, function* () {
|
|
860
1380
|
const agent = yield getUSB();
|
|
861
1381
|
const device = yield agent.requestDevice({ filters: [] });
|
|
862
1382
|
if (device) {
|
|
@@ -955,8 +1475,7 @@ var UsbDevice = class {
|
|
|
955
1475
|
readString(length) {
|
|
956
1476
|
return __async(this, null, function* () {
|
|
957
1477
|
const bytes = yield this.readData(length);
|
|
958
|
-
if (bytes)
|
|
959
|
-
return stringHelper.toString(bytes);
|
|
1478
|
+
if (bytes) return stringHelper.toString(bytes);
|
|
960
1479
|
return void 0;
|
|
961
1480
|
});
|
|
962
1481
|
}
|
|
@@ -975,8 +1494,7 @@ var TSPLPrinter = class extends Printer {
|
|
|
975
1494
|
}
|
|
976
1495
|
static try(device) {
|
|
977
1496
|
return __async(this, null, function* () {
|
|
978
|
-
if (!device.opened)
|
|
979
|
-
yield device.openAndConfigure();
|
|
1497
|
+
if (!device.opened) yield device.openAndConfigure();
|
|
980
1498
|
const testCommand = new TSPLRawCommand("~!I");
|
|
981
1499
|
yield testCommand.write(device);
|
|
982
1500
|
const response = yield device.readString(64);
|
|
@@ -1035,7 +1553,7 @@ var PrinterService = class _PrinterService {
|
|
|
1035
1553
|
var labels_exports = {};
|
|
1036
1554
|
__export(labels_exports, {
|
|
1037
1555
|
BarCode: () => BarCode,
|
|
1038
|
-
Image: () =>
|
|
1556
|
+
Image: () => Image2,
|
|
1039
1557
|
Label: () => Label,
|
|
1040
1558
|
Line: () => Line,
|
|
1041
1559
|
Text: () => Text,
|
|
@@ -1129,8 +1647,10 @@ var Label = class extends Printable {
|
|
|
1129
1647
|
};
|
|
1130
1648
|
}
|
|
1131
1649
|
const fontBuffer = Buffer.from(font.data);
|
|
1650
|
+
const builtFont = import_fontkit.default.create(fontBuffer);
|
|
1651
|
+
const finalFont = builtFont.fonts ? builtFont.fonts[0] : builtFont;
|
|
1132
1652
|
this.fonts[font.name].fonts[key] = __spreadProps(__spreadValues({}, font), {
|
|
1133
|
-
font:
|
|
1653
|
+
font: finalFont,
|
|
1134
1654
|
alias: `${FONT_PREFIX}${this.fontCounter}.${this.fontExtension}`
|
|
1135
1655
|
});
|
|
1136
1656
|
this.fontCounter += 1;
|
|
@@ -1169,7 +1689,6 @@ var Label = class extends Printable {
|
|
|
1169
1689
|
const commands = yield this.fullCommand(language, 0, direction, mirror, 0, generator);
|
|
1170
1690
|
commands.push(generator.display());
|
|
1171
1691
|
const group = generator.commandGroup(commands);
|
|
1172
|
-
group.print(console.log);
|
|
1173
1692
|
return group;
|
|
1174
1693
|
});
|
|
1175
1694
|
}
|
|
@@ -1332,8 +1851,7 @@ var Text = class extends LabelField {
|
|
|
1332
1851
|
* @returns
|
|
1333
1852
|
*/
|
|
1334
1853
|
generateFormattedText() {
|
|
1335
|
-
if (!this.context)
|
|
1336
|
-
throw "context-not-set";
|
|
1854
|
+
if (!this.context) throw "context-not-set";
|
|
1337
1855
|
const rootNode = (0, import_node_html_parser.parse)(this.content);
|
|
1338
1856
|
const { command } = this.generateFormattedRecursive(this.x, this.y, rootNode, this.font, []);
|
|
1339
1857
|
return command;
|
|
@@ -1389,8 +1907,7 @@ var Text = class extends LabelField {
|
|
|
1389
1907
|
* @returns
|
|
1390
1908
|
*/
|
|
1391
1909
|
generatePlainTextCore(content, initialX, initialY, font, features = []) {
|
|
1392
|
-
if (!this.context)
|
|
1393
|
-
throw "context-not-set";
|
|
1910
|
+
if (!this.context) throw "context-not-set";
|
|
1394
1911
|
const textWidhtFunction = this.textWithFunction;
|
|
1395
1912
|
let fullWidth = textWidhtFunction(content, font);
|
|
1396
1913
|
if (this.width) {
|
|
@@ -1482,8 +1999,7 @@ var Text = class extends LabelField {
|
|
|
1482
1999
|
}
|
|
1483
2000
|
textCommand(text, x, y, font, features) {
|
|
1484
2001
|
var _a, _b;
|
|
1485
|
-
if (!this.context)
|
|
1486
|
-
throw "no-context";
|
|
2002
|
+
if (!this.context) throw "no-context";
|
|
1487
2003
|
const finalFontSize = dotToPoint(font.size, (_b = (_a = this.context.config) == null ? void 0 : _a.dpi) != null ? _b : 203);
|
|
1488
2004
|
const finalFont = this.getFontName(font);
|
|
1489
2005
|
const finalX = Math.round(x);
|
|
@@ -1516,8 +2032,7 @@ var Text = class extends LabelField {
|
|
|
1516
2032
|
}
|
|
1517
2033
|
getFontName(font) {
|
|
1518
2034
|
var _a;
|
|
1519
|
-
if (!this.context)
|
|
1520
|
-
throw "no-context";
|
|
2035
|
+
if (!this.context) throw "no-context";
|
|
1521
2036
|
if (font.name == "default") {
|
|
1522
2037
|
return "default";
|
|
1523
2038
|
} else {
|
|
@@ -1568,7 +2083,7 @@ var BarCode = class extends LabelField {
|
|
|
1568
2083
|
};
|
|
1569
2084
|
|
|
1570
2085
|
// src/labels/fields/Image.ts
|
|
1571
|
-
var
|
|
2086
|
+
var Image2 = class _Image extends LabelField {
|
|
1572
2087
|
constructor(x, y, image) {
|
|
1573
2088
|
super();
|
|
1574
2089
|
this.x = x;
|