@sealpixel/plugin-crop 1.0.0-rc.0

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/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @sealpixel/plugin-crop
2
+
3
+ Crop, rotate and flip operations for the Sealpixel image editor. Part of the Sealpixel image editor.
@@ -0,0 +1,104 @@
1
+ import type { Color, OperationBase, Rect } from '@sealpixel/core';
2
+ import { z } from 'zod';
3
+ export interface CropDoc {
4
+ /** Radians, clockwise positive. */
5
+ rotation: number;
6
+ flipX: boolean;
7
+ flipY: boolean;
8
+ /** In rotated-bounding-box space, 0..1. */
9
+ rect: Rect;
10
+ /** Width / height the UI enforces, or null for free. Not used by the renderer. */
11
+ aspect: number | null;
12
+ /** Alpha mask on the output: `circle` keeps the inscribed ellipse, for round avatars. */
13
+ mask: CropMask;
14
+ }
15
+ export type CropMask = 'none' | 'circle';
16
+ /** Merge-sets any subset of the crop state. */
17
+ export interface CropSetOp extends OperationBase<'crop.set'> {
18
+ rotation?: number | undefined;
19
+ flipX?: boolean | undefined;
20
+ flipY?: boolean | undefined;
21
+ rect?: Rect | undefined;
22
+ aspect?: number | null | undefined;
23
+ mask?: CropMask | undefined;
24
+ }
25
+ /** Restores the identity crop. */
26
+ export type CropResetOp = OperationBase<'crop.reset'>;
27
+ declare module '@sealpixel/core' {
28
+ interface OperationRegistry {
29
+ 'crop.set': CropSetOp;
30
+ 'crop.reset': CropResetOp;
31
+ }
32
+ interface DocumentRegistry {
33
+ crop: CropDoc;
34
+ }
35
+ }
36
+ export declare const IDENTITY_CROP: CropDoc;
37
+ export declare const RectSchema: z.ZodObject<{
38
+ x: z.ZodNumber;
39
+ y: z.ZodNumber;
40
+ width: z.ZodNumber;
41
+ height: z.ZodNumber;
42
+ }, z.core.$strict>;
43
+ export declare const cropSet: import("@sealpixel/core").OperationDef<CropDoc, CropSetOp>;
44
+ export declare const cropReset: import("@sealpixel/core").OperationDef<CropDoc, CropResetOp>;
45
+ export declare function isIdentityCrop(doc: CropDoc): boolean;
46
+ export interface CropAspectOption {
47
+ /** Shown in the aspect menu; a plain ratio such as `16:9` needs no translation. */
48
+ label: string;
49
+ /** width / height, or null for a free rectangle. */
50
+ value: number | null;
51
+ }
52
+ export interface CropOptions {
53
+ /** Aspect presets in menu order. */
54
+ aspects: CropAspectOption[];
55
+ /** Aspect applied on load, or null for free. Must be one of `aspects`. */
56
+ defaultAspect: number | null;
57
+ /** Enforce rotation, flip, aspect and minSize constraints in logs (client and server). Off, options only shape the UI. */
58
+ enforce: boolean;
59
+ /** Allow rotation (slider and 90° buttons). */
60
+ rotation: boolean;
61
+ /** Allow horizontal and vertical flips. */
62
+ flip: boolean;
63
+ /** Step of the rotation slider in degrees. */
64
+ rotationStep: number;
65
+ /** Smallest crop in source pixels; null for no minimum. */
66
+ minSize: {
67
+ width: number;
68
+ height: number;
69
+ } | null;
70
+ /**
71
+ * `circle` turns the crop into a round avatar: the aspect is fixed to 1, the
72
+ * gizmo shows a round mask and the export keeps only the inscribed circle
73
+ * (transparent outside; JPEG flattens onto the background colour).
74
+ */
75
+ shape: 'rect' | 'circle';
76
+ /** Offer the "Reset crop" button. Off (with `enforce`), `crop.reset` is rejected too. */
77
+ reset: boolean;
78
+ }
79
+ export declare const CropOptionsSchema: z.ZodObject<{
80
+ aspects: z.ZodArray<z.ZodObject<{
81
+ label: z.ZodString;
82
+ value: z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<-1>]>>;
83
+ }, z.core.$strict>>;
84
+ defaultAspect: z.ZodNullable<z.ZodNumber>;
85
+ enforce: z.ZodBoolean;
86
+ rotation: z.ZodBoolean;
87
+ flip: z.ZodBoolean;
88
+ rotationStep: z.ZodNumber;
89
+ minSize: z.ZodNullable<z.ZodObject<{
90
+ width: z.ZodNumber;
91
+ height: z.ZodNumber;
92
+ }, z.core.$strict>>;
93
+ shape: z.ZodEnum<{
94
+ circle: "circle";
95
+ rect: "rect";
96
+ }>;
97
+ reset: z.ZodBoolean;
98
+ }, z.core.$strict>;
99
+ export declare const CROP_DEFAULT_OPTIONS: CropOptions;
100
+ /** `value: -1` is the marker for "the source's own ratio"; the tool resolves it per image. */
101
+ export declare const ORIGINAL_ASPECT = -1;
102
+ export declare const cropPlugin: import("@sealpixel/plugin-sdk").ConfigurablePlugin<"crop", CropDoc, CropOptions>;
103
+ export type { Color };
104
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,OAAO;IACtB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,2CAA2C;IAC3C,IAAI,EAAE,IAAI,CAAC;IACX,kFAAkF;IAClF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,yFAAyF;IACzF,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzC,+CAA+C;AAC/C,MAAM,WAAW,SAAU,SAAQ,aAAa,CAAC,UAAU,CAAC;IAC1D,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,kCAAkC;AAClC,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;AAEtD,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,iBAAiB;QACzB,UAAU,EAAE,SAAS,CAAC;QACtB,YAAY,EAAE,WAAW,CAAC;KAC3B;IACD,UAAU,gBAAgB;QACxB,IAAI,EAAE,OAAO,CAAC;KACf;CACF;AAED,eAAO,MAAM,aAAa,EAAE,OAO3B,CAAC;AAGF,eAAO,MAAM,UAAU;;;;;kBAGyE,CAAC;AAIjG,eAAO,MAAM,OAAO,4DAsBlB,CAAC;AAEH,eAAO,MAAM,SAAS,8DAIpB,CAAC;AAEH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAYpD;AAED,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,0EAA0E;IAC1E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0HAA0H;IAC1H,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,yFAAyF;IACzF,KAAK,EAAE,OAAO,CAAC;CAChB;AAKD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;kBAmB3B,CAAC;AAEJ,eAAO,MAAM,oBAAoB,EAAE,WAiBlC,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,eAAe,KAAK,CAAC;AAOlC,eAAO,MAAM,UAAU,kFAgFrB,CAAC;AAEH,YAAY,EAAE,KAAK,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,182 @@
1
+ import { defineOperation, definePlugin } from '@sealpixel/plugin-sdk';
2
+ import { z } from 'zod';
3
+ export const IDENTITY_CROP = {
4
+ rotation: 0,
5
+ flipX: false,
6
+ flipY: false,
7
+ rect: { x: 0, y: 0, width: 1, height: 1 },
8
+ aspect: null,
9
+ mask: 'none',
10
+ };
11
+ const unit = z.number().min(0).max(1);
12
+ export const RectSchema = z
13
+ .object({ x: unit, y: unit, width: z.number().gt(0).max(1), height: z.number().gt(0).max(1) })
14
+ .strict()
15
+ .refine((r) => r.x + r.width <= 1 + 1e-9 && r.y + r.height <= 1 + 1e-9, 'rect exceeds bounds');
16
+ const base = { id: z.string().min(1), at: z.number().optional() };
17
+ export const cropSet = defineOperation({
18
+ type: 'crop.set',
19
+ schema: z
20
+ .object({
21
+ type: z.literal('crop.set'),
22
+ ...base,
23
+ rotation: z.number().finite().optional(),
24
+ mask: z.enum(['none', 'circle']).optional(),
25
+ flipX: z.boolean().optional(),
26
+ flipY: z.boolean().optional(),
27
+ rect: RectSchema.optional(),
28
+ aspect: z.number().positive().nullable().optional(),
29
+ })
30
+ .strict(),
31
+ reduce: (slice, op) => ({
32
+ rotation: op.rotation ?? slice.rotation,
33
+ flipX: op.flipX ?? slice.flipX,
34
+ flipY: op.flipY ?? slice.flipY,
35
+ rect: op.rect ?? slice.rect,
36
+ aspect: op.aspect === undefined ? slice.aspect : op.aspect,
37
+ mask: op.mask ?? slice.mask ?? 'none',
38
+ }),
39
+ });
40
+ export const cropReset = defineOperation({
41
+ type: 'crop.reset',
42
+ schema: z.object({ type: z.literal('crop.reset'), ...base }).strict(),
43
+ reduce: () => IDENTITY_CROP,
44
+ });
45
+ export function isIdentityCrop(doc) {
46
+ const r = doc.rect;
47
+ return (doc.rotation === 0 &&
48
+ !doc.flipX &&
49
+ !doc.flipY &&
50
+ r.x === 0 &&
51
+ r.y === 0 &&
52
+ doc.mask === 'none' &&
53
+ r.width === 1 &&
54
+ r.height === 1);
55
+ }
56
+ const ratio = z.number().positive().finite();
57
+ /** A positive ratio, null for free, or -1 for the source's own ratio. */
58
+ const aspectValue = z.union([ratio, z.literal(-1)]).nullable();
59
+ export const CropOptionsSchema = z
60
+ .object({
61
+ aspects: z.array(z.object({ label: z.string().min(1), value: aspectValue }).strict()).min(1),
62
+ defaultAspect: ratio.nullable(),
63
+ enforce: z.boolean(),
64
+ rotation: z.boolean(),
65
+ flip: z.boolean(),
66
+ rotationStep: z.number().positive().max(90),
67
+ minSize: z
68
+ .object({ width: z.number().int().positive(), height: z.number().int().positive() })
69
+ .strict()
70
+ .nullable(),
71
+ shape: z.enum(['rect', 'circle']),
72
+ reset: z.boolean(),
73
+ })
74
+ .strict()
75
+ .refine((o) => o.defaultAspect === null || o.aspects.some((a) => sameRatio(a.value, o.defaultAspect)), 'defaultAspect must be one of aspects');
76
+ export const CROP_DEFAULT_OPTIONS = {
77
+ aspects: [
78
+ { label: 'crop.aspect.free', value: null },
79
+ { label: 'crop.aspect.original', value: -1 },
80
+ { label: 'crop.aspect.square', value: 1 },
81
+ { label: '16:9', value: 16 / 9 },
82
+ { label: '4:3', value: 4 / 3 },
83
+ { label: '3:2', value: 3 / 2 },
84
+ ],
85
+ defaultAspect: null,
86
+ enforce: false,
87
+ rotation: true,
88
+ flip: true,
89
+ rotationStep: 0.5,
90
+ minSize: null,
91
+ shape: 'rect',
92
+ reset: true,
93
+ };
94
+ /** `value: -1` is the marker for "the source's own ratio"; the tool resolves it per image. */
95
+ export const ORIGINAL_ASPECT = -1;
96
+ function sameRatio(a, b) {
97
+ if (a === null || b === null)
98
+ return a === b;
99
+ return Math.abs(a - b) < 1e-6;
100
+ }
101
+ export const cropPlugin = definePlugin({
102
+ id: 'crop',
103
+ version: 1,
104
+ operations: [cropSet, cropReset],
105
+ initialDocument: IDENTITY_CROP,
106
+ stage: { name: 'crop', order: 400 },
107
+ toPlan: (doc) => isIdentityCrop(doc)
108
+ ? null
109
+ : {
110
+ rotation: doc.rotation,
111
+ flipX: doc.flipX,
112
+ flipY: doc.flipY,
113
+ rect: doc.rect,
114
+ // Omitted when none so existing plans and their goldens stay byte-identical.
115
+ ...(doc.mask === 'circle' ? { mask: 'circle' } : {}),
116
+ },
117
+ kernel: { kind: 'core' },
118
+ options: {
119
+ schema: CropOptionsSchema,
120
+ defaults: CROP_DEFAULT_OPTIONS,
121
+ describe: {
122
+ aspects: 'Aspect presets in menu order; value null = free, -1 = the source ratio.',
123
+ defaultAspect: 'Aspect applied on load, or null.',
124
+ enforce: 'Enforce rotation, flip, aspect and minSize constraints in logs.',
125
+ rotation: 'Allow rotation.',
126
+ flip: 'Allow flips.',
127
+ rotationStep: 'Rotation slider step in degrees.',
128
+ minSize: 'Smallest crop in source pixels, or null.',
129
+ shape: 'rect, or circle for a round avatar (square aspect, round mask, transparent outside).',
130
+ reset: 'Offer the Reset crop button; off with enforce, crop.reset is rejected.',
131
+ },
132
+ },
133
+ initialOps: ({ options }) => {
134
+ if (options.shape === 'circle') {
135
+ return [{ type: 'crop.set', aspect: 1, mask: 'circle' }];
136
+ }
137
+ return options.defaultAspect === null
138
+ ? []
139
+ : [{ type: 'crop.set', aspect: options.defaultAspect }];
140
+ },
141
+ validate: (op, { options, slice, source }) => {
142
+ if (!options.enforce)
143
+ return null;
144
+ if (op.type === 'crop.reset') {
145
+ if (!options.reset)
146
+ return 'resetting the crop is disabled';
147
+ if (options.shape === 'circle')
148
+ return 'the crop is a circle; reset would drop the round mask';
149
+ return null;
150
+ }
151
+ if (op.type !== 'crop.set')
152
+ return null;
153
+ const o = op;
154
+ if (!options.rotation && o.rotation !== undefined && Math.abs(o.rotation) > 1e-9)
155
+ return 'rotation is disabled';
156
+ if (!options.flip && (o.flipX === true || o.flipY === true))
157
+ return 'flipping is disabled';
158
+ if (options.shape === 'circle') {
159
+ if (o.mask === 'none')
160
+ return 'the crop is a circle';
161
+ if (o.aspect !== undefined && o.aspect !== 1)
162
+ return 'a circle crop is square';
163
+ }
164
+ if (o.aspect !== undefined && o.aspect !== null) {
165
+ const aspect = o.aspect;
166
+ const original = source.width / source.height;
167
+ const ok = options.aspects.some((a) => a.value === ORIGINAL_ASPECT ? sameRatio(original, aspect) : sameRatio(a.value, aspect));
168
+ if (!ok)
169
+ return 'aspect ratio is not offered by this editor';
170
+ }
171
+ if (options.minSize && o.rect) {
172
+ const rotation = o.rotation ?? slice.rotation;
173
+ const bw = source.width * Math.abs(Math.cos(rotation)) + source.height * Math.abs(Math.sin(rotation));
174
+ const bh = source.width * Math.abs(Math.sin(rotation)) + source.height * Math.abs(Math.cos(rotation));
175
+ if (o.rect.width * bw + 0.5 < options.minSize.width ||
176
+ o.rect.height * bh + 0.5 < options.minSize.height)
177
+ return `crop is smaller than ${options.minSize.width}×${options.minSize.height} px`;
178
+ }
179
+ return null;
180
+ },
181
+ });
182
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@sealpixel/plugin-crop",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Crop, rotate and flip operations for the Sealpixel image editor.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/plugins/crop"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "sideEffects": false,
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "sealpixel-plugin"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.build.json",
31
+ "typecheck": "tsc -p tsconfig.json --noEmit",
32
+ "test": "vitest run"
33
+ },
34
+ "dependencies": {
35
+ "@sealpixel/plugin-sdk": "workspace:*"
36
+ },
37
+ "peerDependencies": {
38
+ "@sealpixel/core": "workspace:*",
39
+ "zod": "^4.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@sealpixel/config": "workspace:*",
43
+ "@sealpixel/core": "workspace:*",
44
+ "@types/node": "^24.0.0",
45
+ "typescript": "^5.9.0",
46
+ "vitest": "^4.0.0",
47
+ "zod": "^4.0.0"
48
+ }
49
+ }