image-edit-tools 1.0.5 → 1.0.8

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/index.d.ts +5 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +5 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp/tools.d.ts.map +1 -1
  7. package/dist/mcp/tools.js +90 -0
  8. package/dist/mcp/tools.js.map +1 -1
  9. package/dist/ops/add-text.d.ts +28 -0
  10. package/dist/ops/add-text.d.ts.map +1 -1
  11. package/dist/ops/add-text.js +255 -40
  12. package/dist/ops/add-text.js.map +1 -1
  13. package/dist/ops/clip-to-shape.d.ts +3 -0
  14. package/dist/ops/clip-to-shape.d.ts.map +1 -0
  15. package/dist/ops/clip-to-shape.js +58 -0
  16. package/dist/ops/clip-to-shape.js.map +1 -0
  17. package/dist/ops/draw-shape.d.ts +3 -0
  18. package/dist/ops/draw-shape.d.ts.map +1 -0
  19. package/dist/ops/draw-shape.js +54 -0
  20. package/dist/ops/draw-shape.js.map +1 -0
  21. package/dist/ops/drop-shadow.d.ts +3 -0
  22. package/dist/ops/drop-shadow.d.ts.map +1 -0
  23. package/dist/ops/drop-shadow.js +54 -0
  24. package/dist/ops/drop-shadow.js.map +1 -0
  25. package/dist/ops/gradient-overlay.d.ts +3 -0
  26. package/dist/ops/gradient-overlay.d.ts.map +1 -0
  27. package/dist/ops/gradient-overlay.js +49 -0
  28. package/dist/ops/gradient-overlay.js.map +1 -0
  29. package/dist/ops/pipeline.d.ts.map +1 -1
  30. package/dist/ops/pipeline.js +16 -0
  31. package/dist/ops/pipeline.js.map +1 -1
  32. package/dist/ops/rotate.d.ts +3 -0
  33. package/dist/ops/rotate.d.ts.map +1 -0
  34. package/dist/ops/rotate.js +25 -0
  35. package/dist/ops/rotate.js.map +1 -0
  36. package/dist/types.d.ts +123 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/utils/font-loader.d.ts +26 -0
  39. package/dist/utils/font-loader.d.ts.map +1 -0
  40. package/dist/utils/font-loader.js +103 -0
  41. package/dist/utils/font-loader.js.map +1 -0
  42. package/package.json +1 -1
  43. package/src/index.ts +5 -0
  44. package/src/mcp/tools.ts +86 -0
  45. package/src/ops/add-text.ts +283 -45
  46. package/src/ops/clip-to-shape.ts +63 -0
  47. package/src/ops/draw-shape.ts +58 -0
  48. package/src/ops/drop-shadow.ts +60 -0
  49. package/src/ops/gradient-overlay.ts +62 -0
  50. package/src/ops/pipeline.ts +9 -0
  51. package/src/ops/rotate.ts +27 -0
  52. package/src/types.ts +131 -1
  53. package/src/utils/font-loader.ts +119 -0
  54. package/tests/integration/font-url.test.ts +62 -0
  55. package/tests/unit/add-text.test.ts +110 -0
  56. package/tests/unit/clip-to-shape.test.ts +36 -0
  57. package/tests/unit/draw-shape.test.ts +34 -0
  58. package/tests/unit/drop-shadow.test.ts +42 -0
  59. package/tests/unit/font-loader.test.ts +39 -0
  60. package/tests/unit/gradient-overlay.test.ts +29 -0
  61. package/tests/unit/rotate.test.ts +42 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ ## [1.0.7] - 2026-03-14
4
+
5
+ ### Added
6
+
7
+ - **Inline Spans** (`TextLayer.spans`): Render mixed-style text within a single layer.
8
+ Each span supports `bold`, `italic`, `color`, `fontSize`, and `highlight` overrides.
9
+ Line breaks via `\n` within span text are fully supported.
10
+ - **fontUrl auto-fetch & cache**: When `fontUrl` starts with `https://`, the font binary
11
+ is automatically downloaded and cached in `os.tmpdir()`. Google Fonts CSS URLs
12
+ (`fonts.googleapis.com/css*`) are parsed to extract the actual font binary URL.
13
+ - `TextSpan` interface exported from `types.ts`.
14
+
15
+ ### Changed
16
+
17
+ - Font injection switched from `@import url()` to `@font-face { src: url() }` for
18
+ better librsvg compatibility with local files.
19
+
20
+ ### Fixed
21
+
22
+ - `fontUrl: 'https://...'` now works correctly (previously failed due to librsvg
23
+ blocking external network requests).
package/dist/index.d.ts CHANGED
@@ -21,4 +21,9 @@ export { detectFaces } from './ops/detect-faces.js';
21
21
  export { extractText } from './ops/extract-text.js';
