zpl-image-ts 1.0.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Mark Warren (original zpl-image, https://github.com/metafloor/zpl-image)
4
+ Copyright (c) 2026 Mika Salminen (TypeScript port)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,62 @@
1
+ # Credits and attribution
2
+
3
+ This package is a TypeScript port of [`zpl-image`](https://github.com/metafloor/zpl-image)
4
+ by **Mark Warren** (`metafloor`), originally published 2019 under the MIT license.
5
+
6
+ The algorithm in `src/index.ts` -- luminance thresholding, optional rotation,
7
+ 1-bit packing, deflate compression, base64 + CRC16 envelope -- is a direct
8
+ translation of the corresponding routines in the upstream
9
+ `zpl-image.js`. The bit-level output of `rgbaToZ64` is verified to match the
10
+ original implementation byte-for-byte via the golden vector test suite under
11
+ `test/fixtures/`.
12
+
13
+ ## What was changed in this port
14
+
15
+ - Rewritten in TypeScript with full type declarations.
16
+ - Isomorphic: runs in Node.js 18+ and any modern browser with zero runtime
17
+ dependencies. Uses the web-standard `CompressionStream('deflate')`
18
+ (global in Node 18+ and all evergreen browsers since 2023) instead of
19
+ `pako` or `node:zlib`. Uses native
20
+ `Uint8Array.prototype.toBase64()` when available (Node 22+, Chrome 133+,
21
+ Firefox 133+, Safari 18.2+) with a portable `btoa` fallback.
22
+ - Public `rgbaToZ64` is async (returns `Promise<Result>`) because
23
+ `CompressionStream` is stream-based. Output is byte-identical to upstream.
24
+ - ESM with named exports (the original was a UMD bundle whose
25
+ `module.exports = factory()` pattern hid named exports from Node's
26
+ cjs-module-lexer, breaking `import {rgbaToZ64}` under real ESM).
27
+ - Narrowed scope: `rgbaToZ64` and `rgbaToACS` are exported.
28
+ `imageToZ64` / `imageToACS` are browser DOM helpers that wrap
29
+ `<canvas>.getImageData()`. With `createImageBitmap()` +
30
+ `OffscreenCanvas` they are a one-liner at the call site, so they are not
31
+ bundled.
32
+ - Vitest test suite with golden vectors captured from the upstream package
33
+ guarantees bit-exact compatibility for both `rgbaToZ64` and `rgbaToACS`.
34
+
35
+ ## Original upstream license
36
+
37
+ The upstream `zpl-image` is distributed under the MIT license. The full
38
+ upstream `LICENSE` text reads:
39
+
40
+ ```
41
+ zpl-image
42
+
43
+ Copyright 2019 Mark Warren
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ of this software and associated documentation files (the "Software"), to deal
47
+ in the Software without restriction, including without limitation the rights
48
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ copies of the Software, and to permit persons to whom the Software is
50
+ furnished to do so, subject to the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be included in all
53
+ copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
61
+ SOFTWARE.
62
+ ```
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # zpl-image-ts
2
+
3
+ TypeScript port of [`metafloor/zpl-image`](https://github.com/metafloor/zpl-image).
4
+ Converts an RGBA bitmap into a Zebra `^GFA`-ready Z64 payload (zlib-deflate +
5
+ base64 + CRC16 envelope). Isomorphic: runs in Node.js 18+ and any modern
6
+ browser, with zero runtime dependencies.
7
+
8
+ ```ts
9
+ import {rgbaToZ64} from 'zpl-image-ts';
10
+
11
+ const result = await rgbaToZ64(rgbaBuffer, width, {rotate: 'R'});
12
+ // result.gfa === `^GFA,${result.length},${result.length},${result.rowlen},${result.z64}`
13
+ const zpl = '^XA' + result.gfa + '^FS^XZ';
14
+ ```
15
+
16
+ ## Import paths
17
+
18
+ Five entry points -- pick whichever matches what you need:
19
+
20
+ ```ts
21
+ // Convenience barrel. Bundlers with sideEffects:false respect it and
22
+ // tree-shake unused encoders automatically.
23
+ import {rgbaToZ64, rgbaToACS, buildZpl} from 'zpl-image-ts';
24
+
25
+ // Explicit subpath -- guarantees the other encoder, its compression glue,
26
+ // and (for /z64) the 256-entry CRC16 table are never bundled.
27
+ import {rgbaToZ64} from 'zpl-image-ts/z64';
28
+ import {rgbaToACS} from 'zpl-image-ts/acs';
29
+
30
+ // Browser DOM helpers -- rasterise an ImageBitmapSource (HTMLImageElement,
31
+ // Blob, ImageData, ImageBitmap, OffscreenCanvas, ...) before encoding.
32
+ // Pulls in zero DOM types on the server side because it lives behind its
33
+ // own subpath.
34
+ import {imageToZ64, imageToACS} from 'zpl-image-ts/browser';
35
+
36
+ // ZPL label builder -- wrap one or more ^GFA blocks in a complete
37
+ // ^XA...^XZ payload with darkness, print rate, copies, etc. Tiny and
38
+ // dependency-free, so importing it from the barrel is fine too.
39
+ import {buildZpl} from 'zpl-image-ts/zpl';
40
+ ```
41
+
42
+ All five paths re-export `RgbaInput` and `RgbaOptions` where relevant.
43
+ The encoder subpaths additionally export their own `RgbaToZ64Result` /
44
+ `RgbaToACSResult` types; the `zpl` subpath exports `ZplLabelOptions`.
45
+
46
+ ## Why a fork?
47
+
48
+ - Native TypeScript types (no community-maintained shim drift).
49
+ - Pure ESM with named exports -- the upstream UMD bundle's
50
+ `module.exports = factory()` shape is opaque to Node's `cjs-module-lexer`,
51
+ so `import {rgbaToZ64} from 'zpl-image'` throws `SyntaxError: The
52
+ requested module does not provide an export named 'rgbaToZ64'` under
53
+ real Node ESM (tsx/esbuild masks this).
54
+ - Isomorphic with zero dependencies: drops `pako` in favour of the
55
+ web-standard `CompressionStream('deflate')` (global in Node 18+ and all
56
+ evergreen browsers since 2023). No Node-specific imports.
57
+ - `result.gfa` ergonomic: every encoder result includes a ready-to-emit
58
+ `^GFA,length,length,rowlen,payload` string, so call sites do not have
59
+ to template the four fields by hand.
60
+ - Optional browser DOM helpers (`imageToZ64` / `imageToACS`) under the
61
+ separate `zpl-image-ts/browser` entry point, tree-shaken out of
62
+ server bundles.
63
+ - Optional ZPL label builder (`buildZpl`) under `zpl-image-ts/zpl`:
64
+ darkness, print rate, copies, field origin, multi-page batches. So
65
+ callers never have to learn ZPL syntax just to print an image.
66
+
67
+ ## Credits
68
+
69
+ All credit for the algorithm goes to **Mark Warren** (`metafloor`) -- this is
70
+ strictly a transliteration, not a redesign. See [NOTICE.md](NOTICE.md) for the
71
+ full attribution and upstream license. Both this port and the upstream are
72
+ distributed under the MIT license.
73
+
74
+ ## API
75
+
76
+ ```ts
77
+ type RgbaInput = Uint8Array | Uint8ClampedArray | readonly number[];
78
+
79
+ interface RgbaOptions {
80
+ /** Blackness threshold 1..99. Default 50. */
81
+ black?: number;
82
+ /** Skip auto-trimming whitespace padding. Default false. */
83
+ notrim?: boolean;
84
+ /** 'N' (none), 'L' / 'B' (90 CCW), 'R' (90 CW), 'I' (180). */
85
+ rotate?: 'N' | 'L' | 'R' | 'I' | 'B';
86
+ }
87
+
88
+ // Deflate + base64 + CRC16 (preferred -- shorter on the wire, supported on
89
+ // every modern Zebra printer). Async because CompressionStream is the
90
+ // underlying web-standard primitive.
91
+ function rgbaToZ64(
92
+ rgba: RgbaInput,
93
+ width: number,
94
+ opts?: RgbaOptions,
95
+ ): Promise<{
96
+ length: number; // uncompressed byte count -> ^GFA arg 1 & 2
97
+ rowlen: number; // packed bytes per row -> ^GFA arg 3
98
+ width: number; // rotated image width in pixels
99
+ height: number; // rotated image height in pixels
100
+ z64: string; // ':Z64:<base64>:<crc16hex>' -> ^GFA arg 4
101
+ gfa: string; // '^GFA,length,length,rowlen,z64' -- ready to splice into ZPL
102
+ }>;
103
+
104
+ // Hex + run-length codes (Alternative Data Compression Scheme).
105
+ // Synchronous -- no compression library needed. Useful when you want a
106
+ // hex-readable payload for debugging, or for older Zebra firmware that
107
+ // predates Z64 support.
108
+ function rgbaToACS(
109
+ rgba: RgbaInput,
110
+ width: number,
111
+ opts?: RgbaOptions,
112
+ ): {
113
+ length: number;
114
+ rowlen: number;
115
+ width: number;
116
+ height: number;
117
+ acs: string; // hex with G..Y / g..z / z run-length codes
118
+ gfa: string; // '^GFA,length,length,rowlen,acs' -- ready to splice into ZPL
119
+ };
120
+
121
+ // Browser-only convenience helpers -- subpath `zpl-image-ts/browser`.
122
+ // Rasterise any ImageBitmapSource (HTMLImageElement, Blob, ImageData,
123
+ // ImageBitmap, OffscreenCanvas, ...) via createImageBitmap +
124
+ // OffscreenCanvas, then run it through rgbaToZ64 / rgbaToACS.
125
+ function imageToZ64(
126
+ source: ImageBitmapSource,
127
+ opts?: RgbaOptions,
128
+ ): Promise<RgbaToZ64Result>;
129
+
130
+ function imageToACS(
131
+ source: ImageBitmapSource,
132
+ opts?: RgbaOptions,
133
+ ): Promise<RgbaToACSResult>;
134
+
135
+ // Wrap one or more ^GFA blocks in a complete ^XA...^XZ label. Subpath
136
+ // `zpl-image-ts/zpl`. Re-exported from the barrel.
137
+ interface ZplLabelOptions {
138
+ darkness?: number; // ~SD, 0..30, one decimal
139
+ printRate?: number; // ^PR, 1..14 (inches/sec on most printers)
140
+ copies?: number; // ^PQ, omitted when <= 1
141
+ fieldOrigin?: {x: number; y: number}; // ^FO before the ^GFA block
142
+ prelude?: string; // raw ZPL after ^XA (e.g. ^PW, ^LL, ^MM)
143
+ postlude?: string; // raw ZPL before ^XZ (e.g. ^XB)
144
+ }
145
+
146
+ function buildZpl(
147
+ gfa: string | readonly string[],
148
+ opts?: ZplLabelOptions,
149
+ ): string;
150
+ ```
151
+
152
+ ### Splicing into a ZPL label
153
+
154
+ ```ts
155
+ const result = await rgbaToZ64(rgba, width);
156
+ const zpl = '^XA' + result.gfa + '^XZ';
157
+ // equivalent to manually writing:
158
+ // '^XA^GFA,' + result.length + ',' + result.length + ',' +
159
+ // result.rowlen + ',' + result.z64 + '^XZ'
160
+ ```
161
+
162
+ For anything beyond the bare `^XA…^XZ` framing -- darkness, print rate,
163
+ copy count, field origin -- use the `buildZpl` helper from
164
+ `zpl-image-ts/zpl` (also re-exported from the barrel). It exists so the
165
+ caller never has to learn ZPL syntax just to get an image onto paper:
166
+
167
+ ```ts
168
+ import {rgbaToZ64, buildZpl} from 'zpl-image-ts';
169
+
170
+ const result = await rgbaToZ64(rgba, width);
171
+ const zpl = buildZpl(result.gfa, {
172
+ darkness: 15, // ~SD15.0 (media darkness, 0..30, one decimal)
173
+ printRate: 4, // ^PR4,A,A (inches/sec, 1..14)
174
+ copies: 2, // ^PQ2 (omitted when <= 1)
175
+ fieldOrigin: {x: 30, y: 15}, // ^FO30,15 before the ^GFA block
176
+ });
177
+ // -> '^XA^PR4,A,A~SD15.0^FO30,15^GFA,...^PQ2^XZ'
178
+ ```
179
+
180
+ `buildZpl` also accepts an array of `gfa` strings -- e.g. one per page
181
+ rasterised from a PDF -- and emits one `^XA…^XZ` block per entry,
182
+ joined with `\n`. The same options apply to every label in the batch.
183
+ For advanced cases the `prelude` and `postlude` options accept raw ZPL
184
+ inserted directly after `^XA` and before `^XZ` respectively
185
+ (e.g. `^PW`, `^LL`, `^MM`, `^XB`).
186
+
187
+ ### End-to-end: image to printer over TCP
188
+
189
+ Zebra network printers accept raw ZPL on TCP port 9100. Combined with
190
+ `imageToZ64` (browser/worker) or `rgbaToZ64` (Node + mupdf, sharp, etc.)
191
+ the full pipeline is a handful of lines and the caller never types `^XA`:
192
+
193
+ ```ts
194
+ // Node: PNG/JPG on disk -> ZPL -> printer
195
+ import {readFile} from 'node:fs/promises';
196
+ import {createConnection} from 'node:net';
197
+ import sharp from 'sharp';
198
+ import {rgbaToZ64, buildZpl} from 'zpl-image-ts';
199
+
200
+ const png = await readFile('label.png');
201
+ const {data, info} = await sharp(png)
202
+ .ensureAlpha()
203
+ .raw()
204
+ .toBuffer({resolveWithObject: true});
205
+
206
+ const result = await rgbaToZ64(data, info.width, {rotate: 'R'});
207
+ const zpl = buildZpl(result.gfa, {darkness: 15, printRate: 4});
208
+
209
+ await new Promise<void>((resolve, reject) => {
210
+ const sock = createConnection({host: '192.168.1.42', port: 9100}, () => {
211
+ sock.end(zpl, 'ascii', () => resolve());
212
+ });
213
+ sock.once('error', reject);
214
+ });
215
+ ```
216
+
217
+ ```ts
218
+ // Browser: <input type="file"> -> ZPL -> POST to your print proxy
219
+ import {imageToZ64} from 'zpl-image-ts/browser';
220
+ import {buildZpl} from 'zpl-image-ts/zpl';
221
+
222
+ const file: Blob = input.files![0];
223
+ const result = await imageToZ64(file, {rotate: 'R'});
224
+ const zpl = buildZpl(result.gfa, {darkness: 15, printRate: 4});
225
+
226
+ await fetch('/api/print', {method: 'POST', body: zpl});
227
+ ```
228
+
229
+ `Node.js Buffer` is accepted at runtime since `Buffer extends Uint8Array`;
230
+ the type was dropped from the signature to keep the package free of
231
+ `@types/node` requirements in browser builds.
232
+
233
+ ## Runtime requirements
234
+
235
+ | Runtime | Required APIs | Status |
236
+ | --- | --- | --- |
237
+ | Node.js | `CompressionStream`, `Blob`, `Response`, `btoa` | All global since Node 18 |
238
+ | Chromium | same | All shipped, evergreen |
239
+ | Firefox | same | All shipped, evergreen |
240
+ | Safari | same | Shipped 16.4+ (March 2023) |
241
+
242
+ Native `Uint8Array.prototype.toBase64()` (TC39, Node 22+, Chrome 133+,
243
+ Firefox 133+, Safari 18.2+) is used when available; otherwise a portable
244
+ `btoa(String.fromCharCode(...))` fallback kicks in.
245
+
246
+ ## Compatibility
247
+
248
+ Output is verified bit-exact against upstream `zpl-image@0.3.0` for both
249
+ `rgbaToZ64` and `rgbaToACS` via golden-vector suites in
250
+ `test/fixtures/fixtures.json` and `test/fixtures/fixtures-acs.json`. Any
251
+ drift fails the test run.
252
+
253
+ ## What is intentionally not ported
254
+
255
+ ### Legacy browser support (pre-2023)
256
+
257
+ `rgbaToZ64` relies on the web-standard `CompressionStream('deflate')` API.
258
+ That global is available in:
259
+
260
+ - Node.js 18+ (April 2022)
261
+ - Chrome / Edge 80+ (February 2020)
262
+ - Safari 16.4+ (March 2023)
263
+ - Firefox 113+ (May 2023)
264
+
265
+ Runtimes older than the above (Safari 16.3 and below, Firefox 112 and below,
266
+ any Internet Explorer) **are not supported and no polyfill is bundled**.
267
+
268
+ If you need to support those runtimes, wrap this library yourself in three
269
+ lines using [`fflate`](https://github.com/101arrowz/fflate) (~8 kB min+gz,
270
+ faster and smaller than `pako`):
271
+
272
+ ```ts
273
+ import {zlibSync} from 'fflate';
274
+ import {rgbaToACS} from 'zpl-image-ts/acs';
275
+ // ...build your own rgbaToZ64 by replacing the deflate step with zlibSync().
276
+ ```
277
+
278
+ ## Development
279
+
280
+ ```sh
281
+ npm install
282
+ npm run typecheck
283
+ npm test
284
+ npm run build
285
+ ```
286
+
287
+ ## License
288
+
289
+ MIT. See [LICENSE](LICENSE) and [NOTICE.md](NOTICE.md).
package/dist/acs.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ACS encoder: hex + ZPL's Alternative Data Compression Scheme run-length
3
+ * codes. Synchronous (no compression library needed).
4
+ *
5
+ * Algorithm credit: Mark Warren (https://github.com/metafloor/zpl-image),
6
+ * MIT 2019. See ../NOTICE.md for full attribution.
7
+ *
8
+ * Importing this module directly (`import {rgbaToACS} from 'zpl-image-ts/acs'`)
9
+ * leaves the Z64 encoder, its CRC16 table, and CompressionStream glue out of
10
+ * the bundle entirely.
11
+ */
12
+ import { type BitmapResult, type RgbaInput, type RgbaOptions } from './internal/bitmap.js';
13
+ export type { RgbaInput, RgbaOptions };
14
+ export interface RgbaToACSResult extends BitmapResult {
15
+ /** Hex-encoded payload with ACS run-length codes; used for `^GFA` arg 4. */
16
+ acs: string;
17
+ }
18
+ /**
19
+ * Convert an RGBA bitmap to a Zebra ACS-encoded `^GFA` payload.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const r = rgbaToACS(rgba, width);
24
+ * const cmd = `^GFA,${r.length},${r.length},${r.rowlen},${r.acs}`;
25
+ * ```
26
+ */
27
+ export declare function rgbaToACS(rgba: RgbaInput, width: number, opts?: RgbaOptions): RgbaToACSResult;
28
+ //# sourceMappingURL=acs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acs.d.ts","sourceRoot":"","sources":["../src/acs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAElG,YAAY,EAAC,SAAS,EAAE,WAAW,EAAC,CAAC;AAErC,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACjD,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACrB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,WAAgB,GACvB,eAAe,CA+CjB"}
package/dist/acs.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * ACS encoder: hex + ZPL's Alternative Data Compression Scheme run-length
3
+ * codes. Synchronous (no compression library needed).
4
+ *
5
+ * Algorithm credit: Mark Warren (https://github.com/metafloor/zpl-image),
6
+ * MIT 2019. See ../NOTICE.md for full attribution.
7
+ *
8
+ * Importing this module directly (`import {rgbaToACS} from 'zpl-image-ts/acs'`)
9
+ * leaves the Z64 encoder, its CRC16 table, and CompressionStream glue out of
10
+ * the bundle entirely.
11
+ */
12
+ import { prepare } from './internal/bitmap.js';
13
+ /**
14
+ * Convert an RGBA bitmap to a Zebra ACS-encoded `^GFA` payload.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const r = rgbaToACS(rgba, width);
19
+ * const cmd = `^GFA,${r.length},${r.length},${r.rowlen},${r.acs}`;
20
+ * ```
21
+ */
22
+ export function rgbaToACS(rgba, width, opts = {}) {
23
+ const { buf, rowlen } = prepare(rgba, width, opts);
24
+ let hex = '';
25
+ for (let i = 0, n = buf.data.length; i < n; i++) {
26
+ hex += hexmap[buf.data[i]];
27
+ }
28
+ // ACS run-length codes:
29
+ // G..Y -> repeats of 1..19
30
+ // g..y -> repeats of 20..380 (in steps of 20)
31
+ // z -> repeats of 400 (combined with above for higher counts)
32
+ const lowRun = '_ghijklmnopqrstuvwxy';
33
+ const highRun = '_GHIJKLMNOPQRSTUVWXY';
34
+ const re = /([0-9a-fA-F])\1{2,}/g;
35
+ let acs = '';
36
+ let offset = 0;
37
+ let match = re.exec(hex);
38
+ while (match) {
39
+ acs += hex.substring(offset, match.index);
40
+ let l = match[0].length;
41
+ while (l >= 400) {
42
+ acs += 'z';
43
+ l -= 400;
44
+ }
45
+ if (l >= 20) {
46
+ acs += lowRun[Math.trunc(l / 20)];
47
+ l = l % 20;
48
+ }
49
+ if (l) {
50
+ acs += highRun[l];
51
+ }
52
+ acs += match[1];
53
+ offset = re.lastIndex;
54
+ match = re.exec(hex);
55
+ }
56
+ acs += hex.substring(offset);
57
+ const length = buf.data.length;
58
+ return {
59
+ length,
60
+ rowlen,
61
+ width: buf.width,
62
+ height: buf.height,
63
+ acs,
64
+ gfa: '^GFA,' + length + ',' + length + ',' + rowlen + ',' + acs,
65
+ };
66
+ }
67
+ const hexmap = (() => {
68
+ const arr = new Array(256);
69
+ for (let i = 0; i < 16; i++)
70
+ arr[i] = '0' + i.toString(16);
71
+ for (let i = 16; i < 256; i++)
72
+ arr[i] = i.toString(16);
73
+ return arr;
74
+ })();
75
+ //# sourceMappingURL=acs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acs.js","sourceRoot":"","sources":["../src/acs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Browser DOM helpers: rasterize an image source via `createImageBitmap` +
3
+ * `OffscreenCanvas`, then run it through `rgbaToZ64` / `rgbaToACS`.
4
+ *
5
+ * Subpath-only entry (`zpl-image-ts/browser`). Not re-exported from the
6
+ * main barrel because both APIs require browser-only globals
7
+ * (`createImageBitmap`, `OffscreenCanvas`) that do not exist in Node.
8
+ *
9
+ * Mirrors upstream `imageToZ64` / `imageToACS` but accepts any
10
+ * `ImageBitmapSource` -- not just `HTMLImageElement` -- so a `Blob` from
11
+ * `fetch()` or an `ImageData` you already have can be passed directly.
12
+ */
13
+ import { type RgbaToZ64Result } from './z64.js';
14
+ import { type RgbaToACSResult } from './acs.js';
15
+ import type { RgbaOptions } from './internal/bitmap.js';
16
+ export type { RgbaOptions, RgbaToZ64Result, RgbaToACSResult };
17
+ /**
18
+ * Decode `source` into RGBA pixels via the platform's image decoder, then
19
+ * compress with Z64. Available in any context that has `createImageBitmap`
20
+ * (every evergreen browser, plus modern web workers).
21
+ */
22
+ export declare function imageToZ64(source: ImageBitmapSource, opts?: RgbaOptions): Promise<RgbaToZ64Result>;
23
+ /**
24
+ * Decode `source` into RGBA pixels and encode with ACS run-length codes.
25
+ * Sync compression -- only the rasterisation step is async because
26
+ * `createImageBitmap` is.
27
+ */
28
+ export declare function imageToACS(source: ImageBitmapSource, opts?: RgbaOptions): Promise<RgbaToACSResult>;
29
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAY,KAAK,eAAe,EAAC,MAAM,UAAU,CAAC;AACzD,OAAO,EAAY,KAAK,eAAe,EAAC,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAEtD,YAAY,EAAC,WAAW,EAAE,eAAe,EAAE,eAAe,EAAC,CAAC;AAE5D;;;;GAIG;AACH,wBAAsB,UAAU,CAC5B,MAAM,EAAE,iBAAiB,EACzB,IAAI,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC5B,MAAM,EAAE,iBAAiB,EACzB,IAAI,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,eAAe,CAAC,CAG1B"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Browser DOM helpers: rasterize an image source via `createImageBitmap` +
3
+ * `OffscreenCanvas`, then run it through `rgbaToZ64` / `rgbaToACS`.
4
+ *
5
+ * Subpath-only entry (`zpl-image-ts/browser`). Not re-exported from the
6
+ * main barrel because both APIs require browser-only globals
7
+ * (`createImageBitmap`, `OffscreenCanvas`) that do not exist in Node.
8
+ *
9
+ * Mirrors upstream `imageToZ64` / `imageToACS` but accepts any
10
+ * `ImageBitmapSource` -- not just `HTMLImageElement` -- so a `Blob` from
11
+ * `fetch()` or an `ImageData` you already have can be passed directly.
12
+ */
13
+ import { rgbaToZ64 } from './z64.js';
14
+ import { rgbaToACS } from './acs.js';
15
+ /**
16
+ * Decode `source` into RGBA pixels via the platform's image decoder, then
17
+ * compress with Z64. Available in any context that has `createImageBitmap`
18
+ * (every evergreen browser, plus modern web workers).
19
+ */
20
+ export async function imageToZ64(source, opts) {
21
+ const { rgba, width } = await rasterize(source);
22
+ return rgbaToZ64(rgba, width, opts);
23
+ }
24
+ /**
25
+ * Decode `source` into RGBA pixels and encode with ACS run-length codes.
26
+ * Sync compression -- only the rasterisation step is async because
27
+ * `createImageBitmap` is.
28
+ */
29
+ export async function imageToACS(source, opts) {
30
+ const { rgba, width } = await rasterize(source);
31
+ return rgbaToACS(rgba, width, opts);
32
+ }
33
+ async function rasterize(source) {
34
+ const bitmap = source instanceof ImageBitmap ? source : await createImageBitmap(source);
35
+ try {
36
+ const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
37
+ const ctx = canvas.getContext('2d');
38
+ if (!ctx) {
39
+ throw new Error('imageToZ64/imageToACS: OffscreenCanvas 2D context unavailable in this runtime');
40
+ }
41
+ ctx.drawImage(bitmap, 0, 0);
42
+ const imageData = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
43
+ return { rgba: imageData.data, width: imageData.width };
44
+ }
45
+ finally {
46
+ // Only close the bitmap we just created -- never the caller's.
47
+ if (source !== bitmap)
48
+ bitmap.close();
49
+ }
50
+ }
51
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,SAAS,EAAuB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAC,SAAS,EAAuB,MAAM,UAAU,CAAC;AAKzD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,MAAyB,EACzB,IAAkB;IAElB,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,MAAyB,EACzB,IAAkB;IAElB,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,SAAS,CACpB,MAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,YAAY,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACxF,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAChE,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,MAAM,IAAI,KAAK,CACX,+EAA+E,CAClF,CAAC;QACN,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACtE,OAAO,EAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAC,CAAC;IAC1D,CAAC;YAAS,CAAC;QACP,+DAA+D;QAC/D,IAAI,MAAM,KAAK,MAAM;YAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IAC1C,CAAC;AACL,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * zpl-image-ts -- TypeScript port of metafloor/zpl-image.
3
+ *
4
+ * This is the convenience barrel re-export. For maximum tree-shaking, import
5
+ * the specific encoder you need directly:
6
+ *
7
+ * ```ts
8
+ * import {rgbaToZ64} from 'zpl-image-ts/z64'; // ACS code not bundled
9
+ * import {rgbaToACS} from 'zpl-image-ts/acs'; // Z64 code not bundled
10
+ * ```
11
+ *
12
+ * Most modern bundlers (Vite, esbuild, Rollup, Webpack 5) tree-shake this
13
+ * barrel correctly too, because `package.json` declares `"sideEffects": false`
14
+ * and both subentries are pure named exports.
15
+ */
16
+ export { rgbaToZ64, type RgbaToZ64Result } from './z64.js';
17
+ export { rgbaToACS, type RgbaToACSResult } from './acs.js';
18
+ export { buildZpl, type ZplLabelOptions } from './zpl.js';
19
+ export type { RgbaInput, RgbaOptions } from './internal/bitmap.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAC,SAAS,EAAE,KAAK,eAAe,EAAC,MAAM,UAAU,CAAC;AACzD,OAAO,EAAC,SAAS,EAAE,KAAK,eAAe,EAAC,MAAM,UAAU,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAE,KAAK,eAAe,EAAC,MAAM,UAAU,CAAC;AACxD,YAAY,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * zpl-image-ts -- TypeScript port of metafloor/zpl-image.
3
+ *
4
+ * This is the convenience barrel re-export. For maximum tree-shaking, import
5
+ * the specific encoder you need directly:
6
+ *
7
+ * ```ts
8
+ * import {rgbaToZ64} from 'zpl-image-ts/z64'; // ACS code not bundled
9
+ * import {rgbaToACS} from 'zpl-image-ts/acs'; // Z64 code not bundled
10
+ * ```
11
+ *
12
+ * Most modern bundlers (Vite, esbuild, Rollup, Webpack 5) tree-shake this
13
+ * barrel correctly too, because `package.json` declares `"sideEffects": false`
14
+ * and both subentries are pure named exports.
15
+ */
16
+ export { rgbaToZ64 } from './z64.js';
17
+ export { rgbaToACS } from './acs.js';
18
+ export { buildZpl } from './zpl.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAC,SAAS,EAAuB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAC,SAAS,EAAuB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAuB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Shared bitmap pipeline: input validation, monochrome conversion, rotation,
3
+ * 1-bit packing. Direct transliteration of routines from upstream
4
+ * metafloor/zpl-image (MIT 2019). See ../../NOTICE.md.
5
+ *
6
+ * Internal: imported by `../z64.ts` and `../acs.ts`. Not part of the public
7
+ * API surface. The dist still ships compiled .js/.d.ts for it (so source
8
+ * maps and declaration maps resolve cleanly), but it is not listed in
9
+ * `package.json` "exports" -- consumers cannot reach it.
10
+ */
11
+ /** Pixel data input. Each pixel is four consecutive bytes: R, G, B, A. */
12
+ export type RgbaInput = Uint8Array | Uint8ClampedArray | readonly number[];
13
+ /** Options shared by every encoder. */
14
+ export interface RgbaOptions {
15
+ /** Blackness threshold, 1..99. Default 50. */
16
+ black?: number;
17
+ /** If true, do not auto-trim surrounding whitespace. Default false. */
18
+ notrim?: boolean;
19
+ /**
20
+ * Rotation:
21
+ * - 'N' (default): no rotation
22
+ * - 'L' or 'B': 90 degrees counter-clockwise
23
+ * - 'R': 90 degrees clockwise
24
+ * - 'I': 180 degrees
25
+ */
26
+ rotate?: 'N' | 'L' | 'R' | 'I' | 'B';
27
+ }
28
+ /** Common fields on every encoder's result. */
29
+ export interface BitmapResult {
30
+ /** Uncompressed byte count; used for `^GFA` args 1 and 2. */
31
+ length: number;
32
+ /** Packed bytes per row; used for `^GFA` arg 3. */
33
+ rowlen: number;
34
+ /** Image width after rotation (pixels). */
35
+ width: number;
36
+ /** Image height after rotation (pixels). */
37
+ height: number;
38
+ /**
39
+ * Ready-to-emit `^GFA,length,length,rowlen,payload` command string.
40
+ * Wrap it in `^XA ... ^XZ` (with any `^FO` / `^PR` / `~SD` etc. you need)
41
+ * and send to the printer. Saves consumers from re-templating the
42
+ * length-twice, rowlen-third structure by hand.
43
+ */
44
+ gfa: string;
45
+ }
46
+ export interface MonoBuffer {
47
+ data: Uint8Array;
48
+ width: number;
49
+ height: number;
50
+ }
51
+ export interface PreparedBitmap {
52
+ buf: MonoBuffer;
53
+ rowlen: number;
54
+ }
55
+ /**
56
+ * Validate input, convert to monochrome, and apply the requested rotation.
57
+ * The returned `buf.data` is 1-bit-packed and ready for hex or deflate
58
+ * encoding.
59
+ */
60
+ export declare function prepare(rgba: RgbaInput, width: number, opts: RgbaOptions): PreparedBitmap;
61
+ //# sourceMappingURL=bitmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../../src/internal/bitmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,iBAAiB,GAAG,SAAS,MAAM,EAAE,CAAC;AAE3E,uCAAuC;AACvC,MAAM,WAAW,WAAW;IACxB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACxC;AAED,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IACzB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE,UAAU,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,cAAc,CA2BzF"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Shared bitmap pipeline: input validation, monochrome conversion, rotation,
3
+ * 1-bit packing. Direct transliteration of routines from upstream
4
+ * metafloor/zpl-image (MIT 2019). See ../../NOTICE.md.
5
+ *
6
+ * Internal: imported by `../z64.ts` and `../acs.ts`. Not part of the public
7
+ * API surface. The dist still ships compiled .js/.d.ts for it (so source
8
+ * maps and declaration maps resolve cleanly), but it is not listed in
9
+ * `package.json` "exports" -- consumers cannot reach it.
10
+ */
11
+ /**
12
+ * Validate input, convert to monochrome, and apply the requested rotation.
13
+ * The returned `buf.data` is 1-bit-packed and ready for hex or deflate
14
+ * encoding.
15
+ */
16
+ export function prepare(rgba, width, opts) {
17
+ const w = width | 0;
18
+ if (!w || w < 0) {
19
+ throw new Error('Invalid width');
20
+ }
21
+ const height = Math.trunc(rgba.length / w / 4);
22
+ const black = +(opts.black ?? 0) || 50;
23
+ const mono = monochrome(rgba, w, height, black, opts.notrim === true);
24
+ let buf;
25
+ switch (opts.rotate) {
26
+ case 'R':
27
+ buf = right(mono);
28
+ break;
29
+ case 'B':
30
+ case 'L':
31
+ buf = left(mono);
32
+ break;
33
+ case 'I':
34
+ buf = invert(mono);
35
+ break;
36
+ default:
37
+ buf = normal(mono);
38
+ break;
39
+ }
40
+ return { buf, rowlen: Math.trunc((buf.width + 7) / 8) };
41
+ }
42
+ function normal(mono) {
43
+ const { width, height, data: src } = mono;
44
+ const buf = new Uint8Array(Math.trunc((width + 7) / 8) * height);
45
+ let idx = 0;
46
+ let byte = 0;
47
+ let bitx = 0;
48
+ for (let i = 0, n = src.length; i < n; i++) {
49
+ byte |= src[i] << (7 - (bitx++ & 7));
50
+ if (bitx === width || !(bitx & 7)) {
51
+ buf[idx++] = byte;
52
+ byte = 0;
53
+ if (bitx === width) {
54
+ bitx = 0;
55
+ }
56
+ }
57
+ }
58
+ return { data: buf, width, height };
59
+ }
60
+ function invert(mono) {
61
+ const { width, height, data: src } = mono;
62
+ const buf = new Uint8Array(Math.trunc((width + 7) / 8) * height);
63
+ let idx = 0;
64
+ let byte = 0;
65
+ let bitx = 0;
66
+ for (let i = src.length - 1; i >= 0; i--) {
67
+ byte |= src[i] << (7 - (bitx++ & 7));
68
+ if (bitx === width || !(bitx & 7)) {
69
+ buf[idx++] = byte;
70
+ byte = 0;
71
+ if (bitx === width) {
72
+ bitx = 0;
73
+ }
74
+ }
75
+ }
76
+ return { data: buf, width, height };
77
+ }
78
+ function left(mono) {
79
+ const { width, height, data: src } = mono;
80
+ const buf = new Uint8Array(Math.trunc((height + 7) / 8) * width);
81
+ let idx = 0;
82
+ let byte = 0;
83
+ for (let x = width - 1; x >= 0; x--) {
84
+ let bitx = 0;
85
+ for (let y = 0; y < height; y++) {
86
+ byte |= src[y * width + x] << (7 - (bitx++ & 7));
87
+ if (y === height - 1 || !(bitx & 7)) {
88
+ buf[idx++] = byte;
89
+ byte = 0;
90
+ }
91
+ }
92
+ }
93
+ return { data: buf, width: height, height: width };
94
+ }
95
+ function right(mono) {
96
+ const { width, height, data: src } = mono;
97
+ const buf = new Uint8Array(Math.trunc((height + 7) / 8) * width);
98
+ let idx = 0;
99
+ let byte = 0;
100
+ for (let x = 0; x < width; x++) {
101
+ let bitx = 0;
102
+ for (let y = height - 1; y >= 0; y--) {
103
+ byte |= src[y * width + x] << (7 - (bitx++ & 7));
104
+ if (y === 0 || !(bitx & 7)) {
105
+ buf[idx++] = byte;
106
+ byte = 0;
107
+ }
108
+ }
109
+ }
110
+ return { data: buf, width: height, height: width };
111
+ }
112
+ /**
113
+ * Convert RGBA to monochrome, 1 bit per byte. Crops empty space around the
114
+ * edges unless `notrim` is true. Uses Rec.601-style luminance weights with
115
+ * straight alpha blending against a white background.
116
+ */
117
+ function monochrome(rgba, width, height, blackPercent, notrim) {
118
+ const black = (255 * blackPercent) / 100;
119
+ let minx;
120
+ let maxx;
121
+ let miny;
122
+ let maxy;
123
+ if (notrim) {
124
+ minx = 0;
125
+ miny = 0;
126
+ maxx = width - 1;
127
+ maxy = height - 1;
128
+ }
129
+ else {
130
+ maxx = 0;
131
+ maxy = 0;
132
+ minx = width;
133
+ miny = height;
134
+ let x = 0;
135
+ let y = 0;
136
+ for (let i = 0, n = width * height * 4; i < n; i += 4) {
137
+ const a = rgba[i + 3] / 255;
138
+ const r = rgba[i] * 0.3 * a + 255 * (1 - a);
139
+ const g = rgba[i + 1] * 0.59 * a + 255 * (1 - a);
140
+ const b = rgba[i + 2] * 0.11 * a + 255 * (1 - a);
141
+ const gray = r + g + b;
142
+ if (gray <= black) {
143
+ if (minx > x)
144
+ minx = x;
145
+ if (miny > y)
146
+ miny = y;
147
+ if (maxx < x)
148
+ maxx = x;
149
+ if (maxy < y)
150
+ maxy = y;
151
+ }
152
+ if (++x === width) {
153
+ x = 0;
154
+ y++;
155
+ }
156
+ }
157
+ }
158
+ const cx = maxx - minx + 1;
159
+ const cy = maxy - miny + 1;
160
+ const buf = new Uint8Array(cx * cy);
161
+ let idx = 0;
162
+ for (let y = miny; y <= maxy; y++) {
163
+ let i = (y * width + minx) * 4;
164
+ for (let x = minx; x <= maxx; x++) {
165
+ const a = rgba[i + 3] / 255;
166
+ const r = rgba[i] * 0.3 * a + 255 * (1 - a);
167
+ const g = rgba[i + 1] * 0.59 * a + 255 * (1 - a);
168
+ const b = rgba[i + 2] * 0.11 * a + 255 * (1 - a);
169
+ const gray = r + g + b;
170
+ buf[idx++] = gray <= black ? 1 : 0;
171
+ i += 4;
172
+ }
173
+ }
174
+ return { data: buf, width: cx, height: cy };
175
+ }
176
+ //# sourceMappingURL=bitmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../src/internal/bitmap.ts"],"names":[],"mappings":"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"}
package/dist/z64.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Z64 encoder: zlib-deflate + base64 + CRC16 envelope.
3
+ *
4
+ * Algorithm credit: Mark Warren (https://github.com/metafloor/zpl-image),
5
+ * MIT 2019. See ../NOTICE.md for full attribution.
6
+ *
7
+ * Isomorphic: uses web-standard `CompressionStream('deflate')` (global in
8
+ * Node 18+ and every evergreen browser) and `Uint8Array.prototype.toBase64()`
9
+ * when available, with a portable btoa-based fallback. Zero runtime deps.
10
+ *
11
+ * Importing this module directly (`import {rgbaToZ64} from 'zpl-image-ts/z64'`)
12
+ * leaves the ACS encoder out of the bundle entirely.
13
+ */
14
+ import { type BitmapResult, type RgbaInput, type RgbaOptions } from './internal/bitmap.js';
15
+ export type { RgbaInput, RgbaOptions };
16
+ export interface RgbaToZ64Result extends BitmapResult {
17
+ /** `:Z64:<base64>:<crc16hex>` payload; used for `^GFA` arg 4. */
18
+ z64: string;
19
+ }
20
+ /**
21
+ * Convert an RGBA bitmap to a Zebra Z64-encoded `^GFA` payload.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const r = await rgbaToZ64(rgba, width);
26
+ * const cmd = `^GFA,${r.length},${r.length},${r.rowlen},${r.z64}`;
27
+ * ```
28
+ */
29
+ export declare function rgbaToZ64(rgba: RgbaInput, width: number, opts?: RgbaOptions): Promise<RgbaToZ64Result>;
30
+ //# sourceMappingURL=z64.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"z64.d.ts","sourceRoot":"","sources":["../src/z64.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAElG,YAAY,EAAC,SAAS,EAAE,WAAW,EAAC,CAAC;AAErC,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACjD,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC3B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,WAAgB,GACvB,OAAO,CAAC,eAAe,CAAC,CAc1B"}
package/dist/z64.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Z64 encoder: zlib-deflate + base64 + CRC16 envelope.
3
+ *
4
+ * Algorithm credit: Mark Warren (https://github.com/metafloor/zpl-image),
5
+ * MIT 2019. See ../NOTICE.md for full attribution.
6
+ *
7
+ * Isomorphic: uses web-standard `CompressionStream('deflate')` (global in
8
+ * Node 18+ and every evergreen browser) and `Uint8Array.prototype.toBase64()`
9
+ * when available, with a portable btoa-based fallback. Zero runtime deps.
10
+ *
11
+ * Importing this module directly (`import {rgbaToZ64} from 'zpl-image-ts/z64'`)
12
+ * leaves the ACS encoder out of the bundle entirely.
13
+ */
14
+ import { prepare } from './internal/bitmap.js';
15
+ /**
16
+ * Convert an RGBA bitmap to a Zebra Z64-encoded `^GFA` payload.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const r = await rgbaToZ64(rgba, width);
21
+ * const cmd = `^GFA,${r.length},${r.length},${r.rowlen},${r.z64}`;
22
+ * ```
23
+ */
24
+ export async function rgbaToZ64(rgba, width, opts = {}) {
25
+ const { buf, rowlen } = prepare(rgba, width, opts);
26
+ const deflated = await deflateZlib(buf.data);
27
+ const b64 = bytesToBase64(deflated);
28
+ const z64 = ':Z64:' + b64 + ':' + crc16(b64);
29
+ const length = buf.data.length;
30
+ return {
31
+ length,
32
+ rowlen,
33
+ width: buf.width,
34
+ height: buf.height,
35
+ z64,
36
+ gfa: '^GFA,' + length + ',' + length + ',' + rowlen + ',' + z64,
37
+ };
38
+ }
39
+ async function deflateZlib(buf) {
40
+ // Cast: TS DOM lib types Blob parts as needing ArrayBuffer-backed views,
41
+ // but the spec accepts any BufferSource (incl. SharedArrayBuffer-backed).
42
+ const stream = new Blob([buf])
43
+ .stream()
44
+ .pipeThrough(new CompressionStream('deflate'));
45
+ return new Uint8Array(await new Response(stream).arrayBuffer());
46
+ }
47
+ function bytesToBase64(buf) {
48
+ // TC39 native: Node 22+, Chrome 133+, Firefox 133+, Safari 18.2+.
49
+ const native = buf.toBase64;
50
+ if (typeof native === 'function')
51
+ return native.call(buf);
52
+ // Portable fallback: btoa is global in Node 16+ and all browsers.
53
+ let s = '';
54
+ for (let i = 0; i < buf.length; i++)
55
+ s += String.fromCharCode(buf[i]);
56
+ return btoa(s);
57
+ }
58
+ // CRC16 used by Zebra. Initial value 0 (not the usual 0xffff) to match the
59
+ // printer's expectation.
60
+ const crcTable = [
61
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
62
+ 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
63
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
64
+ 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
65
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
66
+ 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
67
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
68
+ 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
69
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
70
+ 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
71
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
72
+ 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
73
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
74
+ 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
75
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
76
+ 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
77
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
78
+ 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
79
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
80
+ 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
81
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
82
+ 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
83
+ ];
84
+ function crc16(s) {
85
+ let crc = 0;
86
+ for (let i = 0; i < s.length; i++) {
87
+ const c = s.charCodeAt(i);
88
+ if (c > 255) {
89
+ throw new RangeError('crc16: non-byte character at offset ' + i);
90
+ }
91
+ const j = (c ^ (crc >> 8)) & 0xff;
92
+ crc = crcTable[j] ^ (crc << 8);
93
+ }
94
+ const hex = (crc & 0xffff).toString(16).toLowerCase();
95
+ return '0000'.slice(hex.length) + hex;
96
+ }
97
+ //# sourceMappingURL=z64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"z64.js","sourceRoot":"","sources":["../src/z64.ts"],"names":[],"mappings":"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AE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CACjC,CAAC;AAEF,SAAS,KAAK,CAAC,CAAS;IACpB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;YACV,MAAM,IAAI,UAAU,CAAC,sCAAsC,GAAG,CAAC,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QAClC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;AAC1C,CAAC"}
package/dist/zpl.d.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Tiny, dependency-free ZPL II label builder.
3
+ *
4
+ * Wraps one or more `^GFA` blocks (produced by `rgbaToZ64` / `rgbaToACS`
5
+ * via their `gfa` field, or by `imageToZ64` / `imageToACS`) in a complete
6
+ * `^XA ... ^XZ` payload with the most common printer-control directives:
7
+ *
8
+ * `~SD` (set darkness), `^PR` (print rate), `^PQ` (quantity / copies),
9
+ * `^FO` (field origin) and arbitrary pre/postlude ZPL for advanced use.
10
+ *
11
+ * The point of this module is so that **callers can stay completely
12
+ * ignorant of ZPL syntax** -- pass an image in, get bytes ready to write
13
+ * to TCP port 9100 out. No knowledge of `^XA`, `^GFA`, darkness scale,
14
+ * or print-rate units required.
15
+ */
16
+ /**
17
+ * Options that decorate the generated ZPL with printer-control commands.
18
+ * Every field is optional -- omit to defer to the printer's stored
19
+ * defaults (configured from the LCD panel or via ZPL stored elsewhere).
20
+ */
21
+ export interface ZplLabelOptions {
22
+ /**
23
+ * Media darkness, ZPL `~SD` command. Range `0.0`..`30.0` (in tenths;
24
+ * one decimal of precision). Values outside the range are clamped.
25
+ * Typical thermal-transfer setting is `10`..`20`.
26
+ *
27
+ * Omit to leave the printer at its stored darkness.
28
+ */
29
+ darkness?: number;
30
+ /**
31
+ * Print rate, ZPL `^PR` command. Inches/second on most Zebra
32
+ * desktop and tabletop printers; integer `1`..`14`. Values outside
33
+ * the range are clamped. Print, slew and backfeed rates are all
34
+ * set to the same value (mirroring the existing print-server
35
+ * conventions in metafloor/zpl-image-based stacks).
36
+ *
37
+ * Omit to leave the printer at its stored print rate.
38
+ */
39
+ printRate?: number;
40
+ /**
41
+ * Number of copies of the label, ZPL `^PQ` command. Positive
42
+ * integer; values `< 1` are coerced to `1`. Omit (or pass `1`) to
43
+ * print a single copy and skip emitting `^PQ` entirely.
44
+ */
45
+ copies?: number;
46
+ /**
47
+ * Field origin in dots, ZPL `^FO` command, emitted directly before
48
+ * the `^GFA` block. Useful for offsetting the graphic from the
49
+ * top-left of the label. Negative values are clamped to `0`.
50
+ *
51
+ * Omit to print the graphic at `(0, 0)` without emitting `^FO`.
52
+ */
53
+ fieldOrigin?: {
54
+ x: number;
55
+ y: number;
56
+ };
57
+ /**
58
+ * Raw ZPL inserted **immediately after `^XA`** and before any of
59
+ * the directives above. Use to set label dimensions (`^PW`,
60
+ * `^LL`), print mode (`^MM`), media tracking (`^MN`), etc. The
61
+ * string is concatenated verbatim -- caller is responsible for
62
+ * correctness.
63
+ */
64
+ prelude?: string;
65
+ /**
66
+ * Raw ZPL inserted **immediately before `^XZ`** (after the `^GFA`
67
+ * block and any `^PQ`). Use for end-of-label directives such as
68
+ * `^XB` (suppress backfeed) that some workflows need.
69
+ */
70
+ postlude?: string;
71
+ }
72
+ /**
73
+ * Build a complete ZPL payload from one or more `^GFA` graphic blocks.
74
+ *
75
+ * - Pass a single `gfa` string to produce a single `^XA...^XZ` label.
76
+ * - Pass an array (e.g. one entry per page rasterised from a PDF) to
77
+ * produce one `^XA...^XZ` block per entry, joined with `\n`. The
78
+ * same options apply to every label in the batch.
79
+ *
80
+ * The returned string is byte-for-byte ready to write to TCP port
81
+ * 9100, USB, or whichever transport your printer speaks.
82
+ *
83
+ * @example
84
+ * const res = await rgbaToZ64(rgba, width);
85
+ * const zpl = buildZpl(res.gfa, {darkness: 15, printRate: 4});
86
+ * // -> '^XA^PR4,A,A~SD15.0^GFA,...^XZ'
87
+ */
88
+ export declare function buildZpl(gfa: string | readonly string[], opts?: ZplLabelOptions): string;
89
+ //# sourceMappingURL=zpl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zpl.d.ts","sourceRoot":"","sources":["../src/zpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IAErC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,eAAoB,GAAG,MAAM,CAG5F"}
package/dist/zpl.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Tiny, dependency-free ZPL II label builder.
3
+ *
4
+ * Wraps one or more `^GFA` blocks (produced by `rgbaToZ64` / `rgbaToACS`
5
+ * via their `gfa` field, or by `imageToZ64` / `imageToACS`) in a complete
6
+ * `^XA ... ^XZ` payload with the most common printer-control directives:
7
+ *
8
+ * `~SD` (set darkness), `^PR` (print rate), `^PQ` (quantity / copies),
9
+ * `^FO` (field origin) and arbitrary pre/postlude ZPL for advanced use.
10
+ *
11
+ * The point of this module is so that **callers can stay completely
12
+ * ignorant of ZPL syntax** -- pass an image in, get bytes ready to write
13
+ * to TCP port 9100 out. No knowledge of `^XA`, `^GFA`, darkness scale,
14
+ * or print-rate units required.
15
+ */
16
+ /**
17
+ * Build a complete ZPL payload from one or more `^GFA` graphic blocks.
18
+ *
19
+ * - Pass a single `gfa` string to produce a single `^XA...^XZ` label.
20
+ * - Pass an array (e.g. one entry per page rasterised from a PDF) to
21
+ * produce one `^XA...^XZ` block per entry, joined with `\n`. The
22
+ * same options apply to every label in the batch.
23
+ *
24
+ * The returned string is byte-for-byte ready to write to TCP port
25
+ * 9100, USB, or whichever transport your printer speaks.
26
+ *
27
+ * @example
28
+ * const res = await rgbaToZ64(rgba, width);
29
+ * const zpl = buildZpl(res.gfa, {darkness: 15, printRate: 4});
30
+ * // -> '^XA^PR4,A,A~SD15.0^GFA,...^XZ'
31
+ */
32
+ export function buildZpl(gfa, opts = {}) {
33
+ const blocks = typeof gfa === 'string' ? [gfa] : gfa;
34
+ return blocks.map((g) => buildSingleLabel(g, opts)).join('\n');
35
+ }
36
+ function buildSingleLabel(gfa, opts) {
37
+ const parts = ['^XA'];
38
+ if (opts.prelude)
39
+ parts.push(opts.prelude);
40
+ if (opts.printRate !== undefined) {
41
+ const rate = clampInt(opts.printRate, 1, 14);
42
+ // ^PR<print>,<slew>,<backfeed> -- mirror all three to the same
43
+ // rate, which is the safe default the upstream print server uses.
44
+ parts.push(`^PR${rate},A,A`);
45
+ }
46
+ if (opts.darkness !== undefined) {
47
+ const dark = clampFloat(opts.darkness, 0, 30);
48
+ // ~SD accepts one decimal of precision.
49
+ parts.push(`~SD${dark.toFixed(1)}`);
50
+ }
51
+ if (opts.fieldOrigin) {
52
+ const x = Math.max(0, Math.trunc(opts.fieldOrigin.x));
53
+ const y = Math.max(0, Math.trunc(opts.fieldOrigin.y));
54
+ parts.push(`^FO${x},${y}`);
55
+ }
56
+ parts.push(gfa);
57
+ if (opts.copies !== undefined && opts.copies > 1) {
58
+ parts.push(`^PQ${Math.trunc(opts.copies)}`);
59
+ }
60
+ if (opts.postlude)
61
+ parts.push(opts.postlude);
62
+ parts.push('^XZ');
63
+ return parts.join('');
64
+ }
65
+ function clampInt(value, min, max) {
66
+ return Math.min(Math.max(Math.trunc(value), min), max);
67
+ }
68
+ function clampFloat(value, min, max) {
69
+ return Math.min(Math.max(value, min), max);
70
+ }
71
+ //# sourceMappingURL=zpl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zpl.js","sourceRoot":"","sources":["../src/zpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA6DH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,QAAQ,CAAC,GAA+B,EAAE,OAAwB,EAAE;IAChF,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACrD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW,EAAE,IAAqB;IACxD,MAAM,KAAK,GAAa,CAAC,KAAK,CAAC,CAAC;IAEhC,IAAI,IAAI,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE3C,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7C,+DAA+D;QAC/D,kEAAkE;QAClE,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,wCAAwC;QACxC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEhB,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE7C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,UAAU,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IACvD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "zpl-image-ts",
3
+ "version": "1.0.0",
4
+ "description": "Image to Zebra ZPL: encode RGBA bitmaps to ^GFA (Z64 + ACS), wrap in ^XA…^XZ with darkness/print-rate/copies. TypeScript-native, isomorphic, tree-shakeable ESM port of metafloor/zpl-image.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./z64": {
15
+ "types": "./dist/z64.d.ts",
16
+ "import": "./dist/z64.js"
17
+ },
18
+ "./acs": {
19
+ "types": "./dist/acs.d.ts",
20
+ "import": "./dist/acs.js"
21
+ },
22
+ "./browser": {
23
+ "types": "./dist/browser.d.ts",
24
+ "import": "./dist/browser.js"
25
+ },
26
+ "./zpl": {
27
+ "types": "./dist/zpl.d.ts",
28
+ "import": "./dist/zpl.js"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE",
36
+ "NOTICE.md"
37
+ ],
38
+ "sideEffects": false,
39
+ "engines": {
40
+ "node": ">=20"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc",
44
+ "dev": "tsc --watch",
45
+ "clean": "rimraf dist",
46
+ "prepublishOnly": "npm run clean && npm run build && npm test",
47
+ "typecheck": "tsc -p tsconfig.check.json",
48
+ "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
49
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"*.{json,md}\"",
50
+ "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"*.{json,md}\"",
51
+ "test": "vitest run",
52
+ "test:node": "vitest run --project node",
53
+ "test:browser": "vitest run --project browser",
54
+ "test:watch": "vitest"
55
+ },
56
+ "keywords": [
57
+ "zebra",
58
+ "zpl",
59
+ "z64",
60
+ "gfa",
61
+ "label",
62
+ "label-printer",
63
+ "barcode",
64
+ "rgba",
65
+ "bitmap",
66
+ "typescript",
67
+ "esm"
68
+ ],
69
+ "author": "Mika Salminen",
70
+ "license": "MIT",
71
+ "repository": {
72
+ "type": "git",
73
+ "url": "git+https://github.com/damischa1/zpl-image-ts.git"
74
+ },
75
+ "bugs": {
76
+ "url": "https://github.com/damischa1/zpl-image-ts/issues"
77
+ },
78
+ "homepage": "https://github.com/damischa1/zpl-image-ts#readme",
79
+ "devDependencies": {
80
+ "@eslint/js": "^10.0.1",
81
+ "@types/node": "^24.12.4",
82
+ "@vitest/browser": "^4.1.7",
83
+ "@vitest/browser-playwright": "^4.1.7",
84
+ "eslint": "^10.4.0",
85
+ "playwright": "^1.60.0",
86
+ "prettier": "^3.8.3",
87
+ "rimraf": "^6.1.2",
88
+ "typescript": "^6.0.0",
89
+ "typescript-eslint": "^8.49.0",
90
+ "vitest": "^4.1.7"
91
+ }
92
+ }