Skip to content

Commit 7282d2a

Browse files
Add quantize plugin
1 parent e154c6b commit 7282d2a

9 files changed

+220
-0
lines changed

packages/jimp/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"@jimp/plugin-resize": "workspace:*",
6161
"@jimp/plugin-rotate": "workspace:*",
6262
"@jimp/plugin-threshold": "workspace:*",
63+
"@jimp/plugin-quantize": "workspace:*",
6364
"@jimp/types": "workspace:*",
6465
"@jimp/utils": "workspace:*"
6566
},

packages/jimp/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import * as print from "@jimp/plugin-print";
2727
import * as resize from "@jimp/plugin-resize";
2828
import * as rotate from "@jimp/plugin-rotate";
2929
import * as threshold from "@jimp/plugin-threshold";
30+
import * as quantize from "@jimp/plugin-quantize";
3031

3132
import { createJimp } from "@jimp/core";
3233

@@ -119,6 +120,7 @@ export const Jimp = createJimp({
119120
resize.methods,
120121
rotate.methods,
121122
threshold.methods,
123+
quantize.methods,
122124
],
123125
});
124126

plugins/quantize/package.json

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"name": "@jimp/plugin-quantize",
3+
"version": "1.0.1",
4+
"repository": "jimp-dev/jimp",
5+
"scripts": {
6+
"lint": "eslint .",
7+
"test": "vitest",
8+
"build": "tshy",
9+
"dev": "tshy --watch",
10+
"clean": "rm -rf node_modules .tshy .tshy-build dist .turbo"
11+
},
12+
"author": "Andrew Lisowski <[email protected]>",
13+
"license": "MIT",
14+
"devDependencies": {
15+
"@jimp/config-eslint": "workspace:*",
16+
"@jimp/config-typescript": "workspace:*",
17+
"@jimp/core": "workspace:*",
18+
"@jimp/js-jpeg": "workspace:*",
19+
"@jimp/js-png": "workspace:*",
20+
"@jimp/test-utils": "workspace:*",
21+
"@jimp/types": "workspace:*",
22+
"eslint": "^8.57.0",
23+
"tshy": "^3.0.2",
24+
"typescript": "^5.5.4",
25+
"vitest": "^1.4.0"
26+
},
27+
"tshy": {
28+
"exclude": [
29+
"**/*.test.ts"
30+
],
31+
"exports": {
32+
"./package.json": "./package.json",
33+
".": "./src/index.ts"
34+
}
35+
},
36+
"exports": {
37+
"./package.json": "./package.json",
38+
".": {
39+
"import": {
40+
"types": "./dist/esm/index.d.ts",
41+
"default": "./dist/esm/index.js"
42+
},
43+
"require": {
44+
"types": "./dist/commonjs/index.d.ts",
45+
"default": "./dist/commonjs/index.js"
46+
}
47+
}
48+
},
49+
"main": "./dist/commonjs/index.js",
50+
"types": "./dist/commonjs/index.d.ts",
51+
"type": "module",
52+
"publishConfig": {
53+
"access": "public"
54+
},
55+
"sideEffects": false,
56+
"dependencies": {
57+
"image-q": "^4.0.0",
58+
"zod": "^3.22.4"
59+
},
60+
"module": "./dist/esm/index.js"
61+
}
69.5 KB
Loading
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { expect, test, describe } from "vitest";
2+
import "@jimp/test-utils";
3+
import "@jimp/test-utils/image-snapshot";
4+
5+
import png from "@jimp/js-png";
6+
import { createJimp } from "@jimp/core";
7+
8+
import { methods as quantize } from "./index.js";
9+
10+
const jimp = createJimp({ formats: [png], plugins: [quantize] });
11+
12+
describe("Quantize", () => {
13+
test("defines default threshold for lighter backgrounds", async () => {
14+
const testImage = await jimp.read(__dirname + "/images/colorful.png");
15+
const output = await testImage
16+
.quantize({
17+
colors: 8,
18+
})
19+
.getBuffer("image/png");
20+
21+
expect(output).toMatchImageSnapshot();
22+
});
23+
});

plugins/quantize/src/index.ts

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { JimpClass } from "@jimp/types";
2+
import { applyPaletteSync, buildPaletteSync, utils } from "image-q";
3+
import z from "zod";
4+
5+
const QuantizeOptionsSchema = z.object({
6+
colors: z.number().optional(),
7+
colorDistanceFormula: z
8+
.union([
9+
z.literal("cie94-textiles"),
10+
z.literal("cie94-graphic-arts"),
11+
z.literal("ciede2000"),
12+
z.literal("color-metric"),
13+
z.literal("euclidean"),
14+
z.literal("euclidean-bt709-noalpha"),
15+
z.literal("euclidean-bt709"),
16+
z.literal("manhattan"),
17+
z.literal("manhattan-bt709"),
18+
z.literal("manhattan-nommyde"),
19+
z.literal("pngquant"),
20+
])
21+
.optional(),
22+
paletteQuantization: z
23+
.union([
24+
z.literal("neuquant"),
25+
z.literal("neuquant-float"),
26+
z.literal("rgbquant"),
27+
z.literal("wuquant"),
28+
])
29+
.optional(),
30+
imageQuantization: z
31+
.union([
32+
z.literal("nearest"),
33+
z.literal("riemersma"),
34+
z.literal("floyd-steinberg"),
35+
z.literal("false-floyd-steinberg"),
36+
z.literal("stucki"),
37+
z.literal("atkinson"),
38+
z.literal("jarvis"),
39+
z.literal("burkes"),
40+
z.literal("sierra"),
41+
z.literal("two-sierra"),
42+
z.literal("sierra-lite"),
43+
])
44+
.optional(),
45+
});
46+
47+
export type QuantizeOptions = z.infer<typeof QuantizeOptionsSchema>;
48+
49+
export const methods = {
50+
/**
51+
*/
52+
quantize<I extends JimpClass>(
53+
image: I,
54+
{
55+
colors,
56+
colorDistanceFormula,
57+
paletteQuantization,
58+
imageQuantization,
59+
}: QuantizeOptions
60+
) {
61+
const inPointContainer = utils.PointContainer.fromUint8Array(
62+
image.bitmap.data,
63+
image.bitmap.width,
64+
image.bitmap.height
65+
);
66+
67+
const palette = buildPaletteSync([inPointContainer], {
68+
colors,
69+
colorDistanceFormula,
70+
paletteQuantization,
71+
});
72+
const outPointContainer = applyPaletteSync(inPointContainer, palette, {
73+
colorDistanceFormula,
74+
imageQuantization,
75+
});
76+
77+
image.bitmap.data = Buffer.from(outPointContainer.toUint8Array());
78+
79+
return image;
80+
},
81+
};

plugins/quantize/tsconfig.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "@jimp/config-typescript/base.json",
3+
"compilerOptions": {
4+
"outDir": "dist"
5+
}
6+
}

pnpm-lock.yaml

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)