22
22
  export { pipeline } from './ops/pipeline.js';
23
23
  export { batch } from './ops/batch.js';
24
+ export { rotate } from './ops/rotate.js';
25
+ export { gradientOverlay } from './ops/gradient-overlay.js';
26
+ export { clipToShape } from './ops/clip-to-shape.js';
27
+ export { drawShape } from './ops/draw-shape.js';
28
+ export { dropShadow } from './ops/drop-shadow.js';
24
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -21,4 +21,9 @@ export { detectFaces } from './ops/detect-faces.js';
21
21
  export { extractText } from './ops/extract-text.js';
22
22
  export { pipeline } from './ops/pipeline.js';
23
23
  export { batch } from './ops/batch.js';
24
+ export { rotate } from './ops/rotate.js';
25
+ export { gradientOverlay } from './ops/gradient-overlay.js';
26
+ export { clipToShape } from './ops/clip-to-shape.js';
27
+ export { drawShape } from './ops/draw-shape.js';
28
+ export { dropShadow } from './ops/drop-shadow.js';
24
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI1D,eAAO,MAAM,QAAQ,EAAE,IAAI,EA0N1B,CAAC;AAEF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAmDzF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI1D,eAAO,MAAM,QAAQ,EAAE,IAAI,EAoS1B,CAAC;AAEF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DzF"}
package/dist/mcp/tools.js CHANGED
@@ -216,6 +216,80 @@ export const allTools = [
216
216
  },
217
217
  required: ['images', 'operation', 'options']
218
218
  }
219
+ },
220
+ {
221
+ name: 'image_rotate',
222
+ description: 'Rotates an image by an arbitrary angle. Exposed areas are transparent by default.',
223
+ inputSchema: {
224
+ type: 'object',
225
+ properties: {
226
+ image: { type: 'string' },
227
+ angle: { type: 'number', description: 'Rotation angle in degrees (0-360), clockwise' },
228
+ background: { type: 'string', description: 'Background color for exposed areas. Default: transparent' }
229
+ },
230
+ required: ['image', 'angle']
231
+ }
232
+ },
233
+ {
234
+ name: 'image_gradient_overlay',
235
+ description: 'Applies a gradient overlay for text readability. Great for placing text over photos.',
236
+ inputSchema: {
237
+ type: 'object',
238
+ properties: {
239
+ image: { type: 'string' },
240
+ direction: { type: 'string', enum: ['top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'] },
241
+ color: { type: 'string', description: 'Gradient color. Default: #000000' },
242
+ opacity: { type: 'number', description: '0-1. Default: 0.7' },
243
+ coverage: { type: 'number', description: '0-1 how much of image is covered. Default: 0.5' }
244
+ },
245
+ required: ['image']
246
+ }
247
+ },
248
+ {
249
+ name: 'image_clip_to_shape',
250
+ description: 'Clips an image to a shape: circle, ellipse, or rounded-rect. Perfect for profile photos.',
251
+ inputSchema: {
252
+ type: 'object',
253
+ properties: {
254
+ image: { type: 'string' },
255
+ shape: { type: 'string', enum: ['circle', 'ellipse', 'rounded-rect'] },
256
+ borderRadius: { type: 'number', description: 'For rounded-rect. Default: 32' }
257
+ },
258
+ required: ['image', 'shape']
259
+ }
260
+ },
261
+ {
262
+ name: 'image_draw_shape',
263
+ description: 'Creates a new image containing a shape (rect, circle, ellipse, line). Use with composite to layer.',
264
+ inputSchema: {
265
+ type: 'object',
266
+ properties: {
267
+ width: { type: 'number' }, height: { type: 'number' },
268
+ shape: { type: 'string', enum: ['rect', 'circle', 'ellipse', 'line'] },
269
+ fill: { type: 'string' }, fillOpacity: { type: 'number' },
270
+ stroke: { type: 'string' }, strokeWidth: { type: 'number' },
271
+ borderRadius: { type: 'number' },
272
+ cx: { type: 'number' }, cy: { type: 'number' }, r: { type: 'number' }, ry: { type: 'number' },
273
+ x1: { type: 'number' }, y1: { type: 'number' }, x2: { type: 'number' }, y2: { type: 'number' }
274
+ },
275
+ required: ['width', 'height', 'shape']
276
+ }
277
+ },
278
+ {
279
+ name: 'image_drop_shadow',
280
+ description: 'Adds a drop shadow behind the image. Expands canvas to fit shadow.',
281
+ inputSchema: {
282
+ type: 'object',
283
+ properties: {
284
+ image: { type: 'string' },
285
+ color: { type: 'string', description: 'Shadow color. Default: rgba(0,0,0,0.5)' },
286
+ offsetX: { type: 'number', description: 'Default: 4' },
287
+ offsetY: { type: 'number', description: 'Default: 4' },
288
+ blur: { type: 'number', description: 'Blur radius. Default: 8' },
289
+ expand: { type: 'boolean', description: 'Expand canvas. Default: true' }
290
+ },
291
+ required: ['image']
292
+ }
219
293
  }
