@bwp-web/canvas 0.4.3 → 0.5.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.
@@ -19,15 +19,23 @@ export interface FitViewportOptions {
19
19
  */
20
20
  export declare function fitViewportToBackground(canvas: FabricCanvas, options?: FitViewportOptions): void;
21
21
  /**
22
- * Set the opacity of the canvas background image.
23
- * Value is clamped to the 0–1 range.
22
+ * Set the contrast of the canvas background image.
23
+ *
24
+ * Value is expressed as a 0–2 scale:
25
+ * - **0**: minimum contrast (flat grey).
26
+ * - **1**: normal / unmodified (no filter applied).
27
+ * - **2**: maximum contrast (darks are truly dark, lights truly light).
28
+ *
29
+ * Clamped to the 0–2 range.
24
30
  */
25
- export declare function setBackgroundOpacity(canvas: FabricCanvas, opacity: number): void;
31
+ export declare function setBackgroundContrast(canvas: FabricCanvas, value: number): void;
26
32
  /**
27
- * Get the current opacity of the canvas background image.
33
+ * Get the current contrast of the canvas background image.
34
+ *
35
+ * Returns a value in the 0–2 range where 1 is normal (no filter).
28
36
  * Returns 1 if no background image is set.
29
37
  */
30
- export declare function getBackgroundOpacity(canvas: FabricCanvas): number;
38
+ export declare function getBackgroundContrast(canvas: FabricCanvas): number;
31
39
  /**
32
40
  * Add or remove the Invert filter from the canvas background image.
33
41
  */
@@ -75,14 +83,14 @@ export interface ResizeImageOptions {
75
83
  */
76
84
  export declare function resizeImageUrl(url: string, options?: ResizeImageOptions): Promise<ResizeResult>;
77
85
  export interface SetBackgroundImageOptions extends ResizeImageOptions {
78
- /** Preserve the current background opacity when replacing the image. */
79
- preserveOpacity?: boolean;
86
+ /** Preserve the current background contrast when replacing the image. */
87
+ preserveContrast?: boolean;
80
88
  }
81
89
  /**
82
90
  * Set an image URL as the canvas background image.
83
91
  *
84
92
  * Pass options to control auto-resize (`maxSize`, `minSize`) and/or
85
- * preserve the current background opacity when replacing the image.
93
+ * preserve the current background contrast when replacing the image.
86
94
  * Omit to load the URL as-is without resizing.
87
95
  *
88
96
  * Returns the created FabricImage for further manipulation.
@@ -1 +1 @@
1
- {"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../src/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,WAAW,EAAW,MAAM,QAAQ,CAAC;AAWtE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAIpE;AAID,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,IAAI,CAiCN;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,GACd,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAGjE;AAID;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,OAAO,GAChB,IAAI,CAgBN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAInE;AAID,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAkDvB;AAID,MAAM,WAAW,yBAA0B,SAAQ,kBAAkB;IACnE,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,WAAW,CAAC,CAmBtB"}
1
+ {"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../src/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,WAAW,EAAW,MAAM,QAAQ,CAAC;AAWtE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAIpE;AAID,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,IAAI,CAiCN;AAID;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GACZ,IAAI,CA6BN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAUlE;AAID;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,OAAO,GAChB,IAAI,CAgBN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAInE;AAID,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAkDvB;AAID,MAAM,WAAW,yBAA0B,SAAQ,kBAAkB;IACnE,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,WAAW,CAAC,CAmBtB"}
@@ -4,8 +4,8 @@ export declare const DEFAULT_MIN_ZOOM = 0.2;
4
4
  export declare const DEFAULT_MAX_ZOOM = 10;
5
5
  /** Zoom sensitivity multiplier (applied per wheel tick). */
6
6
  export declare const DEFAULT_ZOOM_FACTOR = 1.03;
7
- /** Default step for programmatic zoomIn/zoomOut. */
8
- export declare const DEFAULT_ZOOM_STEP = 0.2;
7
+ /** Default multiplier for programmatic zoomIn/zoomOut (1.2 = 20% per click). */
8
+ export declare const DEFAULT_ZOOM_STEP = 1.2;
9
9
  /** Default viewport padding fraction (5% on each side). */
10
10
  export declare const DEFAULT_VIEWPORT_PADDING = 0.05;
11
11
  /** Reference canvas dimension for scaling snap margins proportionally. */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAI7C,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,8CAA8C;AAC9C,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAI9C;;;GAGG;AACH,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAI1C,oDAAoD;AACpD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAI1C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,4BAA4B,YAAY,CAAC;AACtD,eAAO,MAAM,kCAAkC,IAAI,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAI7C,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,8CAA8C;AAC9C,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAI9C;;;GAGG;AACH,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAI1C,oDAAoD;AACpD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAI1C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,4BAA4B,YAAY,CAAC;AACtD,eAAO,MAAM,kCAAkC,IAAI,CAAC"}
@@ -129,11 +129,11 @@ export declare function useEditCanvas(options?: UseEditCanvasOptions): {
129
129
  * exceeds the configured limits (opt out via `backgroundResize: false`),
130
130
  * and fits the viewport after setting if `autoFitToBackground` is enabled.
131
131
  *
132
- * Pass `{ preserveOpacity: true }` to keep the current background opacity
132
+ * Pass `{ preserveContrast: true }` to keep the current background contrast
133
133
  * when replacing the image.
134
134
  */
135
135
  setBackground: (url: string, bgOpts?: {
136
- preserveOpacity?: boolean;
136
+ preserveContrast?: boolean;
137
137
  }) => Promise<import("fabric").FabricImage<Partial<import("fabric").ImageProps>, import("fabric").SerializedImageProps, import("fabric").ObjectEvents>>;
138
138
  /** Whether the canvas has been modified since the last `resetDirty()` call. Requires `trackChanges: true`. */
139
139
  isDirty: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditCanvas.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditCanvas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,KAAK,YAAY,EAAW,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAEL,KAAK,iBAAiB,EAEtB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC,mIAAmI;IACnI,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAC7C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAChD;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB;IAuOxD,8CAA8C;sBA9KrC,YAAY;IAgLrB,oDAAoD;;IAEpD,qCAAqC;;IAErC,6CAA6C;;IAE7C,yBAAyB;;QAEvB,wCAAwC;;QAExC,wDAAwD;wBAnDjB,YAAY;QAqDnD,wFAAwF;;QAExF,2DAA2D;;QAE3D,0DAA0D;;QAE1D,uDAAuD;;;IAGzD,+DAA+D;;IAE/D;;;;;;;;;;;;;;OAcG;qBArP+B,SAAS,GAAG,IAAI;IAuPlD;;;;;;;OAOG;yBA3ES,MAAM,WAAW;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE;IA6E1D,8GAA8G;;IAE9G,4DAA4D;;EAG/D"}
1
+ {"version":3,"file":"useEditCanvas.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditCanvas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,KAAK,YAAY,EAAW,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAEL,KAAK,iBAAiB,EAEtB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC,mIAAmI;IACnI,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAC7C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAChD;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB;IAuOxD,8CAA8C;sBA9KrC,YAAY;IAgLrB,oDAAoD;;IAEpD,qCAAqC;;IAErC,6CAA6C;;IAE7C,yBAAyB;;QAEvB,wCAAwC;;QAExC,wDAAwD;wBAnDjB,YAAY;QAqDnD,wFAAwF;;QAExF,2DAA2D;;QAE3D,0DAA0D;;QAE1D,uDAAuD;;;IAGzD,+DAA+D;;IAE/D;;;;;;;;;;;;;;OAcG;qBArP+B,SAAS,GAAG,IAAI;IAuPlD;;;;;;;OAOG;yBA3ES,MAAM,WAAW;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE;IA6E3D,8GAA8G;;IAE9G,4DAA4D;;EAG/D"}
package/dist/index.cjs CHANGED
@@ -55,8 +55,8 @@ __export(index_exports, {
55
55
  enableScaledStrokes: () => enableScaledStrokes,
56
56
  enableVertexEdit: () => enableVertexEdit,
57
57
  fitViewportToBackground: () => fitViewportToBackground,
58
+ getBackgroundContrast: () => getBackgroundContrast,
58
59
  getBackgroundInverted: () => getBackgroundInverted,
59
- getBackgroundOpacity: () => getBackgroundOpacity,
60
60
  getBackgroundSrc: () => getBackgroundSrc,
61
61
  getBaseStrokeWidth: () => getBaseStrokeWidth,
62
62
  getSnapPoints: () => getSnapPoints,
@@ -65,9 +65,9 @@ __export(index_exports, {
65
65
  resetViewport: () => resetViewport,
66
66
  resizeImageUrl: () => resizeImageUrl,
67
67
  serializeCanvas: () => serializeCanvas,
68
+ setBackgroundContrast: () => setBackgroundContrast,
68
69
  setBackgroundImage: () => setBackgroundImage,
69
70
  setBackgroundInverted: () => setBackgroundInverted,
70
- setBackgroundOpacity: () => setBackgroundOpacity,
71
71
  snapCursorPoint: () => snapCursorPoint,
72
72
  useCanvasClick: () => useCanvasClick,
73
73
  useCanvasEvents: () => useCanvasEvents,
@@ -173,7 +173,7 @@ var import_fabric3 = require("fabric");
173
173
  var DEFAULT_MIN_ZOOM = 0.2;
174
174
  var DEFAULT_MAX_ZOOM = 10;
175
175
  var DEFAULT_ZOOM_FACTOR = 1.03;
176
- var DEFAULT_ZOOM_STEP = 0.2;
176
+ var DEFAULT_ZOOM_STEP = 1.2;
177
177
  var DEFAULT_VIEWPORT_PADDING = 0.05;
178
178
  var BASE_CANVAS_SIZE = 1e3;
179
179
  var DEFAULT_SNAP_MARGIN = 6;
@@ -355,15 +355,15 @@ function enablePanAndZoom(canvas, options) {
355
355
  setEnabled(value) {
356
356
  enabled = value;
357
357
  },
358
- zoomIn(step = DEFAULT_ZOOM_STEP) {
359
- const z = Math.min(canvas.getZoom() + step, bounds.maxZoom);
358
+ zoomIn(factor = DEFAULT_ZOOM_STEP) {
359
+ const z = Math.min(canvas.getZoom() * factor, bounds.maxZoom);
360
360
  canvas.zoomToPoint(
361
361
  new import_fabric3.Point(canvas.getWidth() / 2, canvas.getHeight() / 2),
362
362
  z
363
363
  );
364
364
  },
365
- zoomOut(step = DEFAULT_ZOOM_STEP) {
366
- const z = Math.max(canvas.getZoom() - step, bounds.minZoom);
365
+ zoomOut(factor = DEFAULT_ZOOM_STEP) {
366
+ const z = Math.max(canvas.getZoom() / factor, bounds.minZoom);
367
367
  canvas.zoomToPoint(
368
368
  new import_fabric3.Point(canvas.getWidth() / 2, canvas.getHeight() / 2),
369
369
  z
@@ -462,15 +462,37 @@ function fitViewportToBackground(canvas, options) {
462
462
  canvas.setViewportTransform([scale, 0, 0, scale, offsetX, offsetY]);
463
463
  canvas.requestRenderAll();
464
464
  }
465
- function setBackgroundOpacity(canvas, opacity) {
465
+ function setBackgroundContrast(canvas, value) {
466
466
  const bg = getBackgroundImage(canvas);
467
467
  if (!bg) return;
468
- bg.set("opacity", Math.min(1, Math.max(0, opacity)));
468
+ const contrast = Math.min(Math.max(value, 0), 2) - 1;
469
+ const currentFilters = bg.filters ?? [];
470
+ const contrastIdx = currentFilters.findIndex(
471
+ (f) => f instanceof import_fabric4.filters.Contrast
472
+ );
473
+ if (contrast === 0) {
474
+ if (contrastIdx >= 0) {
475
+ bg.filters = currentFilters.filter(
476
+ (f) => !(f instanceof import_fabric4.filters.Contrast)
477
+ );
478
+ bg.applyFilters();
479
+ }
480
+ } else if (contrastIdx >= 0) {
481
+ currentFilters[contrastIdx].contrast = contrast;
482
+ bg.applyFilters();
483
+ } else {
484
+ bg.filters = [...currentFilters, new import_fabric4.filters.Contrast({ contrast })];
485
+ bg.applyFilters();
486
+ }
469
487
  canvas.requestRenderAll();
470
488
  }
471
- function getBackgroundOpacity(canvas) {
489
+ function getBackgroundContrast(canvas) {
472
490
  const bg = getBackgroundImage(canvas);
473
- return bg?.opacity ?? 1;
491
+ if (!bg) return 1;
492
+ const contrastFilter = bg.filters?.find(
493
+ (f) => f instanceof import_fabric4.filters.Contrast
494
+ );
495
+ return 1 + (contrastFilter?.contrast ?? 0);
474
496
  }
475
497
  function setBackgroundInverted(canvas, inverted) {
476
498
  const bg = getBackgroundImage(canvas);
@@ -536,7 +558,7 @@ function resizeImageUrl(url, options) {
536
558
  });
537
559
  }
538
560
  async function setBackgroundImage(canvas, url, options) {
539
- const prevOpacity = options?.preserveOpacity ? getBackgroundOpacity(canvas) : void 0;
561
+ const prevContrast = options?.preserveContrast ? getBackgroundContrast(canvas) : void 0;
540
562
  let imageUrl = url;
541
563
  if (options !== void 0) {
542
564
  const result = await resizeImageUrl(url, options);
@@ -544,8 +566,8 @@ async function setBackgroundImage(canvas, url, options) {
544
566
  }
545
567
  const img = await import_fabric4.FabricImage.fromURL(imageUrl, { crossOrigin: "anonymous" });
546
568
  canvas.backgroundImage = img;
547
- if (prevOpacity !== void 0 && prevOpacity !== 1) {
548
- img.set("opacity", prevOpacity);
569
+ if (prevContrast !== void 0 && prevContrast !== 1) {
570
+ setBackgroundContrast(canvas, prevContrast);
549
571
  }
550
572
  canvas.requestRenderAll();
551
573
  return img;
@@ -2151,6 +2173,7 @@ function serializeCanvas(canvas, options) {
2151
2173
  }
2152
2174
  });
2153
2175
  const json = canvas.toObject(properties);
2176
+ delete json.backgroundColor;
2154
2177
  scaledWidths.forEach((scaled, obj) => {
2155
2178
  obj.strokeWidth = scaled;
2156
2179
  });
@@ -2165,6 +2188,17 @@ async function loadCanvas(canvas, json, options) {
2165
2188
  });
2166
2189
  for (const obj of toRemove) canvas.remove(obj);
2167
2190
  }
2191
+ canvas.forEachObject((obj) => {
2192
+ if (obj.originX === "center" && obj.originY === "center") return;
2193
+ const center = obj.getCenterPoint();
2194
+ obj.set({
2195
+ originX: "center",
2196
+ originY: "center",
2197
+ left: center.x,
2198
+ top: center.y
2199
+ });
2200
+ obj.setCoords();
2201
+ });
2168
2202
  canvas.forEachObject((obj) => {
2169
2203
  obj.set(DEFAULT_CONTROL_STYLE);
2170
2204
  if (obj.shapeType === "circle" && obj instanceof import_fabric16.Rect) {
@@ -2327,7 +2361,7 @@ function useEditCanvas(options) {
2327
2361
  async (url, bgOpts) => {
2328
2362
  const canvas = canvasRef.current;
2329
2363
  if (!canvas) throw new Error("Canvas not ready");
2330
- const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveOpacity ? { preserveOpacity: true } : void 0;
2364
+ const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
2331
2365
  const img = await setBackgroundImage(canvas, url, resizeOpts);
2332
2366
  if (options?.autoFitToBackground !== false) {
2333
2367
  fitViewportToBackground(canvas);
@@ -2385,7 +2419,7 @@ function useEditCanvas(options) {
2385
2419
  * exceeds the configured limits (opt out via `backgroundResize: false`),
2386
2420
  * and fits the viewport after setting if `autoFitToBackground` is enabled.
2387
2421
  *
2388
- * Pass `{ preserveOpacity: true }` to keep the current background opacity
2422
+ * Pass `{ preserveContrast: true }` to keep the current background contrast
2389
2423
  * when replacing the image.
2390
2424
  */
2391
2425
  setBackground,
@@ -2768,8 +2802,8 @@ var import_fabric20 = require("fabric");
2768
2802
  enableScaledStrokes,
2769
2803
  enableVertexEdit,
2770
2804
  fitViewportToBackground,
2805
+ getBackgroundContrast,
2771
2806
  getBackgroundInverted,
2772
- getBackgroundOpacity,
2773
2807
  getBackgroundSrc,
2774
2808
  getBaseStrokeWidth,
2775
2809
  getSnapPoints,
@@ -2778,9 +2812,9 @@ var import_fabric20 = require("fabric");
2778
2812
  resetViewport,
2779
2813
  resizeImageUrl,
2780
2814
  serializeCanvas,
2815
+ setBackgroundContrast,
2781
2816
  setBackgroundImage,
2782
2817
  setBackgroundInverted,
2783
- setBackgroundOpacity,
2784
2818
  snapCursorPoint,
2785
2819
  useCanvasClick,
2786
2820
  useCanvasEvents,