@opendisplay/epaper-dithering 2.1.4 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -14,6 +14,159 @@ var DitherMode = /* @__PURE__ */ ((DitherMode2) => {
14
14
  return DitherMode2;
15
15
  })(DitherMode || {});
16
16
 
17
+ // src/color_space.ts
18
+ var SRGB_TO_LINEAR_LUT = (() => {
19
+ const lut = new Float64Array(256);
20
+ for (let i = 0; i < 256; i++) {
21
+ const s = i / 255;
22
+ lut[i] = s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
23
+ }
24
+ return lut;
25
+ })();
26
+
27
+ // src/color_space_lab.ts
28
+ var M00 = 0.4124564;
29
+ var M01 = 0.3575761;
30
+ var M02 = 0.1804375;
31
+ var M10 = 0.2126729;
32
+ var M11 = 0.7151522;
33
+ var M12 = 0.072175;
34
+ var M20 = 0.0193339;
35
+ var M21 = 0.119192;
36
+ var M22 = 0.9503041;
37
+ var XN = 0.95047;
38
+ var YN = 1;
39
+ var ZN = 1.08883;
40
+ var EPSILON = 216 / 24389;
41
+ var KAPPA = 24389 / 27;
42
+ var WL2 = 0.25;
43
+ var WC2 = 1;
44
+ var WH2 = 4;
45
+ function labF(t) {
46
+ return t > EPSILON ? Math.cbrt(t) : (KAPPA * t + 16) / 116;
47
+ }
48
+ function rgbToLabScalar(r, g, b) {
49
+ const x = M00 * r + M01 * g + M02 * b;
50
+ const y = M10 * r + M11 * g + M12 * b;
51
+ const z = M20 * r + M21 * g + M22 * b;
52
+ const fx = labF(x / XN);
53
+ const fy = labF(y / YN);
54
+ const fz = labF(z / ZN);
55
+ return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
56
+ }
57
+ function precomputePaletteLab(paletteLinear) {
58
+ const n = paletteLinear.length;
59
+ const L = new Float64Array(n);
60
+ const a = new Float64Array(n);
61
+ const b = new Float64Array(n);
62
+ const C = new Float64Array(n);
63
+ for (let i = 0; i < n; i++) {
64
+ const [pl, pa, pb] = rgbToLabScalar(paletteLinear[i][0], paletteLinear[i][1], paletteLinear[i][2]);
65
+ L[i] = pl;
66
+ a[i] = pa;
67
+ b[i] = pb;
68
+ C[i] = Math.sqrt(pa * pa + pb * pb);
69
+ }
70
+ return { L, a, b, C };
71
+ }
72
+ function matchPixelLch(r, g, b, paletteL, paletteA, paletteB, paletteC) {
73
+ const [pL, pa, pb] = rgbToLabScalar(r, g, b);
74
+ const pC = Math.sqrt(pa * pa + pb * pb);
75
+ let bestIdx = 0;
76
+ let bestDist = Infinity;
77
+ const n = paletteL.length;
78
+ for (let i = 0; i < n; i++) {
79
+ const dL = pL - paletteL[i];
80
+ const da = pa - paletteA[i];
81
+ const db = pb - paletteB[i];
82
+ const dC = pC - paletteC[i];
83
+ let dHsq = da * da + db * db - dC * dC;
84
+ if (dHsq < 0) dHsq = 0;
85
+ const dist = WL2 * dL * dL + WC2 * dC * dC + WH2 * dHsq;
86
+ if (dist < bestDist) {
87
+ bestDist = dist;
88
+ bestIdx = i;
89
+ }
90
+ }
91
+ return bestIdx;
92
+ }
93
+
94
+ // src/tone_map.ts
95
+ var LUM_R = 0.2126729;
96
+ var LUM_G = 0.7151522;
97
+ var LUM_B = 0.072175;
98
+ function compressDynamicRange(pixels, width, height, paletteLinear, strength = 1) {
99
+ if (strength <= 0) return;
100
+ const [br, bg, bb] = paletteLinear[0];
101
+ const [wr, wg, wb] = paletteLinear[1];
102
+ const blackY = LUM_R * br + LUM_G * bg + LUM_B * bb;
103
+ const whiteY = LUM_R * wr + LUM_G * wg + LUM_B * wb;
104
+ const displayRange = whiteY - blackY;
105
+ if (displayRange <= 0) return;
106
+ const n = width * height;
107
+ const blackLevel = blackY * strength;
108
+ for (let i = 0; i < n; i++) {
109
+ const base = i * 3;
110
+ const r = pixels[base];
111
+ const g = pixels[base + 1];
112
+ const b = pixels[base + 2];
113
+ const Y = LUM_R * r + LUM_G * g + LUM_B * b;
114
+ if (Y > 1e-6) {
115
+ const compressedY = blackY + Y * displayRange;
116
+ const targetY = strength < 1 ? Y + strength * (compressedY - Y) : compressedY;
117
+ const scale = targetY / Y;
118
+ pixels[base] = Math.max(0, Math.min(1, r * scale));
119
+ pixels[base + 1] = Math.max(0, Math.min(1, g * scale));
120
+ pixels[base + 2] = Math.max(0, Math.min(1, b * scale));
121
+ } else {
122
+ pixels[base] = blackLevel;
123
+ pixels[base + 1] = blackLevel;
124
+ pixels[base + 2] = blackLevel;
125
+ }
126
+ }
127
+ }
128
+ function autoCompressDynamicRange(pixels, width, height, paletteLinear) {
129
+ const [br, bg, bb] = paletteLinear[0];
130
+ const [wr, wg, wb] = paletteLinear[1];
131
+ const blackY = LUM_R * br + LUM_G * bg + LUM_B * bb;
132
+ const whiteY = LUM_R * wr + LUM_G * wg + LUM_B * wb;
133
+ const displayRange = whiteY - blackY;
134
+ if (displayRange <= 0) return;
135
+ const n = width * height;
136
+ const luminances = new Float32Array(n);
137
+ for (let i = 0; i < n; i++) {
138
+ const base = i * 3;
139
+ luminances[i] = LUM_R * pixels[base] + LUM_G * pixels[base + 1] + LUM_B * pixels[base + 2];
140
+ }
141
+ luminances.sort();
142
+ const pLow = luminances[Math.floor(n * 0.02)];
143
+ const pHigh = luminances[Math.floor(n * 0.98)];
144
+ const imageRange = pHigh - pLow;
145
+ if (imageRange < 1e-6) {
146
+ compressDynamicRange(pixels, width, height, paletteLinear, 1);
147
+ return;
148
+ }
149
+ for (let i = 0; i < n; i++) {
150
+ const base = i * 3;
151
+ const r = pixels[base];
152
+ const g = pixels[base + 1];
153
+ const b = pixels[base + 2];
154
+ const Y = LUM_R * r + LUM_G * g + LUM_B * b;
155
+ if (Y > 1e-6) {
156
+ const normalizedY = (Y - pLow) / imageRange;
157
+ const targetY = blackY + normalizedY * displayRange;
158
+ const scale = targetY / Y;
159
+ pixels[base] = Math.max(0, Math.min(1, r * scale));
160
+ pixels[base + 1] = Math.max(0, Math.min(1, g * scale));
161
+ pixels[base + 2] = Math.max(0, Math.min(1, b * scale));
162
+ } else {
163
+ pixels[base] = blackY;
164
+ pixels[base + 1] = blackY;
165
+ pixels[base + 2] = blackY;
166
+ }
167
+ }
168
+ }
169
+
17
170
  // src/palettes.ts