220
294
  ];
221
295
  export async function handleTool(name, args) {
@@ -269,6 +343,22 @@ export async function handleTool(name, args) {
269
343
  const txt = await api.extractText(image, args);
270
344
  return JSON.stringify(txt);
271
345
  }
346
+ else if (name === 'image_rotate')
347
+ result = await api.rotate(image, args);
348
+ else if (name === 'image_gradient_overlay')
349
+ result = await api.gradientOverlay(image, args);
350
+ else if (name === 'image_clip_to_shape')
351
+ result = await api.clipToShape(image, args);
352
+ else if (name === 'image_draw_shape') {
353
+ result = await api.drawShape(args);
354
+ if (result && result.ok && Buffer.isBuffer(result.data)) {
355
+ const b64 = result.data.toString('base64');
356
+ return JSON.stringify({ ok: true, data: `data:image/png;base64,${b64}` });
357
+ }
358
+ return JSON.stringify(result);
359
+ }
360
+ else if (name === 'image_drop_shadow')
361
+ result = await api.dropShadow(image, args);
272
362
  else {
273
363
  return JSON.stringify({ error: `Tool ${name} not implemented`, code: 'INVALID_INPUT' });
274
364
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,32 @@
1
1
  import { TextLayer, ImageInput, ImageResult } from '../types.js';
2
+ /**
3
+ * Adds text layers onto an image using SVG overlay compositing.
4
+ *
5
+ * Supports two rendering modes:
6
+ * 1. **Plain text** — uses `layer.text` with optional `maxWidth` wrapping
7
+ * 2. **Inline spans** — uses `layer.spans[]` for mixed-style rendering
8
+ *
9
+ * Font loading: if `layer.fontUrl` starts with `https://`, the font is
10
+ * automatically downloaded and cached locally for librsvg compatibility.
11
+ *
12
+ * @param input - Source image (Buffer, URL, data-URI, or file path)
13
+ * @param options - Object containing `layers` array of `TextLayer`
14
+ * @returns ImageResult with the composited image buffer
15
+ *
16
+ * @example
17
+ * // Plain text
18
+ * await addText(buffer, { layers: [{ text: 'Hello', x: 10, y: 50 }] });
19
+ *
20
+ * @example
21
+ * // Inline spans
22
+ * await addText(buffer, { layers: [{
23
+ * x: 10, y: 50, fontSize: 28, color: '#333',
24
+ * spans: [
25
+ * { text: 'normal ' },
26
+ * { text: 'bold', bold: true, color: '#000' },
27
+ * ]
28
+ * }] });
29
+ */
2
30
  export declare function addText(input: ImageInput, options: {
3
31
  layers: TextLayer[];
4
32
  }): Promise<ImageResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"add-text.d.ts","sourceRoot":"","sources":["../../src/ops/add-text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAyB,MAAM,aAAa,CAAC;AA2DxF,wBAAsB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CA4HvG"}
1
+ {"version":3,"file":"add-text.d.ts","sourceRoot":"","sources":["../../src/ops/add-text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAY,UAAU,EAAE,WAAW,EAAyB,MAAM,aAAa,CAAC;AA2KlG;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CA8NvG"}
@@ -3,6 +3,16 @@ import { ErrorCode } from '../types.js';
3
3
  import { loadImage } from '../utils/load-image.js';
4
4
  import { err, ok } from '../utils/result.js';
5
5
  import { getImageMetadata } from '../utils/validate.js';
6
+ import { resolveFontUrl } from '../utils/font-loader.js';
7
+ /**
8
+ * Wraps text into lines that fit within a maximum pixel width.
9
+ * Uses a character-width approximation of `fontSize * 0.6`.
10
+ *
11
+ * @param text - The text to wrap
12
+ * @param fontSize - Font size in pixels
13
+ * @param maxWidth - Maximum line width in pixels (optional)
14
+ * @returns Array of text lines
15
+ */
6
16
  function wrapText(text, fontSize, maxWidth) {
7
17
  if (!maxWidth)
8
18
  return [text];
@@ -25,6 +35,12 @@ function wrapText(text, fontSize, maxWidth) {
25
35
  lines.push(currentLine);
26
36
  return lines;
27
37
  }
38
+ /**
39
+ * Escapes special XML characters to prevent SVG injection.
40
+ *
41
+ * @param text - Raw text to escape
42
+ * @returns XML-safe string
43
+ */
28
44
  function escapeXml(text) {
29
45
  return text
30
46
  .replace(/&/g, '&amp;')
@@ -33,15 +49,19 @@ function escapeXml(text) {
33
49
  .replace(/"/g, '&quot;')
34
50
  .replace(/'/g, '&apos;');
35
51
  }
52
+ /**
53
+ * Computes SVG text-anchor and y-offset based on the anchor setting.
54
+ * librsvg only reliably supports `dominant-baseline: auto` (alphabetic),
55
+ * so vertical alignment is achieved via manual y-offset.
56
+ *
57
+ * @param anchor - The text anchor position
58
+ * @param fontSize - Font size for offset calculation
59
+ * @returns Object with `textAnchor` SVG attribute and `yOffset` pixel shift
60
+ */
36
61
  function getAnchorProps(anchor = 'top-left', fontSize = 24) {
37
62
  const parts = anchor.split('-');
38
63
  const yAlign = parts.length === 2 ? parts[0] : parts[0] === 'center' ? 'middle' : parts[0];
39
64
  const xAlign = parts.length === 2 ? parts[1] : parts[0] === 'center' ? 'center' : 'left';
40
- // librsvg does NOT reliably support dominant-baseline values other than 'auto' (alphabetic).
41
- // Instead of relying on dominant-baseline, we compute a y-offset to position text correctly.
42
- // With 'auto' (alphabetic baseline), y = text baseline (bottom of caps).
43
- // To make y = text top, we shift down by ~0.8 * fontSize.
44
- // To make y = text middle, we shift down by ~0.35 * fontSize.
45
65
  let yOffset = 0;
46
66
  if (yAlign === 'top') {
47
67
  yOffset = Math.round(fontSize * 0.8);
@@ -49,7 +69,6 @@ function getAnchorProps(anchor = 'top-left', fontSize = 24) {
49
69
  else if (yAlign === 'middle' || yAlign === 'center') {
50
70
  yOffset = Math.round(fontSize * 0.35);
51
71
  }
52
- // 'bottom' / 'auto' → yOffset = 0 (alphabetic baseline is already at y)
53
72
  let textAnchor = 'start';
54
73
  if (xAlign === 'center')
55
74
  textAnchor = 'middle';
@@ -57,6 +76,117 @@ function getAnchorProps(anchor = 'top-left', fontSize = 24) {
57
76
  textAnchor = 'end';
58
77
  return { textAnchor, yOffset };
59
78
  }
79
+ /**
80
+ * Builds SVG `<tspan>` elements from an array of inline spans.
81
+ * Handles style inheritance, `\n` line breaks, and highlight rects.
82
+ *
83
+ * @param spans - Array of TextSpan objects
84
+ * @param layer - Parent TextLayer for default values
85
+ * @param renderY - The computed y position for the text element
86
+ * @returns Object containing `tspanSvg`, `highlightSvg`, and `approxMaxWidth`
87
+ */
88
+ function buildSpansSvg(spans, layer, renderY) {
89
+ const baseFontSize = layer.fontSize ?? 24;
90
+ const baseColor = layer.color ?? '#000000';
91
+ const lineHeight = layer.lineHeight ?? 1.2;
92
+ let tspanSvg = '';
93
+ let highlightSvg = '';
94
+ // Track cursor position for highlight rects and line breaks
95
+ let cursorX = layer.x;
96
+ let currentLineY = renderY;
97
+ let isFirstOnLine = true;
98
+ let maxLineWidth = 0;
99
+ let currentLineWidth = 0;
100
+ for (const span of spans) {
101
+ const spanFontSize = span.fontSize ?? baseFontSize;
102
+ const spanColor = span.color ?? baseColor;
103
+ // Split on \n to handle line breaks within a single span
104
+ const segments = span.text.split('\n');
105
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
106
+ // Handle line break (every segment after the first means a \n was found)
107
+ if (segIdx > 0) {
108
+ // Flush current line width
109
+ if (currentLineWidth > maxLineWidth)
110
+ maxLineWidth = currentLineWidth;
111
+ currentLineWidth = 0;
112
+ cursorX = layer.x;
113
+ currentLineY += baseFontSize * lineHeight;
114
+ isFirstOnLine = true;
115
+ }
116
+ const segText = segments[segIdx];
117
+ if (segText.length === 0)
118
+ continue;
119
+ const segWidth = segText.length * spanFontSize * 0.6;
120
+ // Highlight rect (rendered BEFORE text so it appears behind)
121
+ if (span.highlight) {
122
+ highlightSvg += `<rect x="${cursorX}" y="${currentLineY - spanFontSize * 0.8}" width="${segWidth}" height="${spanFontSize}" fill="${span.highlight}" />`;
123
+ }
124
+ // Build inline style overrides
125
+ const styleAttrs = [];
126
+ if (span.bold)
127
+ styleAttrs.push('font-weight: bold');
128
+ if (span.italic)
129
+ styleAttrs.push('font-style: italic');
130
+ if (span.color)
131
+ styleAttrs.push(`fill: ${spanColor}`);
132
+ if (span.fontSize)
133
+ styleAttrs.push(`font-size: ${spanFontSize}px`);
134
+ const styleAttr = styleAttrs.length > 0 ? ` style="${styleAttrs.join('; ')};"` : '';
135
+ if (isFirstOnLine) {
136
+ // First tspan on a line: reset x and apply dy for line break
137
+ const dy = currentLineY === renderY ? 0 : baseFontSize * lineHeight;
138
+ if (dy > 0) {
139
+ tspanSvg += `<tspan x="${layer.x}" dy="${dy}"${styleAttr}>${escapeXml(segText)}</tspan>`;
140
+ }
141
+ else {
142
+ tspanSvg += `<tspan${styleAttr}>${escapeXml(segText)}</tspan>`;
143
+ }
144
+ isFirstOnLine = false;
145
+ }
146
+ else {
147
+ tspanSvg += `<tspan${styleAttr}>${escapeXml(segText)}</tspan>`;
148
+ }
149
+ cursorX += segWidth;
150
+ currentLineWidth += segWidth;
151
+ }
152
+ }
153
+ // Final line width check
154
+ if (currentLineWidth > maxLineWidth)
155
+ maxLineWidth = currentLineWidth;
156
+ return {
157
+ tspanSvg,
158
+ highlightSvg,
159
+ approxMaxWidth: maxLineWidth,
160
+ };
161
+ }
162
+ /**
163
+ * Adds text layers onto an image using SVG overlay compositing.
164
+ *
165
+ * Supports two rendering modes:
166
+ * 1. **Plain text** — uses `layer.text` with optional `maxWidth` wrapping
167
+ * 2. **Inline spans** — uses `layer.spans[]` for mixed-style rendering
168
+ *
169
+ * Font loading: if `layer.fontUrl` starts with `https://`, the font is
170
+ * automatically downloaded and cached locally for librsvg compatibility.
171
+ *
172
+ * @param input - Source image (Buffer, URL, data-URI, or file path)
173
+ * @param options - Object containing `layers` array of `TextLayer`
174
+ * @returns ImageResult with the composited image buffer
175
+ *
176
+ * @example
177
+ * // Plain text
178
+ * await addText(buffer, { layers: [{ text: 'Hello', x: 10, y: 50 }] });
179
+ *
180
+ * @example
181
+ * // Inline spans
182
+ * await addText(buffer, { layers: [{
183
+ * x: 10, y: 50, fontSize: 28, color: '#333',
184
+ * spans: [
185
+ * { text: 'normal ' },
186
+ * { text: 'bold', bold: true, color: '#000' },
187
+ * ]
188
+ * }] });
189
+ */
60
190
  export async function addText(input, options) {
61
191
  try {
62
192
  const buffer = await loadImage(input);
@@ -76,12 +206,12 @@ export async function addText(input, options) {
76
206
  const color = layer.color ?? '#000000';
77
207
  const opacity = layer.opacity ?? 1.0;
78
208
  const fontFamily = layer.fontFamily ?? 'sans-serif';
79
- if (layer.fontUrl)
80
- fontImports.add(`@import url('${layer.fontUrl}');`);
81
- const lines = wrapText(layer.text, fontSize, layer.maxWidth);
209
+ // ── Font loading ──────────────────────────────────────────────
210
+ if (layer.fontUrl) {
211
+ const localUrl = await resolveFontUrl(layer.fontUrl);
212
+ fontImports.add(`@font-face { font-family: '${fontFamily}'; src: url('${localUrl}'); }`);
213
+ }
82
214
  const lineHeight = layer.lineHeight ?? 1.2;
83
- const totalHeight = lines.length * fontSize * lineHeight;
84
- const approxMaxWidth = Math.max(...lines.map(l => l.length * fontSize * 0.6));
85
215
  const { textAnchor, yOffset } = getAnchorProps(layer.anchor, fontSize);
86
216
  const renderY = layer.y + yOffset;
87
217
  let align = textAnchor;
@@ -89,41 +219,123 @@ export async function addText(input, options) {
89
219
  align = layer.align === 'left' ? 'start' : layer.align === 'right' ? 'end' : 'middle';
90
220
  }
91
221
  // Always use dominant-baseline: auto (alphabetic) — the only value librsvg reliably supports
92
- const style = `font-family: ${fontFamily}; font-size: ${fontSize}px; fill: ${color}; opacity: ${opacity}; text-anchor: ${align}; dominant-baseline: auto;`;
222
+ let style = `font-family: ${fontFamily}; font-size: ${fontSize}px; fill: ${color}; opacity: ${opacity}; text-anchor: ${align}; dominant-baseline: auto;`;
223
+ // Letter spacing
224
+ if (layer.letterSpacing) {
225
+ style += ` letter-spacing: ${layer.letterSpacing}px;`;
226
+ }
227
+ // Stroke (outline) — paint-order renders stroke behind fill
228
+ if (layer.stroke) {
229
+ style += ` stroke: ${layer.stroke.color}; stroke-width: ${layer.stroke.width}px; paint-order: stroke;`;
230
+ }
93
231
  let layerSvg = '';
94
- if (layer.background) {
95
- const bg = layer.background;
96
- const pad = bg.padding ?? 0;
97
- const bgOpacity = bg.opacity ?? 1.0;
98
- const radius = bg.borderRadius ?? 0;
99
- // Background rect is positioned relative to the *intended* y (layer.y), not renderY
100
- let rectX = layer.x - pad;
101
- let rectY = layer.y - pad;
102
- if (textAnchor === 'middle') {
103
- rectX = layer.x - (approxMaxWidth / 2) - pad;
232
+ let totalHeight;
233
+ let approxMaxWidth;
234
+ let layerTextPreview;
235
+ // ── Spans mode vs plain text mode ─────────────────────────────
236
+ if (layer.spans && layer.spans.length > 0) {
237
+ // Emit warnings for spans mode edge cases
238
+ if (layer.text) {
239
+ warnings.push('text field ignored when spans is provided');
240
+ }
241
+ if (layer.maxWidth) {
242
+ warnings.push('maxWidth is not supported with spans');
104
243
  }
105
- else if (textAnchor === 'end') {
106
- rectX = layer.x - approxMaxWidth - pad;
244
+ const spansResult = buildSpansSvg(layer.spans, layer, renderY);
245
+ approxMaxWidth = spansResult.approxMaxWidth;
246
+ // Count line breaks to compute totalHeight
247
+ const fullText = layer.spans.map((s) => s.text).join('');
248
+ const lineCount = (fullText.match(/\n/g) ?? []).length + 1;
249
+ totalHeight = lineCount * fontSize * lineHeight;
250
+ layerTextPreview = fullText.slice(0, 20);
251
+ // Background rect
252
+ if (layer.background) {
253
+ const bg = layer.background;
254
+ const pad = bg.padding ?? 0;
255
+ const bgOpacity = bg.opacity ?? 1.0;
256
+ const radius = bg.borderRadius ?? 0;
257
+ let rectX = layer.x - pad;
258
+ let rectY = layer.y - pad;
259
+ if (textAnchor === 'middle') {
260
+ rectX = layer.x - (approxMaxWidth / 2) - pad;
261
+ }
262
+ else if (textAnchor === 'end') {
263
+ rectX = layer.x - approxMaxWidth - pad;
264
+ }
265
+ const parts = (layer.anchor ?? 'top-left').split('-');
266
+ const vAlign = parts.length === 2 ? parts[0] : parts[0] === 'center' ? 'middle' : parts[0];
267
+ if (vAlign === 'middle' || vAlign === 'center') {
268
+ rectY = layer.y - (totalHeight / 2) - pad;
269
+ }
270
+ else if (vAlign === 'bottom') {
271
+ rectY = layer.y - totalHeight - pad + fontSize;
272
+ }
273
+ layerSvg += `<rect x="${rectX}" y="${rectY}" width="${approxMaxWidth + pad * 2}" height="${totalHeight + pad * 2}" fill="${bg.color}" opacity="${bgOpacity}" rx="${radius}" ry="${radius}" />`;
107
274
  }
108
- // Adjust for anchor vertical alignment
109
- const parts = (layer.anchor ?? 'top-left').split('-');
110
- const vAlign = parts.length === 2 ? parts[0] : parts[0] === 'center' ? 'middle' : parts[0];
111
- if (vAlign === 'middle' || vAlign === 'center') {
112
- rectY = layer.y - (totalHeight / 2) - pad;
275
+ // Highlight rects (behind text)
276
+ layerSvg += spansResult.highlightSvg;
277
+ // Shadow for spans mode
278
+ if (layer.textShadow) {
279
+ const ts = layer.textShadow;
280
+ const shadowStyle = `font-family: ${fontFamily}; font-size: ${fontSize}px; fill: ${ts.color}; opacity: ${opacity}; text-anchor: ${align}; dominant-baseline: auto;${layer.letterSpacing ? ` letter-spacing: ${layer.letterSpacing}px;` : ''}`;
281
+ const sx = layer.x + ts.offsetX;
282
+ const sy = renderY + ts.offsetY;
283
+ layerSvg += `<text x="${sx}" y="${sy}" style="${shadowStyle}">${spansResult.tspanSvg}</text>`;
113
284
  }
114
- else if (vAlign === 'bottom') {
115
- rectY = layer.y - totalHeight - pad + fontSize;
285
+ // Main text element with spans
286
+ layerSvg += `<text x="${layer.x}" y="${renderY}" style="${style}">${spansResult.tspanSvg}</text>`;
287
+ }
288
+ else {
289
+ // ── Plain text mode (existing logic) ─────────────────────────
290
+ const lines = wrapText(layer.text, fontSize, layer.maxWidth);
291
+ totalHeight = lines.length * fontSize * lineHeight;
292
+ approxMaxWidth = Math.max(...lines.map(l => l.length * fontSize * 0.6));
293
+ layerTextPreview = layer.text.slice(0, 20);
294
+ if (layer.background) {
295
+ const bg = layer.background;
296
+ const pad = bg.padding ?? 0;
297
+ const bgOpacity = bg.opacity ?? 1.0;
298
+ const radius = bg.borderRadius ?? 0;
299
+ let rectX = layer.x - pad;
300
+ let rectY = layer.y - pad;
301
+ if (textAnchor === 'middle') {
302
+ rectX = layer.x - (approxMaxWidth / 2) - pad;
303
+ }
304
+ else if (textAnchor === 'end') {
305
+ rectX = layer.x - approxMaxWidth - pad;
306
+ }
307
+ const parts = (layer.anchor ?? 'top-left').split('-');
308
+ const vAlign = parts.length === 2 ? parts[0] : parts[0] === 'center' ? 'middle' : parts[0];
309
+ if (vAlign === 'middle' || vAlign === 'center') {
310
+ rectY = layer.y - (totalHeight / 2) - pad;
311
+ }
312
+ else if (vAlign === 'bottom') {
313
+ rectY = layer.y - totalHeight - pad + fontSize;
314
+ }
315
+ layerSvg += `<rect x="${rectX}" y="${rectY}" width="${approxMaxWidth + pad * 2}" height="${totalHeight + pad * 2}" fill="${bg.color}" opacity="${bgOpacity}" rx="${radius}" ry="${radius}" />`;
316
+ }
317
+ // Text shadow: render a duplicate text behind the main text
318
+ if (layer.textShadow) {
319
+ const ts = layer.textShadow;
320
+ const shadowStyle = `font-family: ${fontFamily}; font-size: ${fontSize}px; fill: ${ts.color}; opacity: ${opacity}; text-anchor: ${align}; dominant-baseline: auto;${layer.letterSpacing ? ` letter-spacing: ${layer.letterSpacing}px;` : ''}`;
321
+ const sx = layer.x + ts.offsetX;
322
+ const sy = renderY + ts.offsetY;
323
+ layerSvg += `<text x="${sx}" y="${sy}" style="${shadowStyle}">`;
324
+ lines.forEach((line, idx) => {
325
+ let dy = idx === 0 ? 0 : fontSize * lineHeight;
326
+ layerSvg += `<tspan x="${sx}" dy="${dy}">${escapeXml(line)}</tspan>`;
327
+ });
328
+ layerSvg += `</text>`;
116
329
  }
117
- layerSvg += `<rect x="${rectX}" y="${rectY}" width="${approxMaxWidth + pad * 2}" height="${totalHeight + pad * 2}" fill="${bg.color}" opacity="${bgOpacity}" rx="${radius}" ry="${radius}" />`;
330
+ layerSvg += `<text x="${layer.x}" y="${renderY}" style="${style}">`;
331
+ lines.forEach((line, idx) => {
332
+ let dy = idx === 0 ? 0 : fontSize * lineHeight;
333
+ layerSvg += `<tspan x="${layer.x}" dy="${dy}">${escapeXml(line)}</tspan>`;
334
+ });
335
+ layerSvg += `</text>`;
118
336
  }
119
- layerSvg += `<text x="${layer.x}" y="${renderY}" style="${style}">`;
120
- lines.forEach((line, idx) => {
121
- let dy = idx === 0 ? 0 : fontSize * lineHeight;
122
- layerSvg += `<tspan x="${layer.x}" dy="${dy}">${escapeXml(line)}</tspan>`;
123
- });
124
- layerSvg += `</text>`;
125
337
  svgBody += `<g style="isolation: isolate">${layerSvg}</g>`;
126
- // Compute bounding box for overflow detection (using intended y, not renderY)
338
+ // ── Bounding box / overflow detection ──────────────────────────
127
339
  let boxX = layer.x;
128
340
  let boxY = layer.y;
129
341
  if (textAnchor === 'middle')
@@ -141,7 +353,7 @@ export async function addText(input, options) {
141
353
  if (boxBottom > contentBottom)
142
354
  contentBottom = boxBottom;
143
355
  if (boxX < 0 || boxY < 0 || boxRight > width || boxBottom > height) {
144
- warnings.push(`Text layer ${i} ("${layer.text.slice(0, 20)}...") extends beyond canvas bounds.`);
356
+ warnings.push(`Text layer ${i} ("${layerTextPreview}...") extends beyond canvas bounds.`);
145
357
  }
146
358
  }
147
359
  const fontStyle = fontImports.size > 0 ? `<style>${Array.from(fontImports).join('\n')}</style>` : '';
@@ -165,6 +377,9 @@ export async function addText(input, options) {
165
377
  return err('File not found', ErrorCode.INVALID_INPUT);
166
378
  if (msg.includes('unsupported image format'))
167
379
  return err('Corrupt or unsupported input', ErrorCode.INVALID_INPUT);
380
+ if (msg.includes('Font download failed') || msg.includes('Google Fonts CSS fetch failed')) {
381
+ return err(msg, ErrorCode.FETCH_FAILED);
382
+ }
168
383
  return err(msg, ErrorCode.PROCESSING_FAILED);
169
384
  }
170
385
  }