coze-studio/frontend/packages/workflow/fabric-canvas/src/share/fabric-image.ts

96 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 这个文件仅实现 setImageFixed 一个函数就好
* nodejs 图片渲染同样需要计算位置。要在 packages/workflow/nodejs/fabric-render 实现一份功能完全一致的 js 版
*/
import {
type FabricImage,
type FabricObject,
type Group,
type Rect,
} from 'fabric';
import { ImageFixedType, type FabricObjectWithCustomProps } from './typings';
/**
* 调整 img 位置
*/
export const setImageFixed = ({ element }: { element: FabricObject }) => {
const { width, height } = element;
const img = (element as Group).getObjects()[0] as FabricImage;
const { customFixedType } = img as unknown as FabricObjectWithCustomProps;
const borderRect = (element as Group).getObjects()[1] as Rect;
const { strokeWidth = 0 } = borderRect;
// 填充/拉伸时,框适配 group 大小即可
const borderRectWidth = width - strokeWidth;
const borderRectHeight = height - strokeWidth;
borderRect.set({
width: borderRectWidth,
height: borderRectHeight,
left: -width / 2,
top: -height / 2,
});
const { width: originWidth, height: originHeight } = img.getOriginalSize();
/**
* 为什么 +1
* 经过计算后,存储位数有限,不管是 scaleX/Y width/height top/left都会丢失一点点精度
* 这点精度反馈到图片上,就是图片与边框有一点点间隙
* 这里 +1 让图片显示的稍微大一点,弥补精度带来的间隙。
* 弊端:边框会覆盖一点点图片(覆盖多少看缩放比),用户基本无感
*/
const realScaleX = (width - strokeWidth * 2 + 1) / originWidth;
const realScaleY = (height - strokeWidth * 2 + 1) / originHeight;
const minScale = Math.min(realScaleX, realScaleY);
const maxScale = Math.max(realScaleX, realScaleY);
let scaleX = minScale;
let scaleY = minScale;
if (customFixedType === ImageFixedType.FILL) {
scaleX = maxScale;
scaleY = maxScale;
} else if (customFixedType === ImageFixedType.FULL) {
scaleX = realScaleX;
scaleY = realScaleY;
}
const imgLeft = -(originWidth * scaleX) / 2;
const imgTop = -(originHeight * scaleY) / 2;
// 自适应时需要对图片描边
if (customFixedType === ImageFixedType.AUTO) {
borderRect.set({
width: Math.min(borderRectWidth, originWidth * scaleX + strokeWidth),
height: Math.min(borderRectHeight, originHeight * scaleY + strokeWidth),
left: Math.max(-width / 2, imgLeft - strokeWidth),
top: Math.max(-height / 2, imgTop - strokeWidth),
});
}
img.set({
left: imgLeft,
top: imgTop,
width: originWidth,
height: originHeight,
scaleX,
scaleY,
});
};