18
171
  var ColorScheme = /* @__PURE__ */ ((ColorScheme3) => {
19
172
  ColorScheme3[ColorScheme3["MONO"] = 0] = "MONO";
@@ -22,6 +175,8 @@ var ColorScheme = /* @__PURE__ */ ((ColorScheme3) => {
22
175
  ColorScheme3[ColorScheme3["BWRY"] = 3] = "BWRY";
23
176
  ColorScheme3[ColorScheme3["BWGBRY"] = 4] = "BWGBRY";
24
177
  ColorScheme3[ColorScheme3["GRAYSCALE_4"] = 5] = "GRAYSCALE_4";
178
+ ColorScheme3[ColorScheme3["GRAYSCALE_8"] = 6] = "GRAYSCALE_8";
179
+ ColorScheme3[ColorScheme3["GRAYSCALE_16"] = 7] = "GRAYSCALE_16";
25
180
  return ColorScheme3;
26
181
  })(ColorScheme || {});
27
182
  var PALETTES = {
@@ -76,6 +231,40 @@ var PALETTES = {
76
231
  white: { r: 255, g: 255, b: 255 }
77
232
  },
78
233
  accent: "black"
234
+ },
235
+ [6 /* GRAYSCALE_8 */]: {
236
+ colors: {
237
+ black: { r: 0, g: 0, b: 0 },
238
+ gray1: { r: 36, g: 36, b: 36 },
239
+ gray2: { r: 73, g: 73, b: 73 },
240
+ gray3: { r: 109, g: 109, b: 109 },
241
+ gray4: { r: 146, g: 146, b: 146 },
242
+ gray5: { r: 182, g: 182, b: 182 },
243
+ gray6: { r: 219, g: 219, b: 219 },
244
+ white: { r: 255, g: 255, b: 255 }
245
+ },
246
+ accent: "black"
247
+ },
248
+ [7 /* GRAYSCALE_16 */]: {
249
+ colors: {
250
+ black: { r: 0, g: 0, b: 0 },
251
+ gray1: { r: 17, g: 17, b: 17 },
252
+ gray2: { r: 34, g: 34, b: 34 },
253
+ gray3: { r: 51, g: 51, b: 51 },
254
+ gray4: { r: 68, g: 68, b: 68 },
255
+ gray5: { r: 85, g: 85, b: 85 },
256
+ gray6: { r: 102, g: 102, b: 102 },
257
+ gray7: { r: 119, g: 119, b: 119 },
258
+ gray8: { r: 136, g: 136, b: 136 },
259
+ gray9: { r: 153, g: 153, b: 153 },
260
+ gray10: { r: 170, g: 170, b: 170 },
261
+ gray11: { r: 187, g: 187, b: 187 },
262
+ gray12: { r: 204, g: 204, b: 204 },
263
+ gray13: { r: 221, g: 221, b: 221 },
264
+ gray14: { r: 238, g: 238, b: 238 },
265
+ white: { r: 255, g: 255, b: 255 }
266
+ },
267
+ accent: "black"
79
268
  }
80
269
  };
81
270
  function getPalette(scheme) {
@@ -85,143 +274,230 @@ function getColorCount(scheme) {
85
274
  return Object.keys(PALETTES[scheme].colors).length;
86
275
  }
87
276
  function fromValue(value) {
88
- if (value < 0 || value > 5) {
277
+ if (value < 0 || value > 7) {
89
278
  throw new Error(`Invalid color scheme value: ${value}`);
90
279
  }
91
280
  return value;
92
281
  }
282
+ var SPECTRA_7_3_6COLOR = {
283
+ colors: {
284
+ black: { r: 26, g: 13, b: 35 },
285
+ white: { r: 185, g: 202, b: 205 },
286
+ yellow: { r: 202, g: 184, b: 0 },
287
+ red: { r: 121, g: 9, b: 0 },
288
+ blue: { r: 0, g: 69, b: 139 },
289
+ green: { r: 40, g: 82, b: 57 }
290
+ },
291
+ accent: "red"
292
+ };
293
+ var MONO_4_26 = {
294
+ colors: {
295
+ black: { r: 5, g: 5, b: 5 },
296
+ white: { r: 220, g: 220, b: 220 }
297
+ },
298
+ accent: "black"
299
+ };
300
+ var BWRY_4_2 = {
301
+ colors: {
302
+ black: { r: 5, g: 5, b: 5 },
303
+ white: { r: 200, g: 200, b: 200 },
304
+ yellow: { r: 200, g: 180, b: 0 },
305
+ red: { r: 120, g: 15, b: 5 }
306
+ },
307
+ accent: "red"
308
+ };
309
+ var SOLUM_BWR = {
310
+ colors: {
311
+ black: { r: 5, g: 5, b: 5 },
312
+ white: { r: 200, g: 200, b: 200 },
313
+ red: { r: 120, g: 15, b: 5 }
314
+ },
315
+ accent: "red"
316
+ };
317
+ var HANSHOW_BWR = {
318
+ colors: {
319
+ black: { r: 5, g: 5, b: 5 },
320
+ white: { r: 200, g: 200, b: 200 },
321
+ red: { r: 120, g: 15, b: 5 }
322
+ },
323
+ accent: "red"
324
+ };
325
+ var HANSHOW_BWY = {
326
+ colors: {
327
+ black: { r: 5, g: 5, b: 5 },
328
+ white: { r: 200, g: 200, b: 200 },
329
+ yellow: { r: 200, g: 180, b: 0 }
330
+ },
331
+ accent: "yellow"
332
+ };
333
+ var BWRY_3_97 = {
334
+ colors: {
335
+ black: { r: 10, g: 7, b: 14 },
336
+ white: { r: 173, g: 178, b: 174 },
337
+ yellow: { r: 172, g: 128, b: 0 },
338
+ red: { r: 85, g: 24, b: 14 }
339
+ },
340
+ accent: "red"
341
+ };
93
342
 
94
343
  // src/algorithms.ts
95
- function getPaletteColors(scheme) {
96
- const palette = getPalette(scheme);
97
- return Object.values(palette.colors);
344
+ var BAYER_4X4 = new Float32Array([
345
+ 0,
346
+ 8,
347
+ 2,
348
+ 10,
349
+ 12,
350
+ 4,
351
+ 14,
352
+ 6,
353
+ 3,
354
+ 11,
355
+ 1,
356
+ 9,
357
+ 15,
358
+ 7,
359
+ 13,
360
+ 5
361
+ ].map((v) => v / 16 - 0.5));
362
+ function resolvePalette(scheme) {
363
+ return typeof scheme === "number" ? getPalette(scheme) : scheme;
98
364
  }
99
- function findClosestPaletteColor(rgb, palette) {
100
- let minDistance = Infinity;
101
- let closestIdx = 0;
102
- for (let i = 0; i < palette.length; i++) {
103
- const pal = palette[i];
104
- const distance = (rgb.r - pal.r) ** 2 + (rgb.g - pal.g) ** 2 + (rgb.b - pal.b) ** 2;
105
- if (distance < minDistance) {
106
- minDistance = distance;
107
- closestIdx = i;
108
- }
365
+ function paletteToLinear(palette) {
366
+ const paletteRgb = Object.values(palette.colors);
367
+ const paletteLinear = paletteRgb.map((c) => [
368
+ SRGB_TO_LINEAR_LUT[c.r],
369
+ SRGB_TO_LINEAR_LUT[c.g],
370
+ SRGB_TO_LINEAR_LUT[c.b]
371
+ ]);
372
+ return { paletteRgb, paletteLinear };
373
+ }
374
+ function buildLinearBuffer(image) {
375
+ const n = image.width * image.height;
376
+ const pixels = new Float32Array(n * 3);
377
+ const { data } = image;
378
+ for (let i = 0; i < n; i++) {
379
+ const base4 = i * 4;
380
+ const base3 = i * 3;
381
+ const alpha = data[base4 + 3] / 255;
382
+ const inv = 1 - alpha;
383
+ pixels[base3] = SRGB_TO_LINEAR_LUT[data[base4]] * alpha + inv;
384
+ pixels[base3 + 1] = SRGB_TO_LINEAR_LUT[data[base4 + 1]] * alpha + inv;
385
+ pixels[base3 + 2] = SRGB_TO_LINEAR_LUT[data[base4 + 2]] * alpha + inv;
109
386
  }
110
- return closestIdx;
387
+ return pixels;
111
388
  }
112
- function errorDiffusionDither(image, colorScheme, kernel) {
389
+ function errorDiffusionDither(image, scheme, kernel, serpentine) {
113
390
  const { width, height } = image;
114
- const palette = getPaletteColors(colorScheme);
115
- const pixels = new Float32Array(width * height * 3);
116
- for (let i = 0; i < width * height; i++) {
117
- pixels[i * 3] = image.data[i * 4];
118
- pixels[i * 3 + 1] = image.data[i * 4 + 1];
119
- pixels[i * 3 + 2] = image.data[i * 4 + 2];
391
+ const palette = resolvePalette(scheme);
392
+ const { paletteRgb, paletteLinear } = paletteToLinear(palette);
393
+ const numColors = paletteRgb.length;
394
+ const pixels = buildLinearBuffer(image);
395
+ if (typeof scheme !== "number") {
396
+ autoCompressDynamicRange(pixels, width, height, paletteLinear);
397
+ }
398
+ const { L: palL, a: palA, b: palB, C: palC } = precomputePaletteLab(paletteLinear);
399
+ const palR = new Float64Array(numColors);
400
+ const palG = new Float64Array(numColors);
401
+ const palBl = new Float64Array(numColors);
402
+ for (let i = 0; i < numColors; i++) {
403
+ palR[i] = paletteLinear[i][0];
404
+ palG[i] = paletteLinear[i][1];
405
+ palBl[i] = paletteLinear[i][2];
120
406
  }
121
407
  const indices = new Uint8Array(width * height);
122
408
  for (let y = 0; y < height; y++) {
123
- for (let x = 0; x < width; x++) {
124
- const idx = y * width + x;
125
- const pixelIdx = idx * 3;
126
- const oldPixel = {
127
- r: Math.trunc(pixels[pixelIdx]),
128
- g: Math.trunc(pixels[pixelIdx + 1]),
129
- b: Math.trunc(pixels[pixelIdx + 2])
130
- };
131
- const newIdx = findClosestPaletteColor(oldPixel, palette);
132
- const newPixel = palette[newIdx];
133
- indices[idx] = newIdx;
134
- const errorR = oldPixel.r - newPixel.r;
135
- const errorG = oldPixel.g - newPixel.g;
136
- const errorB = oldPixel.b - newPixel.b;
137
- for (const { dx, dy, weight } of kernel) {
138
- const nx = x + dx;
139
- const ny = y + dy;
409
+ const leftToRight = !serpentine || y % 2 === 0;
410
+ const xStart = leftToRight ? 0 : width - 1;
411
+ const xEnd = leftToRight ? width : -1;
412
+ const xStep = leftToRight ? 1 : -1;
413
+ for (let x = xStart; x !== xEnd; x += xStep) {
414
+ const pixIdx = (y * width + x) * 3;
415
+ const r = Math.max(0, Math.min(1, pixels[pixIdx]));
416
+ const g = Math.max(0, Math.min(1, pixels[pixIdx + 1]));
417
+ const b = Math.max(0, Math.min(1, pixels[pixIdx + 2]));
418
+ const newIdx = matchPixelLch(r, g, b, palL, palA, palB, palC);
419
+ indices[y * width + x] = newIdx;
420
+ const errR = r - palR[newIdx];
421
+ const errG = g - palG[newIdx];
422
+ const errB = b - palBl[newIdx];
423
+ for (let k = 0; k < kernel.length; k++) {
424
+ const kEntry = kernel[k];
425
+ const nx = x + (leftToRight ? kEntry.dx : -kEntry.dx);
426
+ const ny = y + kEntry.dy;
140
427
  if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
141
- const neighborIdx = (ny * width + nx) * 3;
142
- pixels[neighborIdx] += errorR * weight;
143
- pixels[neighborIdx + 1] += errorG * weight;
144
- pixels[neighborIdx + 2] += errorB * weight;
428
+ const nIdx = (ny * width + nx) * 3;
429
+ pixels[nIdx] += errR * kEntry.weight;
430
+ pixels[nIdx + 1] += errG * kEntry.weight;
431
+ pixels[nIdx + 2] += errB * kEntry.weight;
145
432
  }
146
433
  }
147
434
  }
148
435
  }
149
- return { width, height, indices, palette };
436
+ return { width, height, indices, palette: paletteRgb };
150
437
  }
151
- function directPaletteMap(image, colorScheme) {
438
+ function directPaletteMap(image, scheme) {
152
439
  const { width, height } = image;
153
- const palette = getPaletteColors(colorScheme);
440
+ const palette = resolvePalette(scheme);
441
+ const { paletteRgb, paletteLinear } = paletteToLinear(palette);
442
+ const pixels = buildLinearBuffer(image);
443
+ if (typeof scheme !== "number") {
444
+ autoCompressDynamicRange(pixels, width, height, paletteLinear);
445
+ }
446
+ const { L: palL, a: palA, b: palB, C: palC } = precomputePaletteLab(paletteLinear);
154
447
  const indices = new Uint8Array(width * height);
155
- for (let i = 0; i < width * height; i++) {
156
- const rgb = {
157
- r: image.data[i * 4],
158
- g: image.data[i * 4 + 1],
159
- b: image.data[i * 4 + 2]
160
- };
161
- indices[i] = findClosestPaletteColor(rgb, palette);
448
+ const n = width * height;
449
+ for (let i = 0; i < n; i++) {
450
+ const base = i * 3;
451
+ const r = Math.max(0, Math.min(1, pixels[base]));
452
+ const g = Math.max(0, Math.min(1, pixels[base + 1]));
453
+ const b = Math.max(0, Math.min(1, pixels[base + 2]));
454
+ indices[i] = matchPixelLch(r, g, b, palL, palA, palB, palC);
162
455
  }
163
- return { width, height, indices, palette };
456
+ return { width, height, indices, palette: paletteRgb };
164
457
  }
165
- function orderedDither(image, colorScheme) {
166
- const bayerMatrix = new Uint8Array([
167
- 0,
168
- 8,
169
- 2,
170
- 10,
171
- 12,
172
- 4,
173
- 14,
174
- 6,
175
- 3,
176
- 11,
177
- 1,
178
- 9,
179
- 15,
180
- 7,
181
- 13,
182
- 5
183
- ]).map((v) => v * 16);
458
+ function orderedDither(image, scheme) {
184
459
  const { width, height } = image;
185
- const palette = getPaletteColors(colorScheme);
460
+ const palette = resolvePalette(scheme);
461
+ const { paletteRgb, paletteLinear } = paletteToLinear(palette);
462
+ const pixels = buildLinearBuffer(image);
463
+ if (typeof scheme !== "number") {
464
+ autoCompressDynamicRange(pixels, width, height, paletteLinear);
465
+ }
466
+ const { L: palL, a: palA, b: palB, C: palC } = precomputePaletteLab(paletteLinear);
186
467
  const indices = new Uint8Array(width * height);
187
468
  for (let y = 0; y < height; y++) {
188
469
  for (let x = 0; x < width; x++) {
189
- const idx = y * width + x;
190
- const dataIdx = idx * 4;
191
- const threshold = bayerMatrix[y % 4 * 4 + x % 4];
192
- const rgb = {
193
- r: Math.max(0, Math.min(255, Math.trunc(image.data[dataIdx] + threshold))),
194
- g: Math.max(0, Math.min(255, Math.trunc(image.data[dataIdx + 1] + threshold))),
195
- b: Math.max(0, Math.min(255, Math.trunc(image.data[dataIdx + 2] + threshold)))
196
- };
197
- indices[idx] = findClosestPaletteColor(rgb, palette);
470
+ const base = (y * width + x) * 3;
471
+ const threshold = BAYER_4X4[y % 4 * 4 + x % 4];
472
+ const r = Math.max(0, Math.min(1, pixels[base] + threshold));
473
+ const g = Math.max(0, Math.min(1, pixels[base + 1] + threshold));
474
+ const b = Math.max(0, Math.min(1, pixels[base + 2] + threshold));
475
+ indices[y * width + x] = matchPixelLch(r, g, b, palL, palA, palB, palC);
198
476
  }
199
477
  }
200
- return { width, height, indices, palette };
478
+ return { width, height, indices, palette: paletteRgb };
201
479
  }
202
- function burkesDither(image, colorScheme) {
203
- const kernel = [
204
- { dx: 1, dy: 0, weight: 32 / 200 },
205
- { dx: 2, dy: 0, weight: 12 / 200 },
206
- { dx: -2, dy: 1, weight: 5 / 200 },
207
- { dx: -1, dy: 1, weight: 12 / 200 },
208
- { dx: 0, dy: 1, weight: 26 / 200 },
209
- { dx: 1, dy: 1, weight: 12 / 200 },
210
- { dx: 2, dy: 1, weight: 5 / 200 }
211
- ];
212
- return errorDiffusionDither(image, colorScheme, kernel);
213
- }
214
- function floydSteinbergDither(image, colorScheme) {
215
- const kernel = [
480
+ function floydSteinbergDither(image, scheme, serpentine = true) {
481
+ return errorDiffusionDither(image, scheme, [
216
482
  { dx: 1, dy: 0, weight: 7 / 16 },
217
483
  { dx: -1, dy: 1, weight: 3 / 16 },
218
484
  { dx: 0, dy: 1, weight: 5 / 16 },
219
485
  { dx: 1, dy: 1, weight: 1 / 16 }
220
- ];
221
- return errorDiffusionDither(image, colorScheme, kernel);
486
+ ], serpentine);
487
+ }
488
+ function burkesDither(image, scheme, serpentine = true) {
489
+ return errorDiffusionDither(image, scheme, [
490
+ { dx: 1, dy: 0, weight: 8 / 32 },
491
+ { dx: 2, dy: 0, weight: 4 / 32 },
492
+ { dx: -2, dy: 1, weight: 2 / 32 },
493
+ { dx: -1, dy: 1, weight: 4 / 32 },
494
+ { dx: 0, dy: 1, weight: 8 / 32 },
495
+ { dx: 1, dy: 1, weight: 4 / 32 },
496
+ { dx: 2, dy: 1, weight: 2 / 32 }
497
+ ], serpentine);
222
498
  }
223
- function sierraDither(image, colorScheme) {
224
- const kernel = [
499
+ function sierraDither(image, scheme, serpentine = true) {
500
+ return errorDiffusionDither(image, scheme, [
225
501
  { dx: 1, dy: 0, weight: 5 / 32 },
226
502
  { dx: 2, dy: 0, weight: 3 / 32 },
227
503
  { dx: -2, dy: 1, weight: 2 / 32 },
@@ -232,30 +508,27 @@ function sierraDither(image, colorScheme) {
232
508
  { dx: -1, dy: 2, weight: 2 / 32 },
233
509
  { dx: 0, dy: 2, weight: 3 / 32 },
234
510
  { dx: 1, dy: 2, weight: 2 / 32 }
235
- ];
236
- return errorDiffusionDither(image, colorScheme, kernel);
511
+ ], serpentine);
237
512
  }
238
- function sierraLiteDither(image, colorScheme) {
239
- const kernel = [
513
+ function sierraLiteDither(image, scheme, serpentine = true) {
514
+ return errorDiffusionDither(image, scheme, [
240
515
  { dx: 1, dy: 0, weight: 2 / 4 },
241
516
  { dx: -1, dy: 1, weight: 1 / 4 },
242
517
  { dx: 0, dy: 1, weight: 1 / 4 }
243
- ];
244
- return errorDiffusionDither(image, colorScheme, kernel);
518
+ ], serpentine);
245
519
  }
246
- function atkinsonDither(image, colorScheme) {
247
- const kernel = [
520
+ function atkinsonDither(image, scheme, serpentine = true) {
521
+ return errorDiffusionDither(image, scheme, [
248
522
  { dx: 1, dy: 0, weight: 1 / 8 },
249
523
  { dx: 2, dy: 0, weight: 1 / 8 },
250
524
  { dx: -1, dy: 1, weight: 1 / 8 },
251
525
  { dx: 0, dy: 1, weight: 1 / 8 },
252
526
  { dx: 1, dy: 1, weight: 1 / 8 },
253
527
  { dx: 0, dy: 2, weight: 1 / 8 }
254
- ];
255
- return errorDiffusionDither(image, colorScheme, kernel);
528
+ ], serpentine);
256
529
  }
257
- function stuckiDither(image, colorScheme) {
258
- const kernel = [
530
+ function stuckiDither(image, scheme, serpentine = true) {
531
+ return errorDiffusionDither(image, scheme, [
259
532
  { dx: 1, dy: 0, weight: 8 / 42 },
260
533
  { dx: 2, dy: 0, weight: 4 / 42 },
261
534
  { dx: -2, dy: 1, weight: 2 / 42 },
@@ -268,11 +541,10 @@ function stuckiDither(image, colorScheme) {
268
541
  { dx: 0, dy: 2, weight: 4 / 42 },
269
542
  { dx: 1, dy: 2, weight: 2 / 42 },
270
543
  { dx: 2, dy: 2, weight: 1 / 42 }
271
- ];
272
- return errorDiffusionDither(image, colorScheme, kernel);
544
+ ], serpentine);
273
545
  }
274
- function jarvisJudiceNinkeDither(image, colorScheme) {
275
- const kernel = [
546
+ function jarvisJudiceNinkeDither(image, scheme, serpentine = true) {
547
+ return errorDiffusionDither(image, scheme, [
276
548
  { dx: 1, dy: 0, weight: 7 / 48 },
277
549
  { dx: 2, dy: 0, weight: 5 / 48 },
278
550
  { dx: -2, dy: 1, weight: 3 / 48 },
@@ -285,40 +557,46 @@ function jarvisJudiceNinkeDither(image, colorScheme) {
285
557
  { dx: 0, dy: 2, weight: 5 / 48 },
286
558
  { dx: 1, dy: 2, weight: 3 / 48 },
287
559
  { dx: 2, dy: 2, weight: 1 / 48 }
288
- ];
289
- return errorDiffusionDither(image, colorScheme, kernel);
560
+ ], serpentine);
290
561
  }
291
562
 
292
563
  // src/core.ts
293
- function ditherImage(image, colorScheme, mode = 1 /* BURKES */) {
564
+ function ditherImage(image, colorScheme, mode = 1 /* BURKES */, serpentine = true) {
294
565
  switch (mode) {
295
566
  case 0 /* NONE */:
296
567
  return directPaletteMap(image, colorScheme);
297
568
  case 2 /* ORDERED */:
298
569
  return orderedDither(image, colorScheme);
299
570
  case 3 /* FLOYD_STEINBERG */:
300
- return floydSteinbergDither(image, colorScheme);
571
+ return floydSteinbergDither(image, colorScheme, serpentine);
301
572
  case 4 /* ATKINSON */:
302
- return atkinsonDither(image, colorScheme);
573
+ return atkinsonDither(image, colorScheme, serpentine);
303
574
  case 5 /* STUCKI */:
304
- return stuckiDither(image, colorScheme);
575
+ return stuckiDither(image, colorScheme, serpentine);
305
576
  case 6 /* SIERRA */:
306
- return sierraDither(image, colorScheme);
577
+ return sierraDither(image, colorScheme, serpentine);
307
578
  case 7 /* SIERRA_LITE */:
308
- return sierraLiteDither(image, colorScheme);
579
+ return sierraLiteDither(image, colorScheme, serpentine);
309
580
  case 8 /* JARVIS_JUDICE_NINKE */:
310
- return jarvisJudiceNinkeDither(image, colorScheme);
581
+ return jarvisJudiceNinkeDither(image, colorScheme, serpentine);
311
582
  case 1 /* BURKES */:
312
583
  default:
313
- return burkesDither(image, colorScheme);
584
+ return burkesDither(image, colorScheme, serpentine);
314
585
  }
315
586
  }
316
587
 
317
588
  // src/index.ts
318
589
  var VERSION = "0.1.0";
319
590
 
591
+ exports.BWRY_3_97 = BWRY_3_97;
592
+ exports.BWRY_4_2 = BWRY_4_2;
320
593
  exports.ColorScheme = ColorScheme;
321
594
  exports.DitherMode = DitherMode;
595
+ exports.HANSHOW_BWR = HANSHOW_BWR;
596
+ exports.HANSHOW_BWY = HANSHOW_BWY;
597
+ exports.MONO_4_26 = MONO_4_26;
598
+ exports.SOLUM_BWR = SOLUM_BWR;
599
+ exports.SPECTRA_7_3_6COLOR = SPECTRA_7_3_6COLOR;
322
600
  exports.VERSION = VERSION;
323
601
  exports.ditherImage = ditherImage;
324
602
  exports.fromValue = fromValue;