From c1d5cd474737b7ac13d6661736c944946ded00c6 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Fri, 14 Feb 2025 19:05:28 +0800 Subject: [PATCH] fix(editor): image size and xywh when converting attachment to image --- .../affine/block-attachment/src/embed.ts | 57 +++++++++++++++---- .../affine/block-attachment/src/utils.ts | 2 +- blocksuite/affine/block-image/src/utils.ts | 22 +------ blocksuite/affine/shared/src/utils/image.ts | 25 ++++++++ blocksuite/affine/shared/src/utils/index.ts | 1 + ...ould-turn-attachment-to-image-works-1.json | 6 +- 6 files changed, 77 insertions(+), 36 deletions(-) create mode 100644 blocksuite/affine/shared/src/utils/image.ts diff --git a/blocksuite/affine/block-attachment/src/embed.ts b/blocksuite/affine/block-attachment/src/embed.ts index 416dd6c843809..004ca9c193cdc 100644 --- a/blocksuite/affine/block-attachment/src/embed.ts +++ b/blocksuite/affine/block-attachment/src/embed.ts @@ -1,20 +1,25 @@ -import type { - AttachmentBlockModel, - ImageBlockProps, +import { + type AttachmentBlockModel, + type ImageBlockProps, + MAX_IMAGE_WIDTH, } from '@blocksuite/affine-model'; import { FileSizeLimitService } from '@blocksuite/affine-shared/services'; import { + readImageSize, transformModel, withTempBlobData, } from '@blocksuite/affine-shared/utils'; import { type BlockStdScope, StdIdentifier } from '@blocksuite/block-std'; import type { Container } from '@blocksuite/global/di'; import { createIdentifier } from '@blocksuite/global/di'; +import { Bound } from '@blocksuite/global/utils'; import type { ExtensionType } from '@blocksuite/store'; import { Extension } from '@blocksuite/store'; import type { TemplateResult } from 'lit'; import { html } from 'lit'; +import { getAttachmentBlob } from './utils'; + export type AttachmentEmbedConfig = { name: string; /** @@ -24,7 +29,10 @@ export type AttachmentEmbedConfig = { /** * The action will be executed when the 「Turn into embed view」 button is clicked. */ - action?: (model: AttachmentBlockModel) => Promise | void; + action?: ( + model: AttachmentBlockModel, + std: BlockStdScope + ) => Promise | void; /** * The template will be used to render the embed view. */ @@ -91,11 +99,11 @@ export class AttachmentEmbedService extends Extension { // Converts to embed view. convertTo(model: AttachmentBlockModel, maxFileSize = this._maxFileSize) { const config = this.values.find(config => config.check(model, maxFileSize)); - if (!config || !config.action) { + if (!config?.action) { model.doc.updateBlock(model, { embed: true }); return; } - config.action(model)?.catch(console.error); + config.action(model, this.std)?.catch(console.error); } embedded(model: AttachmentBlockModel, maxFileSize = this._maxFileSize) { @@ -125,7 +133,12 @@ const embedConfig: AttachmentEmbedConfig[] = [ check: model => model.doc.schema.flavourSchemaMap.has('affine:image') && model.type.startsWith('image/'), - action: model => turnIntoImageBlock(model), + async action(model, std) { + const component = std.view.getBlock(model.id); + if (!component) return; + + await turnIntoImageBlock(model); + }, }, { name: 'pdf', @@ -173,7 +186,7 @@ const embedConfig: AttachmentEmbedConfig[] = [ /** * Turn the attachment block into an image block. */ -export function turnIntoImageBlock(model: AttachmentBlockModel) { +export async function turnIntoImageBlock(model: AttachmentBlockModel) { if (!model.doc.schema.flavourSchemaMap.has('affine:image')) { console.error('The image flavour is not supported!'); return; @@ -185,15 +198,37 @@ export function turnIntoImageBlock(model: AttachmentBlockModel) { const { saveAttachmentData, getImageData } = withTempBlobData(); saveAttachmentData(sourceId, { name: model.name }); - const imageConvertData = model.sourceId - ? getImageData(model.sourceId) + let imageSize = model.sourceId ? getImageData(model.sourceId) : undefined; + + const bounds = model.xywh + ? Bound.fromXYWH(model.deserializedXYWH) : undefined; + if (bounds) { + if (!imageSize?.width || !imageSize?.height) { + const blob = await getAttachmentBlob(model); + if (blob) { + imageSize = await readImageSize(blob); + } + } + + if (imageSize?.width && imageSize?.height) { + const p = imageSize.height / imageSize.width; + imageSize.width = Math.min(imageSize.width, MAX_IMAGE_WIDTH); + imageSize.height = imageSize.width * p; + bounds.w = imageSize.width; + bounds.h = imageSize.height; + } + } + + const others = bounds ? { xywh: bounds.serialize() } : undefined; + const imageProp: Partial = { sourceId, caption: model.caption, size: model.size, - ...imageConvertData, + ...imageSize, + ...others, }; transformModel(model, 'affine:image', imageProp); } diff --git a/blocksuite/affine/block-attachment/src/utils.ts b/blocksuite/affine/block-attachment/src/utils.ts index 85a7c74fdf118..3cf5891d47164 100644 --- a/blocksuite/affine/block-attachment/src/utils.ts +++ b/blocksuite/affine/block-attachment/src/utils.ts @@ -97,7 +97,7 @@ export async function uploadAttachmentBlob( } } -async function getAttachmentBlob(model: AttachmentBlockModel) { +export async function getAttachmentBlob(model: AttachmentBlockModel) { const sourceId = model.sourceId; if (!sourceId) { return null; diff --git a/blocksuite/affine/block-image/src/utils.ts b/blocksuite/affine/block-image/src/utils.ts index 7b08ad2bc7185..8fcfd4c8f3093 100644 --- a/blocksuite/affine/block-image/src/utils.ts +++ b/blocksuite/affine/block-image/src/utils.ts @@ -12,6 +12,7 @@ import { import { downloadBlob, humanFileSize, + readImageSize, transformModel, withTempBlobData, } from '@blocksuite/affine-shared/utils'; @@ -401,27 +402,6 @@ export async function turnImageIntoCardView( transformModel(model, 'affine:attachment', attachmentProp); } -export function readImageSize(file: File) { - return new Promise<{ width: number; height: number }>(resolve => { - const size = { width: 0, height: 0 }; - const img = new Image(); - - img.onload = () => { - size.width = img.width; - size.height = img.height; - URL.revokeObjectURL(img.src); - resolve(size); - }; - - img.onerror = () => { - URL.revokeObjectURL(img.src); - resolve(size); - }; - - img.src = URL.createObjectURL(file); - }); -} - export async function addImages( std: BlockStdScope, files: File[], diff --git a/blocksuite/affine/shared/src/utils/image.ts b/blocksuite/affine/shared/src/utils/image.ts new file mode 100644 index 0000000000000..8fb28215d4371 --- /dev/null +++ b/blocksuite/affine/shared/src/utils/image.ts @@ -0,0 +1,25 @@ +export function readImageSize(file: File | Blob) { + return new Promise<{ width: number; height: number }>(resolve => { + const size = { width: 0, height: 0 }; + if (!file.type.startsWith('image/')) { + resolve(size); + return; + } + + const img = new Image(); + + img.onload = () => { + size.width = img.width; + size.height = img.height; + URL.revokeObjectURL(img.src); + resolve(size); + }; + + img.onerror = () => { + URL.revokeObjectURL(img.src); + resolve(size); + }; + + img.src = URL.createObjectURL(file); + }); +} diff --git a/blocksuite/affine/shared/src/utils/index.ts b/blocksuite/affine/shared/src/utils/index.ts index 5cde1bb8058d4..ba6ca7b7cf305 100644 --- a/blocksuite/affine/shared/src/utils/index.ts +++ b/blocksuite/affine/shared/src/utils/index.ts @@ -8,6 +8,7 @@ export * from './edgeless'; export * from './event'; export * from './file'; export * from './fractional-indexing'; +export * from './image'; export * from './insert'; export * from './is-abort-error'; export * from './math'; diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json index 9eb1cb4229c11..0ee8824968719 100644 --- a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json +++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json @@ -42,10 +42,10 @@ "version": 1, "props": { "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA=", - "width": 0, - "height": 0, + "width": 460, + "height": 345, "index": "a0", - "xywh": "[0,0,0,0]", + "xywh": "[0,0,460,345]", "lockedBySelf": false, "rotate": 0, "size": 45801,