From ddcae4905e32e737465cd5787136868ce9921cf5 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 27 Jan 2026 16:35:56 +0400 Subject: [PATCH 1/2] =?UTF-8?q?ImageManager.=20=D0=9F=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8F=D0=B5=D0=BC=20=D0=B8=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D1=81=D1=8B=D0=B2=D0=B0=D0=B5=D0=BC=20Conten?= =?UTF-8?q?tType=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=20dataURL=20=D0=B8=20=D1=80=D0=B5?= =?UTF-8?q?=D1=81=D0=B0=D0=B9=D0=B7=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 +- package.json | 2 +- src/editor/image-manager/index.ts | 58 ++++++++++++++++++++--------- src/editor/worker-manager/worker.ts | 18 ++++++++- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 39a8e55..accd92a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@anu3ev/fabric-image-editor", - "version": "0.5.32", + "version": "0.5.33", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@anu3ev/fabric-image-editor", - "version": "0.5.32", + "version": "0.5.33", "license": "MIT", "dependencies": { "diff-match-patch": "^1.0.5", diff --git a/package.json b/package.json index d41f056..82a0e88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@anu3ev/fabric-image-editor", - "version": "0.5.32", + "version": "0.5.33", "description": "JavaScript image editor built on FabricJS, allowing you to create instances with an integrated montage area and providing an API to modify and manage state.", "module": "dist/main.js", "files": [ diff --git a/src/editor/image-manager/index.ts b/src/editor/image-manager/index.ts index 9c45c69..1c9b664 100644 --- a/src/editor/image-manager/index.ts +++ b/src/editor/image-manager/index.ts @@ -41,12 +41,14 @@ export type ResizeImageToBoundariesOptions = { dataURL: string, sizeType?: 'max' | 'min', contentType?: string, + quality?: number, maxWidth?: number, maxHeight?: number, minWidth?: number, minHeight?: number, asBase64?: boolean, - asBlob?: boolean + asBlob?: boolean, + emitMessage?: boolean } export type ExportObjectAsImageFileParameters = { @@ -354,6 +356,8 @@ export default class ImageManager { * @param options.minHeight - минимальная высота (по умолчанию CANVAS_MIN_HEIGHT) * @param options.asBase64 - вернуть base64 вместо Blob * @param options.emitMessage - выводить предупреждение в случае ресайза + * @param options.contentType - тип контента + * @param options.quality - качество изображения от 0 до 1 (для JPEG/WebP) * @returns возвращает Promise с Blob или base64 в зависимости от опций */ public async resizeImageToBoundaries( @@ -516,15 +520,19 @@ export default class ImageManager { return data } - // Получаем blob из клонированного канваса + // Получаем blob из клонированного канваса в нужном формате const blob: Blob = await new Promise((resolve, reject) => { - tmpCanvas.getElement().toBlob((canvasBlob) => { - if (canvasBlob) { - resolve(canvasBlob) - } else { - reject(new Error('Failed to create Blob from canvas')) - } - }) + tmpCanvas.getElement().toBlob( + (canvasBlob) => { + if (canvasBlob) { + resolve(canvasBlob) + } else { + reject(new Error('Failed to create Blob from canvas')) + } + }, + adjustedContentType, + 1 + ) }) // Уничтожаем клон @@ -545,9 +553,14 @@ export default class ImageManager { // Создаём bitmap из blob, отправляем в воркер и получаем dataURL const bitmap = await createImageBitmap(blob) + const dataUrl = await workerManager.post( 'toDataURL', - { contentType: adjustedContentType, quality: 1, bitmap }, + { + contentType: adjustedContentType, + quality: 1, + bitmap + }, [bitmap] ) @@ -660,12 +673,12 @@ export default class ImageManager { exportAsBlob = false } = options - const processedFileName = fileName ?? `image.${object.format}` - const processedContentType = contentType ?? object.contentType ?? 'image/png' - const { canvas, workerManager } = this.editor const activeObject = object || canvas.getActiveObject() + const fallbackContentType = contentType ?? 'image/png' + const fallbackFormat = ImageManager.getFormatFromContentType(fallbackContentType) || 'png' + const fallbackFileName = fileName ?? `image.${fallbackFormat}` if (!activeObject) { this.editor.errorManager.emitError({ @@ -673,14 +686,23 @@ export default class ImageManager { method: 'exportObjectAsImageFile', code: 'NO_OBJECT_SELECTED', message: 'Не выбран объект для экспорта', - data: { contentType: processedContentType, fileName: processedFileName, exportAsBase64, exportAsBlob } + data: { contentType: fallbackContentType, fileName: fallbackFileName, exportAsBase64, exportAsBlob } }) return null } + const { contentType: objectContentType, format: objectFormat = '' } = activeObject as { + contentType?: string + format?: string + } + const processedContentType = contentType ?? objectContentType ?? 'image/png' + const format = ImageManager.getFormatFromContentType(processedContentType) + || objectFormat + || 'png' + const processedFileName = fileName ?? `image.${format}` + try { - const format = ImageManager.getFormatFromContentType(processedContentType) if (format === 'svg') { // Конвертируем fabric.Object в SVG-строку @@ -689,7 +711,7 @@ export default class ImageManager { const svg = ImageManager._exportSVGStringAsFile(svgString, { exportAsBase64, exportAsBlob, - fileName + fileName: processedFileName }) const data = { @@ -697,7 +719,7 @@ export default class ImageManager { image: svg, format, contentType: 'image/svg+xml', - fileName: fileName.replace(/\.[^/.]+$/, '.svg') + fileName: processedFileName.replace(/\.[^/.]+$/, '.svg') } canvas.fire('editor:object-exported', data) @@ -755,7 +777,7 @@ export default class ImageManager { } // Преобразуем Blob в File - const file = new File([activeObjectBlob], fileName, { type: processedContentType }) + const file = new File([activeObjectBlob], processedFileName, { type: processedContentType }) const data = { object: activeObject, diff --git a/src/editor/worker-manager/worker.ts b/src/editor/worker-manager/worker.ts index 2a9b45b..3099173 100644 --- a/src/editor/worker-manager/worker.ts +++ b/src/editor/worker-manager/worker.ts @@ -6,7 +6,16 @@ self.onmessage = async(e: MessageEvent): Promise => { try { switch (action) { case 'resizeImage': { - const { dataURL, maxWidth, maxHeight, minWidth, minHeight, contentType, quality, sizeType } = payload + const { + dataURL, + maxWidth, + maxHeight, + minWidth, + minHeight, + contentType, + quality, + sizeType + } = payload const imgBitmap = await createImageBitmap(await (await fetch(dataURL)).blob()) // вычисляем новый размер @@ -38,7 +47,12 @@ self.onmessage = async(e: MessageEvent): Promise => { } case 'toDataURL': { - const { bitmap, contentType, quality, returnBlob } = payload + const { + bitmap, + contentType, + quality, + returnBlob + } = payload const { width, height } = bitmap // рисуем изображение в offscreen From 0de104f4a522af678f0776ec69838b91cdd550d2 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 27 Jan 2026 16:38:00 +0400 Subject: [PATCH 2/2] linter --- src/editor/image-manager/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editor/image-manager/index.ts b/src/editor/image-manager/index.ts index 1c9b664..1981e29 100644 --- a/src/editor/image-manager/index.ts +++ b/src/editor/image-manager/index.ts @@ -703,7 +703,6 @@ export default class ImageManager { const processedFileName = fileName ?? `image.${format}` try { - if (format === 'svg') { // Конвертируем fabric.Object в SVG-строку const svgString = activeObject.toSVG()