Skip to content

Commit

Permalink
crop plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hipstersmoothie committed Mar 16, 2024
1 parent 16779d6 commit 296a776
Show file tree
Hide file tree
Showing 20 changed files with 1,034 additions and 20 deletions.
134 changes: 123 additions & 11 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bitmap, Format } from "@jimp/types";
import { Bitmap, Format, JimpClass, Edge } from "@jimp/types";
import { fromBuffer } from "file-type";

const emptyBitmap: Bitmap = {
Expand Down Expand Up @@ -59,19 +59,20 @@ type JimpInstanceMethod<M, T> =
? (...args: Args) => JimpInstanceMethods<M>
: never;

type JimpInstanceMethods<T> = {
export type JimpInstanceMethods<T> = {
[K in keyof T]: JimpInstanceMethod<T, T[K]>;
};

type JimpOutputMethod<Instance, Output> = (mime: Instance) => Promise<Output>;

type JimpSupportedFormats<U> = U extends Format<infer M>[] ? M : never;

export * from "./utils/constants.js";

export class Jimp<
SupportedMimeTypes extends string = string,
Formats extends Format<SupportedMimeTypes>[] = Format<SupportedMimeTypes>[],
MethodMap extends Record<string, JimpMethod> = Record<string, JimpMethod>,
> {
> implements JimpClass
{
static plugins: JimpPlugin[] = [];
static formatPlugins: JimpFormat[] = [];
static formats: Format[] = [];
Expand Down Expand Up @@ -137,6 +138,26 @@ export class Jimp<
this.formats.push(format as any);
}
}

for (let i = 0; i < classConstructor.plugins.length; ++i) {
const plugin = classConstructor.plugins[i];

if (plugin) {
const methods = plugin(this, options);

if (methods) {
for (const key in methods) {
(this as any)[key] = (...args: any[]) => {
const result = methods[key](this, ...args);

if (result) {
this.bitmap = result.bitmap;
}
};
}
}
}
}
}

/**
Expand Down Expand Up @@ -174,12 +195,103 @@ export class Jimp<
}

/**
* Returns the original MIME of the image (default: "image/png")
* @returns {string} the MIME
* Returns the offset of a pixel in the bitmap buffer
* @param x the x coordinate
* @param y the y coordinate
* @param edgeHandling (optional) define how to sum pixels from outside the border
* @returns the index of the pixel or -1 if not found
*/
getPixelIndex(x: number, y: number, edgeHandling?: Edge) {
let xi;
let yi;

if (!edgeHandling) {
edgeHandling = Edge.EXTEND;
}

if (typeof x !== "number" || typeof y !== "number") {
throw new Error("x and y must be numbers");
}

// round input
x = Math.round(x);
y = Math.round(y);
xi = x;
yi = y;

if (edgeHandling === Edge.EXTEND) {
if (x < 0) xi = 0;
if (x >= this.bitmap.width) xi = this.bitmap.width - 1;
if (y < 0) yi = 0;
if (y >= this.bitmap.height) yi = this.bitmap.height - 1;
}

if (edgeHandling === Edge.WRAP) {
if (x < 0) {
xi = this.bitmap.width + x;
}

if (x >= this.bitmap.width) {
xi = x % this.bitmap.width;
}

if (y < 0) {
yi = this.bitmap.height + y;
}

if (y >= this.bitmap.height) {
yi = y % this.bitmap.height;
}
}

let i = (this.bitmap.width * yi + xi) << 2;

// if out of bounds index is -1
if (xi < 0 || xi >= this.bitmap.width) {
i = -1;
}

if (yi < 0 || yi >= this.bitmap.height) {
i = -1;
}

return i;
}

/**
* Returns the hex color value of a pixel
* @param x the x coordinate
* @param y the y coordinate
* @returns the color of the pixel
*/
getPixelColor(x: number, y: number) {
if (typeof x !== "number" || typeof y !== "number") {
throw new Error("x and y must be numbers");
}

const idx = this.getPixelIndex(x, y);
return this.bitmap.data.readUInt32BE(idx);
}

/**
* Returns the hex colour value of a pixel
* @param hex color to set
* @param x the x coordinate
* @param y the y coordinate
* @returns the index of the pixel or -1 if not found
*/
// getMIME() {
// const mime = this._originalMime || Jimp.MIME_PNG;
setPixelColor(hex: number, x: number, y: number) {
if (
typeof hex !== "number" ||
typeof x !== "number" ||
typeof y !== "number"
) {
throw new Error("hex, x and y must be numbers");
}

// return mime;
// }
const idx = this.getPixelIndex(x, y);
this.bitmap.data.writeUInt32BE(hex, idx);

return this;
}
}
24 changes: 24 additions & 0 deletions packages/core/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// used to auto resizing etc.
export const AUTO = -1;

