portakal 0.2.0 → 0.3.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/README.md +26 -1
- package/dist/_chunks/types.d.mts +169 -0
- package/dist/encoding.d.mts +42 -0
- package/dist/encoding.mjs +1 -0
- package/dist/image.d.mts +22 -0
- package/dist/image.mjs +1 -0
- package/dist/index.d.mts +17 -457
- package/dist/index.mjs +1 -16
- package/dist/languages/cpcl.d.mts +7 -0
- package/dist/languages/cpcl.mjs +3 -0
- package/dist/languages/dpl.d.mts +7 -0
- package/dist/languages/dpl.mjs +3 -0
- package/dist/languages/epl.d.mts +7 -0
- package/dist/languages/epl.mjs +3 -0
- package/dist/languages/escpos.d.mts +7 -0
- package/dist/languages/escpos.mjs +1 -0
- package/dist/languages/ipl.d.mts +7 -0
- package/dist/languages/ipl.mjs +3 -0
- package/dist/languages/sbpl.d.mts +7 -0
- package/dist/languages/sbpl.mjs +3 -0
- package/dist/languages/starprnt.d.mts +7 -0
- package/dist/languages/starprnt.mjs +1 -0
- package/dist/languages/tsc.d.mts +7 -0
- package/dist/languages/tsc.mjs +3 -0
- package/dist/languages/zpl.d.mts +7 -0
- package/dist/languages/zpl.mjs +3 -0
- package/dist/preview.d.mts +7 -0
- package/dist/preview.mjs +2 -0
- package/dist/profiles.d.mts +49 -0
- package/dist/profiles.mjs +1 -0
- package/dist/receipt.d.mts +20 -0
- package/dist/receipt.mjs +1 -0
- package/dist/transport.d.mts +106 -0
- package/dist/transport.mjs +1 -0
- package/package.json +62 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<br><br>
|
|
5
5
|
<b style="font-size: 2em;">portakal</b>
|
|
6
6
|
<br><br>
|
|
7
|
-
Universal printer language SDK —
|
|
7
|
+
Universal printer language SDK — 9 languages, one API.
|
|
8
8
|
<br>
|
|
9
9
|
Text, barcodes, QR codes, images, shapes — anything you can print.
|
|
10
10
|
<br>
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
<a href="https://npmjs.com/package/portakal"><img src="https://img.shields.io/npm/dm/portakal?style=flat&colorA=18181B&colorB=F97316" alt="npm downloads"></a>
|
|
15
15
|
<a href="https://bundlephobia.com/result?p=portakal"><img src="https://img.shields.io/bundlephobia/minzip/portakal?style=flat&colorA=18181B&colorB=F97316" alt="bundle size"></a>
|
|
16
16
|
<a href="https://github.com/productdevbook/portakal/blob/main/LICENSE"><img src="https://img.shields.io/github/license/productdevbook/portakal?style=flat&colorA=18181B&colorB=F97316" alt="license"></a>
|
|
17
|
+
<br><br>
|
|
18
|
+
<a href="https://portakal.productdevbook.com">Playground</a> · <a href="https://github.com/productdevbook/portakal">GitHub</a> · <a href="https://npmjs.com/package/portakal">npm</a>
|
|
17
19
|
</p>
|
|
18
20
|
|
|
19
21
|
> [!NOTE]
|
|
@@ -94,6 +96,28 @@ myLabel.toEPL(); // Eltron EPL2 — LP/TLP 2824, GX420, ZD220
|
|
|
94
96
|
myLabel.toESCPOS(); // ESC/POS — Epson, Bixolon, Star, Citizen
|
|
95
97
|
```
|
|
96
98
|
|
|
99
|
+
### Tree Shaking
|
|
100
|
+
|
|
101
|
+
Import only what you need — each module is a separate entry point:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { compileToTSC } from "portakal/tsc";
|
|
105
|
+
import { compileToZPL } from "portakal/zpl";
|
|
106
|
+
import { compileToEPL } from "portakal/epl";
|
|
107
|
+
import { compileToESCPOS } from "portakal/escpos";
|
|
108
|
+
import { compileToCPCL } from "portakal/cpcl";
|
|
109
|
+
import { compileToDPL } from "portakal/dpl";
|
|
110
|
+
import { compileToSBPL } from "portakal/sbpl";
|
|
111
|
+
import { compileToStarPRNT } from "portakal/starprnt";
|
|
112
|
+
import { compileToIPL } from "portakal/ipl";
|
|
113
|
+
import { imageToMonochrome } from "portakal/image";
|
|
114
|
+
import { formatPair, separator } from "portakal/receipt";
|
|
115
|
+
import { encodeTextForPrinter } from "portakal/encoding";
|
|
116
|
+
import { getProfile } from "portakal/profiles";
|
|
117
|
+
import { chunkedWrite } from "portakal/transport";
|
|
118
|
+
import { renderPreview } from "portakal/preview";
|
|
119
|
+
```
|
|
120
|
+
|
|
97
121
|
### Software-rendered barcode/QR (with etiket)
|
|
98
122
|
|
|
99
123
|
For pixel-perfect output, styled QR codes, or when the printer doesn't support a format natively:
|
|
@@ -376,6 +400,7 @@ await usbDevice.transferOut(endpointNumber, escpos);
|
|
|
376
400
|
|
|
377
401
|
- Zero dependencies — pure computation, no native modules, no node-gyp
|
|
378
402
|
- **9 printer languages** — TSC, ZPL, EPL, CPCL, DPL, SBPL, ESC/POS, Star PRNT, IPL
|
|
403
|
+
- **Tree-shakeable** — sub-path exports for every module (`portakal/tsc`, `portakal/image`, etc.)
|
|
379
404
|
- Pure ESM, edge-runtime compatible (Cloudflare Workers, Deno, Bun)
|
|
380
405
|
- TypeScript-first with strict types (tsgo)
|
|
381
406
|
- Transport-agnostic — generates commands, you handle the connection
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/** Unit of measurement for label dimensions */
|
|
3
|
+
type Unit = "mm" | "inch" | "dot";
|
|
4
|
+
/** Print orientation / rotation */
|
|
5
|
+
type Rotation = 0 | 90 | 180 | 270;
|
|
6
|
+
/** Text alignment */
|
|
7
|
+
type Alignment = "left" | "center" | "right";
|
|
8
|
+
/** Dithering algorithm for image processing */
|
|
9
|
+
type DitherAlgorithm = "threshold" | "floyd-steinberg" | "atkinson" | "ordered";
|
|
10
|
+
/** Label configuration */
|
|
11
|
+
interface LabelConfig {
|
|
12
|
+
/** Label width */
|
|
13
|
+
width: number;
|
|
14
|
+
/** Label height (optional for receipt/continuous mode) */
|
|
15
|
+
height?: number;
|
|
16
|
+
/** Unit of measurement (default: "mm") */
|
|
17
|
+
unit?: Unit;
|
|
18
|
+
/** Printer DPI (default: 203) */
|
|
19
|
+
dpi?: number;
|
|
20
|
+
/** Gap between labels in mm (label printers only) */
|
|
21
|
+
gap?: number;
|
|
22
|
+
/** Print speed (1-10, printer-dependent) */
|
|
23
|
+
speed?: number;
|
|
24
|
+
/** Print darkness/density (0-15) */
|
|
25
|
+
density?: number;
|
|
26
|
+
/** Print direction */
|
|
27
|
+
direction?: 0 | 1;
|
|
28
|
+
/** Number of copies */
|
|
29
|
+
copies?: number;
|
|
30
|
+
}
|
|
31
|
+
/** Text element options */
|
|
32
|
+
interface TextOptions {
|
|
33
|
+
/** X position */
|
|
34
|
+
x?: number;
|
|
35
|
+
/** Y position */
|
|
36
|
+
y?: number;
|
|
37
|
+
/** Font name or ID */
|
|
38
|
+
font?: string;
|
|
39
|
+
/** Font size or magnification */
|
|
40
|
+
size?: number;
|
|
41
|
+
/** Horizontal magnification (1-10) */
|
|
42
|
+
xScale?: number;
|
|
43
|
+
/** Vertical magnification (1-10) */
|
|
44
|
+
yScale?: number;
|
|
45
|
+
/** Rotation */
|
|
46
|
+
rotation?: Rotation;
|
|
47
|
+
/** Bold */
|
|
48
|
+
bold?: boolean;
|
|
49
|
+
/** Underline */
|
|
50
|
+
underline?: boolean;
|
|
51
|
+
/** Reverse (white on black) */
|
|
52
|
+
reverse?: boolean;
|
|
53
|
+
/** Alignment */
|
|
54
|
+
align?: Alignment;
|
|
55
|
+
/** Max width for word-wrap (in dots) */
|
|
56
|
+
maxWidth?: number;
|
|
57
|
+
/** Line spacing (in dots) */
|
|
58
|
+
lineSpacing?: number;
|
|
59
|
+
}
|
|
60
|
+
/** Image element options */
|
|
61
|
+
interface ImageOptions {
|
|
62
|
+
/** X position */
|
|
63
|
+
x?: number;
|
|
64
|
+
/** Y position */
|
|
65
|
+
y?: number;
|
|
66
|
+
/** Target width in dots (auto-scale if set) */
|
|
67
|
+
width?: number;
|
|
68
|
+
/** Target height in dots (auto-scale if set) */
|
|
69
|
+
height?: number;
|
|
70
|
+
/** Dithering algorithm (default: "threshold") */
|
|
71
|
+
dither?: DitherAlgorithm;
|
|
72
|
+
/** Threshold for monochrome conversion (0-255, default: 128) */
|
|
73
|
+
threshold?: number;
|
|
74
|
+
}
|
|
75
|
+
/** Box/rectangle element options */
|
|
76
|
+
interface BoxOptions {
|
|
77
|
+
/** X position */
|
|
78
|
+
x: number;
|
|
79
|
+
/** Y position */
|
|
80
|
+
y: number;
|
|
81
|
+
/** Width */
|
|
82
|
+
width: number;
|
|
83
|
+
/** Height */
|
|
84
|
+
height: number;
|
|
85
|
+
/** Border thickness in dots (default: 1) */
|
|
86
|
+
thickness?: number;
|
|
87
|
+
/** Corner radius in dots */
|
|
88
|
+
radius?: number;
|
|
89
|
+
}
|
|
90
|
+
/** Line element options */
|
|
91
|
+
interface LineOptions {
|
|
92
|
+
/** Start X */
|
|
93
|
+
x1: number;
|
|
94
|
+
/** Start Y */
|
|
95
|
+
y1: number;
|
|
96
|
+
/** End X */
|
|
97
|
+
x2: number;
|
|
98
|
+
/** End Y */
|
|
99
|
+
y2: number;
|
|
100
|
+
/** Line thickness in dots (default: 1) */
|
|
101
|
+
thickness?: number;
|
|
102
|
+
}
|
|
103
|
+
/** Circle element options */
|
|
104
|
+
interface CircleOptions {
|
|
105
|
+
/** Center X */
|
|
106
|
+
x: number;
|
|
107
|
+
/** Center Y */
|
|
108
|
+
y: number;
|
|
109
|
+
/** Diameter in dots */
|
|
110
|
+
diameter: number;
|
|
111
|
+
/** Border thickness in dots (default: 1) */
|
|
112
|
+
thickness?: number;
|
|
113
|
+
}
|
|
114
|
+
/** 1-bit monochrome bitmap (universal intermediate format for images) */
|
|
115
|
+
interface MonochromeBitmap {
|
|
116
|
+
/** Packed 1-bit pixel data, row-major, MSB-first */
|
|
117
|
+
data: Uint8Array;
|
|
118
|
+
/** Width in pixels */
|
|
119
|
+
width: number;
|
|
120
|
+
/** Height in pixels */
|
|
121
|
+
height: number;
|
|
122
|
+
/** Bytes per row = ceil(width / 8) */
|
|
123
|
+
bytesPerRow: number;
|
|
124
|
+
}
|
|
125
|
+
/** Internal label element union type */
|
|
126
|
+
type LabelElement = {
|
|
127
|
+
type: "text";
|
|
128
|
+
content: string;
|
|
129
|
+
options: TextOptions;
|
|
130
|
+
} | {
|
|
131
|
+
type: "image";
|
|
132
|
+
bitmap: MonochromeBitmap;
|
|
133
|
+
options: ImageOptions;
|
|
134
|
+
} | {
|
|
135
|
+
type: "box";
|
|
136
|
+
options: BoxOptions;
|
|
137
|
+
} | {
|
|
138
|
+
type: "line";
|
|
139
|
+
options: LineOptions;
|
|
140
|
+
} | {
|
|
141
|
+
type: "circle";
|
|
142
|
+
options: CircleOptions;
|
|
143
|
+
} | {
|
|
144
|
+
type: "raw";
|
|
145
|
+
content: string | Uint8Array;
|
|
146
|
+
};
|
|
147
|
+
/** Resolved label configuration with computed values */
|
|
148
|
+
interface ResolvedLabel {
|
|
149
|
+
/** Width in dots */
|
|
150
|
+
widthDots: number;
|
|
151
|
+
/** Height in dots (0 for continuous/receipt) */
|
|
152
|
+
heightDots: number;
|
|
153
|
+
/** DPI */
|
|
154
|
+
dpi: number;
|
|
155
|
+
/** Gap in dots */
|
|
156
|
+
gapDots: number;
|
|
157
|
+
/** Speed */
|
|
158
|
+
speed: number;
|
|
159
|
+
/** Density */
|
|
160
|
+
density: number;
|
|
161
|
+
/** Direction */
|
|
162
|
+
direction: 0 | 1;
|
|
163
|
+
/** Copies */
|
|
164
|
+
copies: number;
|
|
165
|
+
/** All elements to render */
|
|
166
|
+
elements: LabelElement[];
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
169
|
+
export { ImageOptions as a, LineOptions as c, Rotation as d, TextOptions as f, DitherAlgorithm as i, MonochromeBitmap as l, BoxOptions as n, LabelConfig as o, Unit as p, CircleOptions as r, LabelElement as s, Alignment as t, ResolvedLabel as u };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/encoding.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* UTF-8 to ESC/POS code page encoding engine.
|
|
4
|
+
*
|
|
5
|
+
* Accepts UTF-8 text and produces encoded byte segments with minimal
|
|
6
|
+
* code page switching. Solves the #1 pain point across all thermal
|
|
7
|
+
* printer libraries (200+ issues in the ecosystem).
|
|
8
|
+
*/
|
|
9
|
+
/** ESC/POS code page ID → ESC t parameter value */
|
|
10
|
+
interface CodePage {
|
|
11
|
+
/** ESC t parameter value */
|
|
12
|
+
id: number;
|
|
13
|
+
/** Human-readable name */
|
|
14
|
+
name: string;
|
|
15
|
+
/** Character mapping: Unicode code point → byte value (0x80-0xFF range) */
|
|
16
|
+
chars: Map<number, number>;
|
|
17
|
+
}
|
|
18
|
+
/** Encoded segment — a chunk of bytes with an associated code page switch */
|
|
19
|
+
interface EncodedSegment {
|
|
20
|
+
/** Code page ID to switch to (ESC t n), or -1 for ASCII (no switch needed) */
|
|
21
|
+
codePage: number;
|
|
22
|
+
/** Encoded bytes */
|
|
23
|
+
data: Uint8Array;
|
|
24
|
+
}
|
|
25
|
+
/** Available code pages in priority order */
|
|
26
|
+
declare const CODE_PAGES: CodePage[];
|
|
27
|
+
/**
|
|
28
|
+
* Encode a UTF-8 string into ESC/POS byte segments with optimal code page switching.
|
|
29
|
+
*
|
|
30
|
+
* Strategy: greedily encode as much as possible in the current code page before switching.
|
|
31
|
+
* ASCII (0x20-0x7E) never requires a code page switch.
|
|
32
|
+
*/
|
|
33
|
+
declare function encodeText(text: string): EncodedSegment[];
|
|
34
|
+
/**
|
|
35
|
+
* Encode text and return complete ESC/POS bytes including code page switch commands.
|
|
36
|
+
* Ready to send to printer.
|
|
37
|
+
*/
|
|
38
|
+
declare function encodeTextForPrinter(text: string): Uint8Array;
|
|
39
|
+
/** Check if a string contains only ASCII printable characters */
|
|
40
|
+
declare function isASCII(text: string): boolean;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CODE_PAGES, CodePage, EncodedSegment, encodeText, encodeTextForPrinter, isASCII };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){let t=new Map;for(let[n,r]of e)t.set(n,r);return t}const t=[[199,128],[252,129],[233,130],[226,131],[228,132],[224,133],[229,134],[231,135],[234,136],[235,137],[232,138],[239,139],[238,140],[236,141],[196,142],[197,143],[201,144],[230,145],[198,146],[244,147],[246,148],[242,149],[251,150],[249,151],[255,152],[214,153],[220,154],[162,155],[163,156],[165,157],[223,225],[181,230],[241,164],[209,165]],n=[...t,[8364,213]],r=[[8364,128],[8218,130],[402,131],[8222,132],[8230,133],[8224,134],[8225,135],[710,136],[8240,137],[352,138],[8249,139],[338,140],[381,142],[8216,145],[8217,146],[8220,147],[8221,148],[8226,149],[8211,150],[8212,151],[732,152],[8482,153],[353,154],[8250,155],[339,156],[382,158],[376,159],...Array.from({length:96},(e,t)=>[160+t,160+t])],i=[...Array.from({length:32},(e,t)=>[1040+t,128+t]),...Array.from({length:16},(e,t)=>[1072+t,160+t]),...Array.from({length:16},(e,t)=>[1088+t,224+t]),[1025,240],[1105,241],[1028,242],[1108,243],[1031,244],[1111,245],[1038,246],[1118,247]],a=[...t.filter(([e])=>e!==223),[286,160],[287,161],[304,152],[305,141],[350,158],[351,159]],o=[{id:0,name:`CP437`,chars:e(t)},{id:19,name:`CP858`,chars:e(n)},{id:16,name:`CP1252`,chars:e(r)},{id:17,name:`CP866`,chars:e(i)},{id:13,name:`CP857`,chars:e(a)}];function s(e){for(let t of o){let n=t.chars.get(e);if(n!==void 0)return{cpId:t.id,byte:n}}return null}function c(e){let t=[],n=-1,r=[];function i(){r.length>0&&(t.push({codePage:n,data:new Uint8Array(r)}),r=[])}for(let t=0;t<e.length;t++){let a=e.codePointAt(t);if(a>=32&&a<=126){r.push(a);continue}if(a===10||a===13){r.push(a);continue}let o=s(a);o?(o.cpId!==n&&(i(),n=o.cpId),r.push(o.byte)):r.push(63),a>65535&&t++}return i(),t}function l(e){let t=c(e),n=[];for(let e of t)e.codePage>=0&&n.push(new Uint8Array([27,116,e.codePage])),n.push(e.data);let r=0;for(let e of n)r+=e.length;let i=new Uint8Array(r),a=0;for(let e of n)i.set(e,a),a+=e.length;return i}function u(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if((n<32||n>126)&&n!==10&&n!==13)return!1}return!0}export{o as CODE_PAGES,c as encodeText,l as encodeTextForPrinter,u as isASCII};
|
package/dist/image.d.mts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { i as DitherAlgorithm, l as MonochromeBitmap } from "./_chunks/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/image.d.ts
|
|
4
|
+
/** Convert RGBA pixel data to grayscale (BT.601 luminance, alpha composited on white) */
|
|
5
|
+
declare function rgbaToGrayscale(rgba: Uint8Array | Uint8ClampedArray, width: number, height: number): Uint8Array;
|
|
6
|
+
/** Simple threshold: pixels below threshold become black */
|
|
7
|
+
declare function ditherThreshold(gray: Uint8Array, width: number, height: number, threshold?: number): Uint8Array;
|
|
8
|
+
/** Floyd-Steinberg error diffusion dithering */
|
|
9
|
+
declare function ditherFloydSteinberg(gray: Uint8Array, width: number, height: number): Uint8Array;
|
|
10
|
+
/** Atkinson dithering — preserves more contrast (75% error propagation) */
|
|
11
|
+
declare function ditherAtkinson(gray: Uint8Array, width: number, height: number): Uint8Array;
|
|
12
|
+
/** Ordered dithering using 4x4 Bayer matrix */
|
|
13
|
+
declare function ditherOrdered(gray: Uint8Array, width: number, height: number): Uint8Array;
|
|
14
|
+
/** Pack 8-bit dithered pixels (0 or 255) into 1-bit MonochromeBitmap */
|
|
15
|
+
declare function packBitmap(dithered: Uint8Array, width: number, height: number): MonochromeBitmap;
|
|
16
|
+
/** Convert RGBA image to MonochromeBitmap with specified dithering algorithm */
|
|
17
|
+
declare function imageToMonochrome(rgba: Uint8Array | Uint8ClampedArray, width: number, height: number, options?: {
|
|
18
|
+
dither?: DitherAlgorithm;
|
|
19
|
+
threshold?: number;
|
|
20
|
+
}): MonochromeBitmap;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { ditherAtkinson, ditherFloydSteinberg, ditherOrdered, ditherThreshold, imageToMonochrome, packBitmap, rgbaToGrayscale };
|
package/dist/image.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t,n){let r=new Uint8Array(t*n);for(let i=0;i<t*n;i++){let t=e[i*4],n=e[i*4+1],a=e[i*4+2],o=e[i*4+3],s=(t*o+255*(255-o))/255,c=(n*o+255*(255-o))/255,l=(a*o+255*(255-o))/255;r[i]=Math.round(.299*s+.587*c+.114*l)}return r}function t(e,t,n,r=128){let i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=e[t]<r?0:255;return i}function n(e,t,n){let r=new Float32Array(e.length);for(let t=0;t<e.length;t++)r[t]=e[t];for(let e=0;e<n;e++){let i=(e&1)==0,a=i?0:t-1,o=i?t:-1,s=i?1:-1;for(let i=a;i!==o;i+=s){let a=e*t+i,o=r[a],c=o<128?0:255;r[a]=c;let l=o-c,u=i+s;u>=0&&u<t&&(r[e*t+u]+=l*7/16),e+1<n&&(i-s>=0&&i-s<t&&(r[(e+1)*t+i-s]+=l*3/16),r[(e+1)*t+i]+=l*5/16,u>=0&&u<t&&(r[(e+1)*t+u]+=l*1/16))}}let i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=r[t]<128?0:255;return i}function r(e,t,n){let r=new Float32Array(e.length);for(let t=0;t<e.length;t++)r[t]=e[t];for(let e=0;e<n;e++)for(let i=0;i<t;i++){let a=e*t+i,o=r[a],s=o<128?0:255;r[a]=s;let c=(o-s)/8;i+1<t&&(r[a+1]+=c),i+2<t&&(r[a+2]+=c),e+1<n&&(i-1>=0&&(r[(e+1)*t+i-1]+=c),r[(e+1)*t+i]+=c,i+1<t&&(r[(e+1)*t+i+1]+=c)),e+2<n&&(r[(e+2)*t+i]+=c)}let i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=r[t]<128?0:255;return i}const i=[[0,8,2,10],[12,4,14,6],[3,11,1,9],[15,7,13,5]];function a(e,t,n){let r=new Uint8Array(e.length);for(let a=0;a<n;a++)for(let n=0;n<t;n++){let o=i[a%4][n%4]/16*255;r[a*t+n]=e[a*t+n]>o?255:0}return r}function o(e,t,n){let r=Math.ceil(t/8),i=new Uint8Array(r*n);for(let a=0;a<n;a++)for(let n=0;n<t;n++)if(e[a*t+n]===0){let e=a*r+Math.floor(n/8),t=7-n%8;i[e]|=1<<t}return{data:i,width:t,height:n,bytesPerRow:r}}function s(i,s,c,l={}){let u=e(i,s,c),d=l.dither??`threshold`,f;switch(d){case`floyd-steinberg`:f=n(u,s,c);break;case`atkinson`:f=r(u,s,c);break;case`ordered`:f=a(u,s,c);break;default:f=t(u,s,c,l.threshold??128);break}return o(f,s,c)}export{r as ditherAtkinson,n as ditherFloydSteinberg,a as ditherOrdered,t as ditherThreshold,s as imageToMonochrome,o as packBitmap,e as rgbaToGrayscale};
|