Skip to content

Commit

Permalink
fix(editor): image size and xywh when converting attachment to image
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Feb 14, 2025
1 parent e1117f8 commit c1d5cd4
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 36 deletions.
57 changes: 46 additions & 11 deletions blocksuite/affine/block-attachment/src/embed.ts
Original file line number Diff line number Diff line change
@@ -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;
/**
Expand All @@ -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> | void;
action?: (
model: AttachmentBlockModel,
std: BlockStdScope
) => Promise<void> | void;
/**
* The template will be used to render the embed view.
*/
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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;
Expand All @@ -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<ImageBlockProps> = {
sourceId,
caption: model.caption,
size: model.size,
...imageConvertData,
...imageSize,
...others,
};
transformModel(model, 'affine:image', imageProp);
}
2 changes: 1 addition & 1 deletion blocksuite/affine/block-attachment/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 1 addition & 21 deletions blocksuite/affine/block-image/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import {
downloadBlob,
humanFileSize,
readImageSize,
transformModel,
withTempBlobData,
} from '@blocksuite/affine-shared/utils';
Expand Down Expand Up @@ -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[],
Expand Down
25 changes: 25 additions & 0 deletions blocksuite/affine/shared/src/utils/image.ts
Original file line number Diff line number Diff line change
@@ -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);

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
});
}
1 change: 1 addition & 0 deletions blocksuite/affine/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit c1d5cd4

Please sign in to comment.