// Align modes for cover, contain, bit masks
export const HORIZONTAL_ALIGN_LEFT = 1;
export const HORIZONTAL_ALIGN_CENTER = 2;
export const HORIZONTAL_ALIGN_RIGHT = 4;

export const VERTICAL_ALIGN_TOP = 8;
export const VERTICAL_ALIGN_MIDDLE = 16;
export const VERTICAL_ALIGN_BOTTOM = 32;

// blend modes
export const BLEND_SOURCE_OVER = "srcOver";
export const BLEND_DESTINATION_OVER = "dstOver";
export const BLEND_MULTIPLY = "multiply";
export const BLEND_ADD = "add";
export const BLEND_SCREEN = "screen";
export const BLEND_OVERLAY = "overlay";
export const BLEND_DARKEN = "darken";
export const BLEND_LIGHTEN = "lighten";
export const BLEND_HARDLIGHT = "hardLight";
export const BLEND_DIFFERENCE = "difference";
export const BLEND_EXCLUSION = "exclusion";
1 change: 1 addition & 0 deletions packages/jimp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"author": "Andrew Lisowski <lisowski54@gmail.com>",
"license": "MIT",
"dependencies": {
"@jimp/plugin-crop": "workspace:*",
"@jimp/js-png": "workspace:*",
"@jimp/core": "workspace:*"
},
Expand Down
11 changes: 7 additions & 4 deletions packages/jimp/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { expect, test } from "vitest";
// import { expect, test } from "vitest";
import { promises as fs } from "fs";
import path from "path";

import { Jimp } from "./index.js";

test("adds 1 + 2 to equal 3", () => {
expect(1 + 2).toBe(3);
});
// test("adds 1 + 2 to equal 3", () => {
// expect(1 + 2).toBe(3);
// });

async function run() {
const image = new Jimp();
Expand All @@ -16,10 +16,13 @@ async function run() {

await image.fromBuffer(imageBuffer);

image.crop(100, 100, 150, 100);

const outputBuffer = await image.toBuffer("image/png");
const outPath = path.join(__dirname, "./out.png");

await fs.writeFile(outPath, outputBuffer);
console.log(outPath);
}

run();
5 changes: 4 additions & 1 deletion packages/jimp/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Jimp as JimpCustom } from "@jimp/core";

import crop from "@jimp/plugin-crop";

import png from "@jimp/js-png";

export const Jimp = JimpCustom.addFormat(png);
export const Jimp = JimpCustom.addFormat(png).plugin(crop);
21 changes: 21 additions & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
export enum Edge {
EXTEND = 1,
WRAP = 2,
CROP = 3,
}

export interface Bitmap {
data: Buffer;
width: number;
Expand All @@ -9,3 +15,18 @@ export interface Format<T extends string = string> {
encode: (image: Bitmap) => Promise<Buffer>;
decode: (data: Buffer) => Promise<Bitmap>;
}

export interface RGBAColor {
r: number;
g: number;
b: number;
a: number;
}

export interface JimpClass {
bitmap: Bitmap;

getPixelIndex: (x: number, y: number, edgeHandling?: Edge) => number;
getPixelColor: (x: number, y: number) => number;
setPixelColor: (hex: number, x: number, y: number) => JimpClass;
}
46 changes: 46 additions & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@jimp/utils",
"version": "1.0.0",
"repository": "jimp-dev/jimp",
"scripts": {
"lint": "eslint .",
"test": "vitest",
"build": "tshy",
"dev": "tshy --watch"
},
"author": "Andrew Lisowski <lisowski54@gmail.com>",
"license": "MIT",
"dependencies": {
"@jimp/types": "workspace:*"
},
"devDependencies": {
"@jimp/config-eslint": "workspace:*",
"@jimp/config-typescript": "workspace:*",
"eslint": "^8.57.0",
"tshy": "^1.12.0",
"typescript": "^5.4.2",
"vitest": "^1.4.0"
},
"tshy": {
"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"
}
5 changes: 5 additions & 0 deletions packages/utils/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect, test } from "vitest";

test("adds 1 + 2 to equal 3", () => {
expect(1 + 2).toBe(3);
});
Loading

0 comments on commit 296a776

Please sign in to comment.