Skip to content

Commit

Permalink
use zod for param validation and normalize object APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
hipstersmoothie committed Apr 8, 2024
1 parent d80ad56 commit 8cf0f88
Show file tree
Hide file tree
Showing 53 changed files with 875 additions and 539 deletions.
6 changes: 1 addition & 5 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# TODO

- [ ] Object APIs

## Guides

- [ ] Getting Started
- [ ] Custom Jimp
- [ ] Authoring Plugins
- [ ] Using in Browser
- [] Using in Browser
- [ ] Worker
1 change: 0 additions & 1 deletion packages/core/src/utils/image-bitmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ function exifRotate<I extends JimpClass>(img: I) {

if (transformation) {
transformBitmap(img, newWidth, newHeight, transformation);
console.log("done", img);
}
}

Expand Down
10 changes: 8 additions & 2 deletions packages/diff/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ export function diff<I extends JimpClass>(img1: I, img2: I, threshold = 0.1) {
if (bmp1.width !== bmp2.width || bmp1.height !== bmp2.height) {
if (bmp1.width * bmp1.height > bmp2.width * bmp2.height) {
// img1 is bigger
img1 = methods.resize(clone(img1), bmp2.width, bmp2.height);
img1 = methods.resize(clone(img1), {
w: bmp2.width,
h: bmp2.height,
});
} else {
// img2 is bigger (or they are the same in area)
img2 = methods.resize(clone(img2), bmp1.width, bmp1.height);
img2 = methods.resize(clone(img2), {
w: bmp1.width,
h: bmp1.height,
});
}
}

Expand Down
33 changes: 27 additions & 6 deletions packages/jimp/src/callbacks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,57 @@ import { expect, test, describe } from "vitest";
import { makeTestImage } from "@jimp/test-utils";

import { HorizontalAlign, Jimp, VerticalAlign } from "./index.js";
import { CropOptions } from "@jimp/plugin-crop";
import { FlipOptions } from "@jimp/plugin-flip";
import { ResizeOptions, ScaleToFitOptions } from "@jimp/plugin-resize";
import { CoverOptions } from "@jimp/plugin-cover";
import { ContainOptions } from "@jimp/plugin-contain";

describe("Callbacks", () => {
const targetImg = Jimp.fromBitmap(makeTestImage("▴▸▾", "◆▪▰", "▵▹▿"));
const miniImg = Jimp.fromBitmap(makeTestImage("□▥", "▥■"));

const operations = {
crop: { args: [1, 1, 2, 1] },
crop: {
args: [{ x: 1, y: 1, w: 2, h: 1 } as CropOptions],
},
invert: { args: [] },
flip: { args: [true, false] },
flip: {
args: [{ horizontal: true, vertical: false } as FlipOptions],
},
gaussian: { args: [1] },
blur: { args: [1] },
greyscale: { args: [] },
sepia: { args: [] },
opacity: { args: [0.5] },
resize: { args: [2, 2] },
resize: { args: [{ w: 2, h: 2 } as ResizeOptions] },
scale: { args: [0.5] },
brightness: { args: [0.5] },
contrast: { args: [0.75] },
posterize: { args: [5] },
dither: { args: [] },
// background: { args: [0xffffffff] },
cover: {
args: [3, 2, HorizontalAlign.LEFT | VerticalAlign.TOP],
args: [
{
w: 3,
h: 2,
align: HorizontalAlign.LEFT | VerticalAlign.TOP,
} as CoverOptions,
],
},
contain: {
args: [3, 2, HorizontalAlign.LEFT | VerticalAlign.TOP],
args: [
{
w: 3,
h: 2,
align: HorizontalAlign.LEFT | VerticalAlign.TOP,
} as ContainOptions,
],
},
opaque: { args: [] },
fade: { args: [0.5] },
scaleToFit: { args: [3, 2] },
scaleToFit: { args: [{ w: 3, h: 2 } as ScaleToFitOptions] },
blit: { args: [{ src: miniImg }] },
composite: { args: [miniImg, 0, 0] },
};
Expand Down
4 changes: 2 additions & 2 deletions packages/jimp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import { createJimp } from "@jimp/core";
* then write it back to a file.
*
* ```ts
* import { Jimp, AutoSize } from "jimp";
* import { Jimp } from "jimp";
* import { promises as fs } from "fs";
*
* const image = await Jimp.read("test/image.png");
Expand Down Expand Up @@ -143,7 +143,7 @@ export type {
} from "@jimp/plugin-color";
export type { CircleOptions } from "@jimp/plugin-circle";
export type { AutocropOptions } from "@jimp/plugin-crop";
export { AutoSize, ResizeStrategy } from "@jimp/plugin-resize";
export { ResizeStrategy } from "@jimp/plugin-resize";
export type { ThresholdOptions } from "@jimp/plugin-threshold";
export { distance, compareHashes } from "@jimp/plugin-hash";
export type { JPEGOptions } from "@jimp/js-jpeg";
Expand Down
5 changes: 4 additions & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@
},
"main": "./dist/commonjs/index.js",
"types": "./dist/commonjs/index.d.ts",
"type": "module"
"type": "module",
"dependencies": {
"zod": "^3.22.4"
}
}
10 changes: 10 additions & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { z } from "zod";

export enum Edge {
EXTEND = 1,
WRAP = 2,
Expand Down Expand Up @@ -33,6 +35,14 @@ export interface RGBAColor {
a: number;
}

export const JimpClassSchema = z.object({
bitmap: z.object({
data: z.instanceof(Buffer),
width: z.number(),
height: z.number(),
}),
});

export interface JimpClass {
background: number;
bitmap: Bitmap;
Expand Down
17 changes: 9 additions & 8 deletions plugins/plugin-blit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,24 @@
"author": "Andrew Lisowski <[email protected]>",
"license": "MIT",
"dependencies": {
"@jimp/types": "workspace:*",
"@jimp/utils": "workspace:*",
"@jimp/types": "workspace:*"
"zod": "^3.22.4"
},
"devDependencies": {
"@jimp/js-jpeg": "workspace:*",
"@jimp/js-png": "workspace:*",
"@jimp/core": "workspace:*",
"@jimp/test-utils": "workspace:*",
"@jimp/config-eslint": "workspace:*",
"@jimp/config-typescript": "workspace:*",
"@jimp/config-vitest": "workspace:*",
"@jimp/core": "workspace:*",
"@jimp/js-jpeg": "workspace:*",
"@jimp/js-png": "workspace:*",
"@jimp/test-utils": "workspace:*",
"@vitest/browser": "^1.4.0",
"eslint": "^8.57.0",
"tshy": "^1.12.0",
"typescript": "^5.4.2",
"@vitest/browser": "^1.4.0",
"vitest": "^1.4.0",
"vite-plugin-node-polyfills": "^0.21.0"
"vite-plugin-node-polyfills": "^0.21.0",
"vitest": "^1.4.0"
},
"tshy": {
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion plugins/plugin-blit/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("Blit over image", function () {
));

test("blit on top, with no crop", () => {
expect(targetImg.clone().blit({ src: srcImg })).toMatchSnapshot();
expect(targetImg.clone().blit(srcImg)).toMatchSnapshot();
});

test("blit on middle, with no crop", () => {
Expand Down
33 changes: 20 additions & 13 deletions plugins/plugin-blit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { JimpClass } from "@jimp/types";
import { JimpClass, JimpClassSchema } from "@jimp/types";
import { limit255, scan } from "@jimp/utils";
import { z } from "zod";

export interface BlitOptions<I extends JimpClass> {
/** This image to blit on to the current image */
src: I;
const BlitOptionsSchemaComplex = z.object({
src: JimpClassSchema,
/** the x position to blit the image */
x?: number;
x: z.number().optional(),
/** the y position to blit the image */
y?: number;
y: z.number().optional(),
/** the x position from which to crop the source image */
srcX?: number;
srcX: z.number().optional(),
/** the y position from which to crop the source image */
srcY?: number;
srcY: z.number().optional(),
/** the width to which to crop the source image */
srcW?: number;
srcW: z.number().optional(),
/** the height to which to crop the source image */
srcH?: number;
}
srcH: z.number().optional(),
});

type BlitOptionsComplex = z.infer<typeof BlitOptionsSchemaComplex>;

const BlitOptionsSchema = z.union([JimpClassSchema, BlitOptionsSchemaComplex]);

export type BlitOptions = z.infer<typeof BlitOptionsSchema>;

export const methods = {
/**
Expand All @@ -34,7 +40,8 @@ export const methods = {
* image.blit(parrot, x, y);
* ```
*/
blit<I extends JimpClass>(image: I, options: BlitOptions<I>) {
blit<I extends JimpClass>(image: I, options: BlitOptions) {
const parsed = BlitOptionsSchema.parse(options);
let {
src,
x = 0,
Expand All @@ -43,7 +50,7 @@ export const methods = {
srcY = 0,
srcW = src.bitmap.width,
srcH = src.bitmap.height,
} = options;
} = "bitmap" in parsed ? ({ src: parsed } as BlitOptionsComplex) : parsed;

if (!("bitmap" in src)) {
throw new Error("The source must be a Jimp image");
Expand Down
6 changes: 3 additions & 3 deletions plugins/plugin-blur/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
"@jimp/config-eslint": "workspace:*",
"@jimp/config-typescript": "workspace:*",
"@jimp/config-vitest": "workspace:*",
"@vitest/browser": "^1.4.0",
"eslint": "^8.57.0",
"tshy": "^1.12.0",
"typescript": "^5.4.2",
"@vitest/browser": "^1.4.0",
"vitest": "^1.4.0",
"vite-plugin-node-polyfills": "^0.21.0"
"vite-plugin-node-polyfills": "^0.21.0",
"vitest": "^1.4.0"
},
"tshy": {
"exclude": [
Expand Down
11 changes: 6 additions & 5 deletions plugins/plugin-circle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@
"author": "Andrew Lisowski <[email protected]>",
"license": "MIT",
"dependencies": {
"@jimp/types": "workspace:*"
"@jimp/types": "workspace:*",
"zod": "^3.22.4"
},
"devDependencies": {
"@jimp/core": "workspace:*",
"@jimp/config-eslint": "workspace:*",
"@jimp/config-typescript": "workspace:*",
"@jimp/config-vitest": "workspace:*",
"@jimp/core": "workspace:*",
"@jimp/test-utils": "workspace:*",
"@vitest/browser": "^1.4.0",
"eslint": "^8.57.0",
"tshy": "^1.12.0",
"typescript": "^5.4.2",
"@vitest/browser": "^1.4.0",
"vitest": "^1.4.0",
"vite-plugin-node-polyfills": "^0.21.0"
"vite-plugin-node-polyfills": "^0.21.0",
"vitest": "^1.4.0"
},
"tshy": {
"exclude": [
Expand Down
24 changes: 14 additions & 10 deletions plugins/plugin-circle/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { JimpClass } from "@jimp/types";
import { z } from "zod";

export interface CircleOptions {
/** the x position to draw the image */
x?: number;
/** the y position to draw the image */
y?: number;
const CircleOptionsSchema = z.object({
/** the x position to draw the circle */
x: z.number().optional(),
/** the y position to draw the circle */
y: z.number().optional(),
/** the radius of the circle */
radius?: number;
}
radius: z.number().min(0).optional(),
});

export type CircleOptions = z.infer<typeof CircleOptionsSchema>;

export const methods = {
/**
Expand All @@ -24,15 +27,16 @@ export const methods = {
* ```
*/
circle<I extends JimpClass>(image: I, options: CircleOptions = {}) {
const parsed = CircleOptionsSchema.parse(options);
const radius =
options.radius ||
parsed.radius ||
(image.bitmap.width > image.bitmap.height
? image.bitmap.height
: image.bitmap.width) / 2;

const center = {
x: typeof options.x === "number" ? options.x : image.bitmap.width / 2,
y: typeof options.y === "number" ? options.y : image.bitmap.height / 2,
x: typeof parsed.x === "number" ? parsed.x : image.bitmap.width / 2,
y: typeof parsed.y === "number" ? parsed.y : image.bitmap.height / 2,
};

image.scan((x, y, idx) => {
Expand Down
9 changes: 5 additions & 4 deletions plugins/plugin-color/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
"@jimp/js-png": "workspace:*",
"@jimp/test-utils": "workspace:*",
"@types/tinycolor2": "^1.4.6",
"@vitest/browser": "^1.4.0",
"eslint": "^8.57.0",
"tshy": "^1.12.0",
"typescript": "^5.4.2",
"@vitest/browser": "^1.4.0",
"vitest": "^1.4.0",
"vite-plugin-node-polyfills": "^0.21.0"
"vite-plugin-node-polyfills": "^0.21.0",
"vitest": "^1.4.0"
},
"dependencies": {
"@jimp/core": "workspace:*",
"@jimp/types": "workspace:*",
"@jimp/utils": "workspace:*",
"tinycolor2": "^1.6.0"
"tinycolor2": "^1.6.0",
"zod": "^3.22.4"
},
"tshy": {
"exclude": [
Expand Down
20 changes: 16 additions & 4 deletions plugins/plugin-color/src/convolution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,24 @@ describe("Convolution", function () {
});

test("3x3 sharp matrix on EDGE_WRAP", () => {
expect(imgMid.clone().convolution(sharpM, Edge.WRAP)).toMatchSnapshot();
expect(imgTopLeft.clone().convolution(sharpM, Edge.WRAP)).toMatchSnapshot();
expect(
imgMid.clone().convolution({ kernel: sharpM, edgeHandling: Edge.WRAP })
).toMatchSnapshot();
expect(
imgTopLeft
.clone()
.convolution({ kernel: sharpM, edgeHandling: Edge.WRAP })
).toMatchSnapshot();
});

test("3x3 sharp matrix on EDGE_CROP", () => {
expect(imgMid.clone().convolution(sharpM, Edge.CROP)).toMatchSnapshot();
expect(imgTopLeft.clone().convolution(sharpM, Edge.CROP)).toMatchSnapshot();
expect(
imgMid.clone().convolution({ kernel: sharpM, edgeHandling: Edge.CROP })
).toMatchSnapshot();
expect(
imgTopLeft
.clone()
.convolution({ kernel: sharpM, edgeHandling: Edge.CROP })
).toMatchSnapshot();
});
});
Loading

0 comments on commit 8cf0f88

Please sign in to comment.