96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
/*
|
||
* 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,
|
||
});
|
||
};
|