Skip to content

Commit

Permalink
Add quantize plugin (#1307)
Browse files Browse the repository at this point in the history
  • Loading branch information
hipstersmoothie authored Sep 1, 2024
1 parent e154c6b commit 1343488
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/jimp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@jimp/plugin-resize": "workspace:*",
"@jimp/plugin-rotate": "workspace:*",
"@jimp/plugin-threshold": "workspace:*",
"@jimp/plugin-quantize": "workspace:*",
"@jimp/types": "workspace:*",
"@jimp/utils": "workspace:*"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/jimp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import * as print from "@jimp/plugin-print";
import * as resize from "@jimp/plugin-resize";
import * as rotate from "@jimp/plugin-rotate";
import * as threshold from "@jimp/plugin-threshold";
import * as quantize from "@jimp/plugin-quantize";

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

Expand Down Expand Up @@ -119,6 +120,7 @@ export const Jimp = createJimp({
resize.methods,
rotate.methods,
threshold.methods,
quantize.methods,
],
});

Expand Down
5 changes: 5 additions & 0 deletions plugins/quantize/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: [require.resolve("@jimp/config-eslint/base.js")],
};
8 changes: 8 additions & 0 deletions plugins/quantize/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div align="center">
<img width="200" height="200"
src="https://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-11/256/crayon.png">
<h1>@jimp/plugin-quantize</h1>
<p>Reduces the number of colors in an image.</p>
</div>

- [quantize](http://jimp-dev.github.io/jimp/api/jimp/classes/jimp#quantize)
61 changes: 61 additions & 0 deletions plugins/quantize/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@jimp/plugin-quantize",
"version": "1.0.1",
"repository": "jimp-dev/jimp",
"scripts": {
"lint": "eslint .",
"test": "vitest",
"build": "tshy",
"dev": "tshy --watch",
"clean": "rm -rf node_modules .tshy .tshy-build dist .turbo"
},
"author": "Andrew Lisowski <[email protected]>",
"license": "MIT",
"devDependencies": {
"@jimp/config-eslint": "workspace:*",
"@jimp/config-typescript": "workspace:*",
"@jimp/core": "workspace:*",
"@jimp/js-jpeg": "workspace:*",
"@jimp/js-png": "workspace:*",
"@jimp/test-utils": "workspace:*",
"@jimp/types": "workspace:*",
"eslint": "^8.57.0",
"tshy": "^3.0.2",
"typescript": "^5.5.4",
"vitest": "^1.4.0"
},
"tshy": {
"exclude": [
"**/*.test.ts"
],
"exports": {
"./package.json": "./package.json",
".": "./src/index.ts"
}
},
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.js"
}
}
},
"main": "./dist/commonjs/index.js",
"types": "./dist/commonjs/index.d.ts",
"type": "module",
"publishConfig": {
"access": "public"
},
"sideEffects": false,
"dependencies": {
"image-q": "^4.0.0",
"zod": "^3.22.4"
},
"module": "./dist/esm/index.js"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugins/quantize/src/images/colorful.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions plugins/quantize/src/index.node.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect, test, describe } from "vitest";
import "@jimp/test-utils";
import "@jimp/test-utils/image-snapshot";

import png from "@jimp/js-png";
import { createJimp } from "@jimp/core";

import { methods as quantize } from "./index.js";

const jimp = createJimp({ formats: [png], plugins: [quantize] });

describe("Quantize", () => {
test("defines default threshold for lighter backgrounds", async () => {
const testImage = await jimp.read(__dirname + "/images/colorful.png");
const output = await testImage
.quantize({
colors: 8,
})
.getBuffer("image/png");

expect(output).toMatchImageSnapshot();
});
});
82 changes: 82 additions & 0 deletions plugins/quantize/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { JimpClass } from "@jimp/types";
import { applyPaletteSync, buildPaletteSync, utils } from "image-q";
import z from "zod";

const QuantizeOptionsSchema = z.object({
colors: z.number().optional(),
colorDistanceFormula: z
.union([
z.literal("cie94-textiles"),
z.literal("cie94-graphic-arts"),
z.literal("ciede2000"),
z.literal("color-metric"),
z.literal("euclidean"),
z.literal("euclidean-bt709-noalpha"),
z.literal("euclidean-bt709"),
z.literal("manhattan"),
z.literal("manhattan-bt709"),
z.literal("manhattan-nommyde"),
z.literal("pngquant"),
])
.optional(),
paletteQuantization: z
.union([
z.literal("neuquant"),
z.literal("neuquant-float"),
z.literal("rgbquant"),
z.literal("wuquant"),
])
.optional(),
imageQuantization: z
.union([
z.literal("nearest"),
z.literal("riemersma"),
z.literal("floyd-steinberg"),
z.literal("false-floyd-steinberg"),
z.literal("stucki"),
z.literal("atkinson"),
z.literal("jarvis"),
z.literal("burkes"),
z.literal("sierra"),
z.literal("two-sierra"),
z.literal("sierra-lite"),
])
.optional(),
});

export type QuantizeOptions = z.infer<typeof QuantizeOptionsSchema>;

export const methods = {
/**
* Image color number reduction.
*/
quantize<I extends JimpClass>(
image: I,
{
colors,
colorDistanceFormula,
paletteQuantization,
imageQuantization,
}: QuantizeOptions
) {
const inPointContainer = utils.PointContainer.fromUint8Array(
image.bitmap.data,
image.bitmap.width,
image.bitmap.height
);

const palette = buildPaletteSync([inPointContainer], {
colors,
colorDistanceFormula,
paletteQuantization,
});
const outPointContainer = applyPaletteSync(inPointContainer, palette, {
colorDistanceFormula,
imageQuantization,
});

image.bitmap.data = Buffer.from(outPointContainer.toUint8Array());

return image;
},
};
6 changes: 6 additions & 0 deletions plugins/quantize/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "@jimp/config-typescript/base.json",
"compilerOptions": {
"outDir": "dist"
}
}
46 changes: 46 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1343488

Please sign in to comment.