fabric-texture
Version:
This JavaScript library enables fast and efficient image distortion transformations using Canvas 2D.
1,522 lines (1,521 loc) • 58.6 kB
TypeScript
import { Bezier } from 'bezier-js';
/**
* 贴图变形区域的顶点类型枚举
* 用于标识变形区域四个角的位置。
*
* @enum {string}
*/
export declare enum VertexType {
/** 左上角顶点 */
TOP_LEFT = "tl",
/** 右上角顶点 */
TOP_RIGHT = "tr",
/** 左下角顶点 */
BOTTOM_LEFT = "bl",
/** 右下角顶点 */
BOTTOM_RIGHT = "br"
}
/**
* 变形区域类型
* 描述一个矩形变形区域,包含其四个顶点的坐标信息。
*
* @example
* const area: Area = {
* tl: { x: 0, y: 0 }, // 左上角坐标
* tr: { x: 100, y: 0 }, // 右上角坐标
* bl: { x: 0, y: 100 }, // 左下角坐标
* br: { x: 100, y: 100 } // 右下角坐标
* };
*/
export type Area = Record<VertexType, Coord>;
/**
* 变形区域边界方向类型
* 用于标识变形区域的四个边界方向。
*/
export type Direction = 'top' | 'bottom' | 'left' | 'right';
/**
* 分割点计算策略接口
* 用于自定义网格分割点的计算方法。当图像发生变形时,
* 该策略决定了如何在变形区域内部生成网格分割点,从而影响最终的变形效果。
*
* @example
* // 自定义一个简单的分割策略
* const myStrategy: Strategy = {
* name: 'custom-strategy',
* execute: (texture) => {
* // 在这里实现你的分割点计算逻辑
* return [[[{ x: 0, y: 0 }]]];
* }
* };
*
* // 应用策略
* texture.setSplitStrategy(myStrategy);
*
* @property {string} name - 策略的唯一标识名称
* @property {Function} execute - 执行分割点计算的方法
* @property {Texture} execute.texture - 当前的贴图实例对象
* @property {Coord[][][]} execute.return - 返回三维数组,表示每个分割区域的网格点坐标
* [区域行][区域列][网格点坐标]
*/
export type Strategy = {
name: string;
execute: (texture: Texture) => Coord[][][];
};
/**
* 贴图渲染配置选项
* 控制贴图的渲染效果和调试视图的显示。通过这些选项,
* 你可以自定义贴图的外观、性能和调试信息。
*
* @example
* const texture = new Texture(canvas);
* texture.setRenderOptions({
* padding: 10, // 设置10像素的留白边距
* showGrid: true, // 显示网格便于调试
* color: { r: 0, g: 255, b: 0, a: 1 } // 使用绿色网格
* });
*/
export interface TextureRenderOptions {
/**
* 贴图四周的留白距离(单位:像素)
* 常用于提供部分留白区域以避免溢出的变形内容被裁切
* @default 0
*/
padding: number;
/**
* 是否启用抗锯齿
* 启用后可以让图像边缘更平滑,但可能略微影响性能
* @default true
*/
antialias: boolean;
/**
* 是否启用安全渲染模式
* 启用后,当WebGL渲染失败时会自动降级使用Canvas 2D渲染
* @default true
* @remarks 建议在生产环境中保持启用状态
*/
safe: boolean;
/**
* 是否显示变形后的贴图
* 用于控制最终贴图的可见性
* @default true
*/
showTexture: boolean;
/**
* 是否显示变形网格
* 用于调试变形效果,可以直观地看到网格的变化
* @default false
*/
showGrid: boolean;
/**
* 是否显示网格的顶点
* 用于调试网格顶点的位置
* @default false
*/
showGridDot: boolean;
/**
* 网格和网格顶点的颜色配置
* @property {number} r - 红色通道值 (0-255)
* @property {number} g - 绿色通道值 (0-255)
* @property {number} b - 蓝色通道值 (0-255)
* @property {number} a - 透明度 (0-1)
* @default { r: 255, g: 0, b: 0, a: 1 } // 默认红色
* @remarks 在WebGL渲染模式下,透明度的变化可能会影响贴图的渲染效果
*/
color: {
r: number;
g: number;
b: number;
a: number;
};
}
/**
* 贴图变形数据结构
*
* 包含了描述贴图变形状态所需的全部数据。
*/
export type TransformData = {
/**
* 分割点的相对位置列表
*/
splitRatioPoints: Coord[];
/**
* 区域边界变形数据
*
* 三维数组,存储每个分割区域四条边的贝塞尔曲线控制点:
* - 第一维:区域行索引
* - 第二维:区域列索引
* - 第三维:该区域四条边(top/right/bottom/left)的控制点数组
*
* @example
* // 一个 2x2 网格的边界数据示例
* areaBound: [
* [
* { // 左上区域
* top: [{x: 0, y: 0}, ...], // 上边曲线的控制点
* right: [{x: 0, y: 0}, ...], // 右边曲线的控制点
* bottom: [{x: 0, y: 0}, ...], // 下边曲线的控制点
* left: [{x: 0, y: 0}, ...] // 左边曲线的控制点
* },
* // ... 右上区域
* ],
* // ... 下面一行的区域
* ]
*/
areaBound: Record<Direction, Coord[]>[][];
};
/**
* 贴图类
* 贴图类可以基于图像源创建其对应的变形工具对象实例,
* 该实例对象可以结合内部方法可以对图像施加变形并产出变形后的图形画布。
*
* @example
* const canvas = document.createElement('canvas');
* const ctx = canvas.getContext('2d');
* if (!ctx) return;
* // 绘制矩形
* ctx.fillRect(0, 0, canvas.width, canvas.height);
*
* // 创建 Texture 贴图类实例,传入画布作为图像源
* const texture = new Texture(canvas);
*
* // 将画布图像左上角移动到(50,50)的位置
* texture.setVertexCoord(0, 0, 'tl', { x: 50, y: 50 });
*
* // 生成变形后的图像画布并加入文档
* const textureCanvas = texture.create();
* document.body.appendChild(textureCanvas);
*/
export declare class Texture {
/**
* 图像源画布对象
* 存储原始图像数据的画布。如果构造函数传入的是 HTMLImageElement,
* 会自动创建一个新的画布并将图像绘制到其中,以避免对原始图像的修改。
*
* @example
* const img = new Image();
* img.src = 'example.jpg';
* img.onload = () => {
* const texture = new Texture(img); // 会自动创建画布
* };
*/
source: HTMLCanvasElement;
/**
* 图像分割点的相对位置列表
* 存储图像分割点的相对坐标(范围0-1)。这些点将图像划分为多个可变形区域,
* 每个分割点的坐标都是相对于图像尺寸的比例值。
*
* @remarks 请勿直接操作该列表,而是通过 addSplitPoint 方法来添加分割点。
*/
splitRatioPoints: Coord[];
/**
* 变形前的区域信息
* 二维数组,存储变形前每个分割区域的四个顶点坐标。
* 数组结构:[区域行][区域列],每个区域包含左上(tl)、右上(tr)、左下(bl)、右下(br)四个顶点。
*
* @example
* // 访问第一个区域的左上角坐标
* const topLeft = texture.initialSplitAreas[0][0].tl;
*/
initialSplitAreas: Area[][];
/**
* 初始网格点坐标
* 三维数组,存储变形前每个区域内部的网格点坐标。
* 这些点用于计算变形时的图像映射关系。
* 数组结构:[区域行][区域列][网格点列表]
*/
initialMeshPoints: Coord[][][];
/**
* 区域边界曲线
* 存储每个分割区域四条边的贝塞尔曲线对象。
*
* @remarks 请勿直接操作该列表对象,而是通过 setBoundCoords 方法调整指定曲线以实现区域边界的弯曲变形效果。
*
* @example
* // 调整第一个区域的上边界曲线
* texture.setBoundCoords(0, 0, 'top', [
* { x: 0, y: 0 },
* { x: 100, y: 100 },
* { x: 200, y: 100 },
* { x: 300, y: 0 }
* ]);
*/
areaBoundCurves: Record<Direction, Bezier>[][];
/**
* 变形后的网格曲线
* 存储变形后每个区域的网格线条,包括垂直和水平方向的贝塞尔曲线。
* 这些曲线决定了最终图像的变形效果。
*/
mesh: {
vertical: Bezier[];
horizontal: Bezier[];
}[][];
/**
* 变形后的网格点
* 存储变形后的网格点坐标。这些点的位置由分割策略计算得出,
* 不同的分割策略会产生不同的变形效果。
*
* @see Strategy 查看分割策略的详细说明
*/
meshPoints: Coord[][][];
/**
* 网格分割比例
* 控制网格的密度,值范围 0-1。这个值越小,网格越密,变形效果越精细,
* 但同时也会增加计算量。例如,值为 0.1 时,每个网格的最大尺寸为图像宽度的 10%。
*
* @default 0.05
*
* @example
* // 设置更密的网格以获得更精细的变形效果
* texture.setSplitUnit(0.02);
*/
splitUnit: number;
/**
* 分割点计算策略
* 定义如何计算变形区域内部的网格点位置。
* 默认使用内置的扭曲策略,你也可以通过 setSplitStrategy 方法设置自定义策略。
*
* @example
* // 设置自定义分割策略
* texture.setSplitStrategy({
* name: 'custom',
* execute: (texture) => {
* // 返回自定义的网格点计算结果
* return [[[{ x: 0, y: 0 }]]];
* }
* });
*/
splitStrategy: Strategy;
/**
* 渲染引擎类型
* 指定使用的渲染方式,支持 'canvas' 或 'webgl'。
* WebGL 模式性能更好,当设置了安全渲染配置时,在不支持 WebGL 的环境下会自动降级使用 Canvas。
*
* @default 'webgl'
*
* @example
* // 强制使用 Canvas 2D 渲染
* texture.useCanvasRender();
*/
renderEngine: 'canvas' | 'webgl';
/**
* 渲染选项
* 控制渲染过程的各种参数,包括留白、抗锯齿、调试网格显示等。
* 可以通过 setRenderOptions 方法动态修改这些选项。
*
* @see TextureRenderOptions 查看所有可用的渲染选项
*
* @example
* texture.setRenderOptions({
* padding: 20, // 设置20像素留白
* showGrid: true, // 显示调试网格
* antialias: true // 启用抗锯齿
* });
*/
renderOptions: TextureRenderOptions;
/**
* 图像源尺寸缓存
*
* 缓存当前图像源的尺寸信息,在尺寸变化时触发网格点重新计算。
*/
private _cacheSourceSize;
/**
* 源图像数据缓存
* 缓存原始图像的像素数据,用于优化 Web Worker 渲染时的性能。
* 当使用 Web Worker 进行渲染时,避免重复获取图像数据可以显著提升性能。
*
* @private
* @type {ImageData | null}
*/
private _cacheSourceImageData;
/**
* 输入画布缓存
* 当需要对输入图像进行尺寸调整时使用的缓存画布。
* 使用独立的缓存画布可以避免修改原始图像源,保证原始数据的完整性。
*
* @private
* @type {HTMLCanvasElement | null}
*
* @see setInputLimitSize 设置输入尺寸限制时会使用此缓存
*/
private _cacheInputCanvas;
/**
* 输出画布缓存
* 用于存储渲染结果的单例画布。
* 当多次渲染时,重用同一个画布可以减少内存占用。
*
* @private
* @type {HTMLCanvasElement | null}
*
* @see useInstanceCanvas 设置输出画布为单例模式
*/
private _cacheOutputCanvas;
/**
* 输入尺寸限制
* 限制输入图像的最大尺寸。
* 当图像尺寸超过限制时,会自动等比缩放到限制范围内。
*
* @private
* @type {{ width?: number; height?: number } | undefined}
*/
private _inputLimitSize;
/**
* 输入缩放比率
* 由输入尺寸限制导致的缩放比率。
* 当输入图像需要被缩放时,此值记录实际的缩放比例。
*
* @private
* @type {number}
* @default 1
*/
private _inputLimitScale;
/**
* 输出尺寸限制
* 限制输出画布的最大尺寸。
* 当变形后的图像尺寸超过限制时,会自动等比缩放到限制范围内。
*
* @private
* @type {{ width?: number; height?: number } | undefined}
*
* @remarks 设置合适的输出尺寸限制可以避免生成过大的画布而导致性能问题或无法渲染。
*/
private _outputLimitSize;
/**
* 输出缩放比率
* 由输出尺寸限制导致的缩放比率。
* 当输出画布需要被缩放时,此值记录实际的缩放比例。
*
* @private
* @type {number}
* @default 1
*/
private _outputLimitScale;
/**
* 构造贴图对象实例
*
* 创建一个新的贴图变形工具实例。你可以传入一个图像或画布作为源,
* 并可以选择性地设置初始的网格分割数量。
*
* @param source - 图像源,可以是 HTMLImageElement 或 HTMLCanvasElement
* 如果传入图像,会自动创建一个新画布并将图像绘制其中
* 如果传入画布,将直接使用该画布作为源
*
* @param rows - 初始横向分割数量
* - 必须是大于等于 1 的整数
* - 值为 1 时不进行横向分割
* - 值为 2 时会在中间添加一条分割线
* - 默认值: 1
*
* @param columns - 初始纵向分割数量
* - 必须是大于等于 1 的整数
* - 值为 1 时不进行纵向分割
* - 值为 2 时会在中间添加一条分割线
* - 默认值: 1
*
* @example
* // 用法:使用图像创建实例
* const img = new Image();
* img.src = 'example.jpg';
* img.onload = () => {
* const texture = new Texture(img);
* };
*
* // 用法:使用画布创建实例并设置 2x2 的初始网格分割
* const canvas = document.createElement('canvas');
* const texture = new Texture(canvas, 2, 2);
*/
constructor(source: HTMLCanvasElement | HTMLImageElement, rows?: number, columns?: number);
/**
* 获取最大分割像素大小
*
* 计算当前贴图允许的最大网格分割尺寸(以像素为单位)。
* 这个值由 splitUnit(分割比例)和图像宽度共同决定。
*
* @returns {number} 返回最大分割像素值
* - 当 splitUnit 为 0.1 时,返回图像宽度的 10%
* - 当 splitUnit 为 0.05 时,返回图像宽度的 5%
*
* @example
* // 假设图像宽度为 1000px,splitUnit 为 0.1
* const maxSize = texture.maxSplitUnitPixel; // 返回 100px
*
* @see splitUnit 查看分割比例的设置
*/
get maxSplitUnitPixel(): number;
/**
* 获取画布的实际缩放比率
*
* 返回当前画布相对于原始尺寸的缩放比例。
* 缩放比例由输入限制和输出限制共同影响:
* - 输入限制:处理大尺寸图像时的自动缩放
* - 输出限制:防止生成过大画布时的自动缩放
*
* @returns {{ x: number, y: number }} 返回 x 和 y 方向的缩放比例
* - 值为 1 表示原始大小
* - 值小于 1 表示被缩小
* - x 和 y 始终保持相同以避免变形
*
* @example
* const { x, y } = texture.scale;
* console.log(`当前画布被缩放至原始尺寸的 ${x * 100}%`);
*/
get scale(): {
x: number;
y: number;
};
/**
* 内置扭曲分隔策略
*
* 这是一个默认的网格分割策略,通过计算横纵向贝塞尔曲线的交点中点来生成网格点。
* 该策略能够很好地表现出平面扭曲的效果,特别适合用于:
* - 图像弯曲变形
* - 透视变形
* - 波浪效果
*
* @param texture - 当前的贴图实例
* @returns 返回三维数组,包含所有分割区域的网格点坐标
* - 第一维:区域行索引
* - 第二维:区域列索引
* - 第三维:该区域内的网格点列表
*
* @example
* // 1. 使用默认策略
* const texture = new Texture(image);
* // 默认已经使用此策略,无需额外设置
*
* // 2. 显式设置此策略
* texture.setSplitStrategy({
* name: 'default',
* execute: Texture.strategy
* });
*
* @remarks
* 该策略的工作原理:
* 1. 遍历每个分割区域
* 2. 计算区域内横向和纵向贝塞尔曲线的交点
* 3. 取每对交点的中点作为网格点
* 4. 这样可以保证网格点均匀分布,且能跟随曲线变形
*/
static strategy(texture: Texture): Coord[][][];
/**
* 压缩变形数据
*
* 将贴图的变形数据压缩为 base64 字符串格式,便于传输和存储。
* 压缩的数据包含:
* - 分割点信息(splitRatioPoints)
* - 区域边界变形信息(areaBound)
*
* @param transformData - 需要压缩的变形数据
* 包含分割点和边界变形信息的对象
* @returns 返回压缩后的 base64 字符串
*
* @example
* // 1. 获取当前贴图的变形数据
* const transformData = texture.getTransformData();
*
* // 2. 压缩数据
* const compressed = Texture.compressTransformData(transformData);
*
* @see decompressTransformData 解压缩变形数据
* @see getTransformData 获取变形数据
*/
static compressTransformData(transformData: TransformData): string;
/**
* 解压缩变形数据
*
* 将通过 compressTransformData 压缩的数据还原为可用的变形数据对象。
* 解压缩后可以直接用于重建贴图的变形状态。
*
* @param base64String - 通过 compressTransformData 压缩得到的 base64 字符串
*
* @returns {object} 解压缩后的变形数据对象
* @returns {Coord[]} splitRatioPoints - 分割点数组,每个点包含相对坐标 (x,y)
* @returns {Record<Direction, Coord[]>[][]} boundData - 边界变形数据,包含每个区域的边界信息
*
* @example
* // 1. 解压缩数据
* const { splitRatioPoints, boundData } = Texture.decompressTransformData(data);
*
* // 2. 应用变形数据
* texture.setTransformData(splitRatioPoints, boundData);
*
* @see compressTransformData 压缩变形数据
* @see setTransformData 应用变形数据
*/
static decompressTransformData(base64String: string): TransformData;
/**
* 初始化分割比例点
*
* 根据指定的行列数创建初始的分割点网格。每个分割点使用相对坐标(0-1范围内),
* 这些点将被用于将图像划分为多个可变形区域。
*
* @param rows - 横向分割数量
* - 必须是大于等于 1 的整数
* - 实际分割线数量为 rows - 1
* - 例如:rows = 2 时会在中间添加一条横向分割线
* - 默认值:1(不进行横向分割)
*
* @param columns - 纵向分割数量
* - 必须是大于等于 1 的整数
* - 实际分割线数量为 columns - 1
* - 例如:columns = 2 时会在中间添加一条纵向分割线
* - 默认值:1(不进行纵向分割)
*
* @returns 返回分割点坐标数组,每个坐标都是相对于图像尺寸的比例值(0-1)
*
* @example
* // 创建 2x2 的网格(在中间添加一条横向和一条纵向分割线)
* const points = this._initializeGridPoints(2, 2);
* // 返回 [{ x: 0.5, y: 0.5 }]
*/
private _initializeGridPoints;
/**
* 初始化分割区域
*
* 基于分割比例点将图像划分为多个矩形区域。每个区域包含四个顶点坐标,
* 这些坐标是实际的像素位置(不是比例值)。
*
* @returns 返回二维数组,包含所有分割区域的信息
* - 第一维:行索引
* - 第二维:列索引
* - 每个区域包含 tl/tr/bl/br 四个顶点的像素坐标
*
* @example
* // 假设图像尺寸为 100x100,有一个分割点 { x: 0.5, y: 0.5 }
* const areas = this._initializeGridAreas();
* // 返回 2x2 的区域网格,每个区域大小为 50x50
*/
private _initializeGridAreas;
/**
* 计算区域边界的采样点
*
* 为贝塞尔曲线计算采样点的位置。采样点数量根据区域大小自动调整,
* 以确保变形效果的平滑性和性能的平衡。
*
* @param area - 需要计算采样点的区域
* 包含 tl(左上)、tr(右上)、bl(左下)、br(右下)四个顶点
*
* @returns 返回水平和垂直方向的采样点位置
* - hts:水平方向的采样点位置数组(0-1)
* - vts:垂直方向的采样点位置数组(0-1)
*
* @remarks
* t 值在贝塞尔曲线中表示曲线上的相对位置:
* - t = 0:曲线起点
* - t = 1:曲线终点
* - 0 < t < 1:曲线上的对应点
*
* @example
* const area = {
* tl: { x: 0, y: 0 },
* tr: { x: 100, y: 0 },
* bl: { x: 0, y: 100 },
* br: { x: 100, y: 100 }
* };
* const { hts, vts } = this._calculateSamplingPoints(area);
* // 根据区域大小返回适当数量的采样点
*/
private _calculateSamplingPoints;
/**
* 初始化分割区域内的网格点
*
* 根据初始分割区域生成网格点。这些点将用于:
* 1. 构建变形时的参考网格
* 2. 计算纹理映射关系
* 3. 生成最终的变形效果
*
* @returns 返回三维数组,包含所有分割区域的网格点:
* - 第一维:区域行索引
* - 第二维:区域列索引
* - 第三维:该区域内的网格点列表
*
* @example
* // 假设有一个 2x2 的分割区域,每个区域内生成 3x3 的网格点
* const meshPoints = this._initializeGridMeshPoints();
* // 返回结构:[[[p1,p2,p3...], [p1,p2,p3...]], [[p1,p2,p3...], [p1,p2,p3...]]]
*
* @see _calculateSamplingPoints 获取采样点位置
*/
private _initializeGridMeshPoints;
/**
* 初始化边界贝塞尔曲线控制点
*
* 为每个分割区域的四条边界创建三阶贝塞尔曲线的控制点。
* 初始状态下,这些曲线都是直线,但可以通过调整控制点使其变成曲线。
*
* @param areas - 分割区域数组,包含每个区域的四个顶点坐标
*
* @returns 返回三维数组,包含所有区域边界的贝塞尔曲线控制点:
* - 第一维:区域行索引
* - 第二维:区域列索引
* - 第三维:该区域四个方向(top/right/bottom/left)的控制点数组
* 每个方向包含 4 个点:起点、第一控制点、第二控制点、终点
*
* @remarks
* 三阶贝塞尔曲线的四个控制点作用:
* - P0(起点):曲线的起始位置
* - P1(第一控制点):控制起点处的切线方向和曲率
* - P2(第二控制点):控制终点处的切线方向和曲率
* - P3(终点):曲线的结束位置
*
* @example
* const areas = [
* [{
* tl: {x: 0, y: 0},
* tr: {x: 100, y: 0},
* bl: {x: 0, y: 100},
* br: {x: 100, y: 100}
* }]
* ];
* const curvePoints = this._initializeBoundaryControlPoints(areas);
*/
private _initializeBoundaryControlPoints;
/**
* 生成区域内的分割曲线网格
*
* 根据给定的边界曲线和采样点位置,生成区域内部的网格曲线。
* 这些曲线构成了变形的基础框架,决定了图像的变形方式。
*
* @param bounds - 区域四条边界的贝塞尔曲线对象
* @param hts - 水平方向的采样点位置数组(范围:0-1)
* @param vts - 垂直方向的采样点位置数组(范围:0-1)
*
* @returns 返回包含水平和垂直方向网格曲线的对象:
* - vertical: 垂直方向的贝塞尔曲线数组
* - horizontal: 水平方向的贝塞尔曲线数组
*
* @remarks
* 网格生成过程:
* 1. 在水平方向上,根据 hts 在上下边界间插值生成垂直曲线
* 2. 在垂直方向上,根据 vts 在左右边界间插值生成水平曲线
* 3. 所有曲线都保持贝塞尔曲线的特性,确保平滑过渡
*
* @example
* const curves = this._generateAreaMeshCurves(
* bounds,
* [0, 0.5, 1], // 在水平方向上分成两份
* [0, 0.5, 1] // 在垂直方向上分成两份
* );
*/
private _generateAreaMeshCurves;
/**
* 生成分割区域的内部网格曲线
*
* 根据边界贝塞尔曲线生成区域内部的网格曲线。这些曲线将用于:
* 1. 构建变形的基础网格框架
* 2. 计算纹理映射的参考点
* 3. 实现平滑的变形效果
*
* @param areaBoundCurves - 区域边界曲线数组
* - 第一维:行索引
* - 第二维:列索引
* - 第三维:每个区域的四条边界贝塞尔曲线(top/right/bottom/left)
*
* @returns 返回三维数组,包含所有区域的网格曲线:
* - 第一维:行索引
* - 第二维:列索引
* - 第三维:该区域的垂直和水平方向的贝塞尔曲线
* - vertical: 垂直方向的曲线数组
* - horizontal: 水平方向的曲线数组
*
* @see Bezier bezier-js库的曲线对象,用于处理贝塞尔曲线的计算
* @see _generateAreaMeshCurves 生成单个区域的网格曲线
* @see _calculateSamplingPoints 计算采样点位置
*/
private _generateMeshCurves;
/**
* 设置变形网格分割的最大比例
*
* 控制网格分割的精细程度。较小的值会产生更密集的网格,
* 从而实现更精细的变形效果,但同时也会增加计算量。
*
* @param splitUnit - 网格分割的最大比例值
* - 范围:0-1 之间的数值
* - 值为 0.1 时,单个网格最大为图像宽度的 10%
* - 值为 0.05 时,单个网格最大为图像宽度的 5%
* - 值大于 1 或小于等于 0 时会被重置为 1
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 设置较密的网格以获得更精细的变形效果
* texture.setSplitUnit(0.05);
*
* // 设置较疏的网格以提高性能
* texture.setSplitUnit(0.2);
*/
setSplitUnit(splitUnit: number): this;
/**
* 设置变形分割点的计算策略
*
* 自定义网格分割点的计算方法,通过不同的策略可以实现不同的变形效果。
*
* @param strategy - 分割点计算策略对象
* - name: 策略名称,用于标识不同的策略,自定义标识
* - execute: 策略的执行函数,接收 texture 实例作为参数
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 使用自定义策略
* texture.setSplitStrategy({
* name: 'custom',
* execute: (texture) => {
* // 返回自定义的网格点计算结果
* return [[[{ x: 0, y: 0 }]]];
* }
* });
*
* @see Texture.strategy 查看默认策略的实现
*/
setSplitStrategy(strategy: Strategy): this;
/**
* 设置输入画布的尺寸限制
*
* 当处理大尺寸图像时,可以通过此方法限制输入画布的最大尺寸,
* 系统会自动将图像等比缩放到限制范围内进行处理,以提高性能和减少内存占用。
*
* @param limitSize - 尺寸限制配置对象
* - width?: number - 最大宽度(像素)
* - height?: number - 最大高度(像素)
* - 传入 undefined 则取消限制,使用原始尺寸
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 限制输入图像最大尺寸为 1000x1000
* texture.setInputLimitSize({
* width: 1000,
* height: 1000
* });
*
* // 只限制宽度,高度自动等比缩放
* texture.setInputLimitSize({
* width: 1000
* });
*
* // 取消尺寸限制
* texture.setInputLimitSize(undefined);
*
* @remarks
* 性能建议:
* 1. 对于大尺寸图像(如>2000px),建议设置合适的限制以提高性能
* 2. 图像会被等比缩放,保持原始宽高比
* 3. 实际处理时会使用缓存画布,避免重复缩放
*/
setInputLimitSize(limitSize: {
width?: number;
height?: number;
} | undefined): this;
/**
* 设置输出画布的尺寸限制
*
* 限制变形后输出画布的最大尺寸。当变形导致画布尺寸过大时,
* 系统会自动将结果等比缩放到限制范围内,避免因内存限制导致渲染失败。
*
* @param limitSize - 尺寸限制配置对象
* - width?: number - 最大宽度(像素)
* - height?: number - 最大高度(像素)
* - 传入 undefined 则取消限制,使用原始尺寸
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 限制输出画布最大尺寸为 2000x2000
* texture.setOutputLimitSize({
* width: 2000,
* height: 2000
* });
*
* // 只限制宽度,高度自动等比缩放
* texture.setOutputLimitSize({
* width: 2000
* });
*
* // 取消尺寸限制(注意:可能导致大尺寸图像渲染失败)
* texture.setOutputLimitSize(undefined);
*
* @remarks
* 重要提示:
* 1. 不设置限制时,变形后的大尺寸图像可能超出浏览器的 Canvas 尺寸限制导致渲染失败或显示空白
* 2. 建议根据实际使用场景设置合理的限制值
* 3. 输出尺寸会影响渲染性能和内存占用
*/
setOutputLimitSize(limitSize: {
width?: number;
height?: number;
} | undefined): this;
/**
* 设置使用 Canvas 2D 进行渲染
*
* 将渲染引擎设置为 Canvas 2D 模式。这种模式具有以下特点:
* - 兼容性最好,支持所有现代浏览器
* - 适合处理中小尺寸图像的变形
* - 性能相对 WebGL 较低,但稳定性高
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 创建实例并设置为 Canvas 2D 渲染
* const texture = new Texture(image)
* .useCanvasRender()
* .create();
*
* @see useWebGLRender 切换到 WebGL 渲染模式
*/
useCanvasRender(): this;
/**
* 设置使用 WebGL 进行渲染
*
* 将渲染引擎设置为 WebGL 模式。这种模式具有以下特点:
* - 性能最佳,特别适合处理大尺寸图像
* - 支持 GPU 加速,渲染速度快
* - 内存占用相对较低
*
* @returns 返回实例本身,支持链式调用
*
* @remarks
* 重要说明:
* 1. 当设置为 安全渲染模式 时,当浏览器不支持 WebGL或某些特殊情况下渲染失败时,会自动降级使用 Canvas 2D
* 2. 建议在处理大尺寸图像时优先使用此模式
*
* @example
* // 创建实例并设置为 WebGL 渲染
* const texture = new Texture(image)
* .useWebGLRender()
* .create();
*
* @see useCanvasRender 切换到 Canvas 2D 渲染模式
*/
useWebGLRender(): this;
/**
* 设置使用单例画布进行渲染
*
* 指定一个固定的画布用于渲染输出。这在以下场景特别有用:
* - 需要复用同一个画布进行多次渲染
* - 需要直接操作输出画布的内容
*
* @param canvas - 指定的画布元素
* - 传入 null 或不传参数时会创建新的画布
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 1. 使用已有画布
* const canvas = document.createElement('canvas');
* texture.useInstanceCanvas(canvas);
*
* // 2. 创建新画布
* texture.useInstanceCanvas();
*
* // 3. 在动画循环中复用画布
* const canvas = document.createElement('canvas');
* texture.useInstanceCanvas(canvas);
*
* function animate() {
* // 每帧都在同一个画布上更新内容
* texture.create();
* requestAnimationFrame(animate);
* }
*
* @remarks
* 性能提示:
* - 在需要频繁更新的场景中,使用单例画布可以减少内存分配
* - 避免在每次渲染时都创建新的画布实例
*/
useInstanceCanvas(canvas?: HTMLCanvasElement | null): this;
/**
* 设置渲染配置选项
*
* 配置贴图渲染的各种参数。
*
* @param options - 渲染配置对象,可以部分覆盖默认配置
* - padding: number - 留白距离(像素),默认 0
* - antialias: boolean - 抗锯齿效果,默认 true
* - safe: boolean - 安全渲染模式(仅WebGL模式有效,WebGL失败时自动降级),默认 true
* - showTexture: boolean - 是否显示贴图,默认 true
* - showGrid: boolean - 是否显示网格,默认 false
* - showGridDot: boolean - 是否显示网格顶点,默认 false
* - color: { r, g, b, a } - 网格和顶点颜色,默认红色
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 渲染设置
* texture.setRenderOptions({
* padding: 10,
* showTexture: true
* });
*
* @remarks
* 使用建议:
* 1. 生产环境建议保持 safe 为 true
* 2. padding 可用于预留变形溢出空间
*/
setRenderOptions(options: Partial<TextureRenderOptions>): this;
/**
* 获取变形后图像的包围盒信息
*
* 计算变形后图像的边界范围和偏移量。
*
* @returns {object} 包围盒信息
* @returns {number} offsetX - X轴偏移量
* @returns {number} offsetY - Y轴偏移量
* @returns {number} width - 包围盒的宽度(像素),包含 padding
* @returns {number} height - 包围盒的高度(像素),包含 padding
*
* @example
* // 获取变形后图像的尺寸和位置信息
* const { width, height, offsetX, offsetY } = texture.getBoundingBoxInfo();
*
* // 使用这些信息设置画布尺寸
* canvas.width = width;
* canvas.height = height;
*
* // 调整图像位置
* ctx.translate(offsetX, offsetY);
*
* @see setRenderOptions 设置 padding 值
*/
getBoundingBoxInfo(): {
offsetX: number;
offsetY: number;
width: number;
height: number;
};
/**
* 构建类直线的三阶贝塞尔曲线
*
* 将两点之间的直线转换为三阶贝塞尔曲线表示。该方法通过在直线上均匀分布控制点,
* 创建一个视觉上与直线相同但具有贝塞尔曲线特性的路径。
*
* @param p0 - 起始点坐标
* @param p1 - 终止点坐标
*
* @returns 返回包含 4 个点的数组,表示三阶贝塞尔曲线的控制点:
* [起点, 第一控制点, 第二控制点, 终点]
*/
private _createLinearBezier;
/**
* 合并两条贝塞尔曲线
*
* 将两条贝塞尔曲线平滑地合并为一条。这个方法在删除分割点时使用,
* 用于确保合并后的曲线保持平滑过渡,避免出现突变或尖角。
*
* @param curve1Points - 第一条曲线的控制点数组 [p0, p1, p2, p3]
* @param curve2Points - 第二条曲线的控制点数组 [p0, p1, p2, p3]
*
* @returns 返回合并后的贝塞尔曲线控制点数组 [p0, p1, p2, p3]
*
* @see _createLinearBezier 用于创建初始的直线型贝塞尔曲线
*/
private _mergeBezierCurves;
/**
* 找到连接顶点的另一个顶点
*
* 在变形网格中,每个顶点都与其他顶点相连。这个方法用于获取与当前顶点相连的另一个顶点的位置信息。
* 例如:当移动一个顶点时,需要同时更新与之相连的顶点,以保持网格的连续性。
*
* @param direction - 当前边的方向
* - 'top': 上边
* - 'bottom': 下边
* - 'left': 左边
* - 'right': 右边
* @param position - 在当前边上的位置
* - 'first': 边的起点
* - 'last': 边的终点
*
* @returns 返回相连顶点的信息
* - direction: 相连顶点所在边的方向
* - position: 相连顶点在该边上的位置
*/
private _findConnectedVertex;
/**
* 更新某个顶点的坐标
*
* 当移动网格的某个顶点时,需要同时更新:
* 1. 该顶点所在的两条边的贝塞尔曲线
* 2. 与该顶点相连的另一个顶点所在的边的贝塞尔曲线
* 这样可以确保网格的连续性和平滑性。
*
* @param rowIndex - 顶点所在的行索引
* @param colIndex - 顶点所在的列索引
* @param type - 顶点类型(tl/tr/bl/br)
* @param coord - 新的顶点坐标 { x, y }
* @param redistribute - 是否重新分配曲线控制点
* - true: 重新计算所有控制点(平滑过渡)
* - false: 仅更新端点(保持原有曲率)
* - 默认值:true
*
* @example
* // 移动左上角顶点到新位置
* this._setSingleAreaVertexCoord(
* 0, // 第一行
* 0, // 第一列
* VertexType.TOP_LEFT, // 左上角
* { x: 100, y: 100 }, // 新坐标
* true // 重新分配控制点
* );
*
* @see _findConnectedVertex 获取相连顶点的信息
* @see _createLinearBezier 创建贝塞尔曲线的控制点
*/
private _setSingleAreaVertexCoord;
/**
* 更新单个变形后的贴图顶点的坐标
*
* 移动网格的某个顶点,并自动同步所有相关联的顶点以保持网格的连续性。
*
* @param rowIndex - 目标区域的行索引(从0开始)
* @param colIndex - 目标区域的列索引(从0开始)
* @param vertexType - 要移动的顶点类型
* - 'tl': 左上角顶点
* - 'tr': 右上角顶点
* - 'bl': 左下角顶点
* - 'br': 右下角顶点
* @param coord - 顶点的新坐标
* - x: X坐标(像素)
* - y: Y坐标(像素)
* @param redistribute - 是否重新计算贝塞尔曲线控制点
* - true: 重新计算以实现平滑过渡(默认)
* - false: 仅更新端点,保持曲线形状
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 将区域(0,0)的左上角顶点移动到(100,100)
* texture.setVertexCoord(
* 0, // rowIndex
* 0, // colIndex
* 'tl', // vertexType
* { x: 100, y: 100 }, // 新位置
* true // 重新计算曲线
* );
*
* @remarks
* 注意事项:
* 1. 移动顶点会影响所有相连的顶点和曲线
* 2. 设置 redistribute=false 可以在移动时保持曲线形状
* 3. 无效的行列索引会被静默忽略
*
* @see _setSingleAreaVertexCoord 内部顶点更新方法
*/
setVertexCoord(rowIndex: number, colIndex: number, vertexType: `${VertexType}`, coord: Coord, redistribute?: boolean): this;
/**
* 更新某个方向边的曲线坐标
*
* 修改区域边界的贝塞尔曲线形状。通过设置新的控制点,
* 可以改变边界的弯曲程度和形状,同时保持与相邻区域的连接。
*
* @param rowIndex - 目标区域的行索引(从0开始)
* @param colIndex - 目标区域的列索引(从0开始)
* @param direction - 要更新的边界方向
* - 'top': 上边界
* - 'right': 右边界
* - 'bottom': 下边界
* - 'left': 左边界
* @param coords - 贝塞尔曲线的4个控制点坐标
* - p0: 起始点坐标
* - pm0: 第一控制点坐标
* - pm1: 第二控制点坐标
* - p1: 终点坐标
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 创建一个S形的上边界曲线
* texture.setBoundCoords(
* 0, // rowIndex
* 0, // colIndex
* 'top', // direction
* [
* { x: 0, y: 0 }, // 起始点
* { x: 30, y: 20 }, // 控制点1
* { x: 70, y: -20 }, // 控制点2
* { x: 100, y: 0 } // 终点
* ]
* );
*
* @see setVertexCoord 用于更新单个顶点
*/
setBoundCoords(rowIndex: number, colIndex: number, direction: Direction, coords: [p0: Coord, pm0: Coord, pm1: Coord, p1: Coord]): this;
/**
* 获取所有区域的边界曲线数据
*
* 导出所有变形区域的边界曲线控制点数据。
*
* @param callback - 自定义数据处理函数(可选)
* - rowIndex: 区域的行索引
* - colIndex: 区域的列索引
* - direction: 边界方向('top'|'right'|'bottom'|'left')
* - bezier: 贝塞尔曲线对象,包含控制点信息
* - 默认返回原始控制点数组
*
* @returns 返回三维数组,包含所有区域边界的控制点数据:
* - 第一维:区域行索引
* - 第二维:区域列索引
* - 第三维:该区域四个方向的控制点数组
* - top: 上边界的控制点 [起点,控制点1,控制点2,终点]
* - right: 右边界的控制点
* - bottom: 下边界的控制点
* - left: 左边界的控制点
*
* @remarks
* 返回的控制点数组格式:
* [
* [ // 第一行区域
* { // 第一列区域
* top: [{x,y}, {x,y}, {x,y}, {x,y}], // 4个控制点
* right: [{x,y}, {x,y}, {x,y}, {x,y}], // 4个控制点
* bottom: [{x,y}, {x,y}, {x,y}, {x,y}], // 4个控制点
* left: [{x,y}, {x,y}, {x,y}, {x,y}] // 4个控制点
* },
* // ... 更多列
* ],
* // ... 更多行
* ]
*
* @see setBoundCoords 设置单个区域的边界曲线
* @see getTransformData 获取完整的变形数据
*/
getAreaBoundCoords(callback?: (rowIndex: number, colIndex: number, direction: Direction, bezier: Bezier) => Coord[]): Record<Direction, Coord[]>[][];
/**
* 初始化区域边界的贝塞尔曲线对象
*
* 将输入的边界点数据转换为贝塞尔曲线对象。
*
* @param areaBoundCoords - 边界点数据,三维数组结构:
* - 第一维:行索引
* - 第二维:列索引
* - 第三维:每个区域的四条边界的控制点数组
* - top: 上边界 [起点,控制点1,控制点2,终点]
* - right: 右边界
* - bottom: 下边界
* - left: 左边界
*
* @returns 返回贝塞尔曲线对象数组,结构与输入数据相同:
* - 第一维:行索引
* - 第二维:列索引
* - 第三维:每个区域的四条贝塞尔曲线对象
*
* @see Bezier bezier-js库的曲线对象,用于处理贝塞尔曲线的计算
*/
private _initializeAreaBoundCurves;
/**
* 获取当前贴图的变形数据
*
* 导出当前贴图的变形状态,包括分割点和边界曲线数据。
* 这些数据可以用于:
* 1. 保存当前的变形状态
* 2. 在其他贴图上复制相同的变形效果
* 3. 序列化变形数据用于传输或存储
*
* @returns {TransformData} 变形数据对象
* - splitRatioPoints: 分割点数组,每个点的坐标都是相对于原始图像尺寸的比例值(0-1)
* - areaBound: 边界曲线数据,包含每个分割区域四条边的贝塞尔曲线控制点
*
* @see setTransformData 使用变形数据设置贴图
*/
getTransformData(): TransformData;
/**
* 设置贴图的变形数据
*
* 使用指定的变形数据更新贴图的状态。可以用于:
* 1. 还原之前保存的变形状态
* 2. 在多个贴图之间复制变形效果
* 3. 使用预设的变形模板
*
* @param splitPoints - 分割点数组,每个点的坐标应该是相对于原始图像尺寸的比例值(0-1)
* @param areaBound - 边界曲线数据(可选)
* - 如果提供,将直接使用这些数据设置边界曲线
* - 如果为 null,将根据分割点自动生成直线边界
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 1. 使用完整的变形数据
* const data = anotherTexture.getTransformData();
* texture.setTransformData(data.splitRatioPoints, data.areaBound);
*
* // 2. 仅设置分割点,使用默认直线边界,将还原回无扭曲状态
* texture.setTransformData([
* { x: 0.5, y: 0.5 } // 在图像中心添加一个分割点
* ]);
*
* @see getTransformData 获取变形数据
* @see resetTransformData 重置变形状态
*/
setTransformData(splitPoints: Coord[], areaBound?: Record<Direction, Coord[]>[][] | null): this;
/**
* 重置贴图的变形状态
*
* 清除所有变形效果,将贴图重置为指定行列数的网格。
* 这个方法会:
* 1. 清除所有分割点
* 2. 重置所有边界为直线
* 3. 重新创建指定数量的网格
*
* @param rows - 重置后的网格行数,默认为 1
* @param columns - 重置后的网格列数,默认为 1
*
* @returns 返回实例本身,支持链式调用
*
* @example
* // 重置为默认状态(1x1 网格)
* texture.resetTransformData();
*
* // 重置为 2x3 的网格
* texture.resetTransformData(2, 3);
*
* @see setTransformData 设置变形数据
*/
resetTransformData(rows?: number, columns?: number): this;
/**
* 检查贴图是否处于初始未变形状态
*
* 判断当前贴图是否完全处于未变形的初始状态。
* 满足以下所有条件时返回 true:
* 1. 没有任何分割点(splitRatioPoints.length === 0)
* 2. 所有边界都是直线(没有曲线变形)
* 3. 边界位置与原始图像边界重合
*
* @returns {boolean}
* - true: 贴图处于完全未变形的初始状态
* - false: 贴图已经发生了变形或分割
*/
isNoneTransform(): boolean;
/**
* 检测指定坐标点是否在变形后的贴图区域内
*
* 判断一个坐标点是否落在变形后的贴图区域内,并返回详细的位置信息。
* 这个方法通常用于:
* 1. 实现鼠标交互功能
* 2. 检测点击位置
* 3. 获取点击区域的详细信息
*
* @param point - 要检测的坐标点
* - x: X坐标(像素)
* - y: Y坐标(像素)
*
* @returns 如果点在区域内,返回包含以下信息的对象:
* - rowIndex: 所在区域的行索引
* - colIndex: 所在区域的列索引
* - row: 所在网格的行号
* - col: 所在网格的列号
* - before: 原始网格的四个顶点坐标 [左上,右上,右下,左下]
* - after: 变形后网格的四个顶点坐标 [左上,右上,右下,左下]
* - clickPart: 归属区域的哪个三角图元(0:上三角图元, 1:下三角图元)
* 如果点不在变形图像区域内,返回 null
*
* @example
* // 检测鼠标点击位置
* canvas.addEventListener('click', (e) => {
* const info = texture.contains({
* x: e.clientX - canvas.offsetLeft,
* y: e.clientY - canvas.offsetTop
* });
*
* if (info) {
* console.log('点击位置在区域内:', info);
* }
* });
*/
containsPoint(point: Coord): {
rowIndex: number;
colIndex: number;
row: number;
col: number;
before: Coord[];
after: Coord[];
clickPart: 0 | 1;
} | null;
/**
* 在指定位置添加分割点
*
* 在贴图的指定区域添加一个新的分割点,将区域分割成更小的子区域。
*
* @param rowIndex - 目标区域的行索引
* @param colIndex - 目标区域的列索引
* @param splitPoint - 分割点的坐标
* - x: X坐标(像素)
* - y: Y坐标(像素)
* @param tolerate - 分割点的容差值(默认0.05)
* - 范围:0-1之间
* - 当分割点距离边界的距离小于容差时,会自动吸附到边界
* - 较大的容差值可以防止在边界附近产生过小的分割区域
*
* @example
* // 在第一个区域(0,0)的中心位置添加分割点,分割后该区域会变成2x2的区域
* const area = texture.initialSplitAreas[0][0];
* texture.addSplitPoint(
* 0, // rowIndex
* 0, // colIndex
* { // 区域中心点
* x: (area.tl.x + area.br.x) / 2,
* y: (area.tl.y + area.br.y) / 2
* },
* 0.1 // 10%的容差
* );
*
* @remarks
* 注意事项:
* 1. 分割点会根据容差值自动吸附到边界
* 2. 添加分割点会影响相邻区域的边界形状,特别是已扭曲的区域
* 3. 过多的分割点可能会影响性能
*
* @see removeSplitPoints 删除分割点
*/
addSplitPoint(rowIndex: number, colIndex: number, splitPoint: Coord, tolerate?: number): void;
/**
* 删除指定位置的分割点
*
* 删除一个或多个分割点,并自动合并相关的区域。
*
* @param list - 要删除的分割点位置数组
* - 每个元素是一个包含行列索引的元组 [行索引, 列索引]
* - 行列索引从 0 开始计数
*
* @example
* // 删除区域分割点
* texture.removeSplitPoints([
* [1, 1], // 删除第2行第2列的分割点
* [2, 2], // 删除第3行第3列的分割点
* ]);
*
* @remarks
* 重要说明:
* 1. 以下情况的删除操作无效:
* - 图像四个角的顶点
* - 超出区域范围的点
* - 不存在的分割点
*
* 2. 删除分割点的处理顺序:
* - 先合并行(从下往上)
* - 再合并列(从右往左)
* - 自动处理边界曲线的平滑过渡
*
* 3. 性能考虑:
* - 建议一次性删除多个分割点,而不是多次调用删除单个点
*
* @see addSplitPoint 添加分割点
*/
removeSplitPoints(list: [splitRowIndex: number, splitColIndex: number][]): void;
/**
* 遍历变形网格中的所有四边形单元
*
* 遍历贴图变形网格中的每个四边形单元,并提供其变形前后的顶点信息。
*
* @param handler - 处理每个四边形单元的回调函数
* 接收以下参数:
* - newVertexs: 变形后的四个顶点坐标 [左上,右上,右下,左下]
* - oldVertexs: 变形前的四个顶点坐标 [左上,右上,右下,左下]
* - row: 在当前区域内的行索引
* - col: 在当前区域内的列索引
* - rowIndex: 所属变形区域的行索引
* - colIndex: 所属变形区域的列索引
*
* @example
* // 遍历所有网格单元并打印其位置信息
* texture.forEachSplitArea((newVertexs, oldVertexs, row, col, rowIndex, colIndex) => {
* console.log(`区域[${rowIndex},${colIndex}] 所在内部分割的网格位置[${row},${col}]:`);
* console.log('变形前:', oldVertexs);
* console.log('变形后:', newVertexs);
* });
*/
forEachSplitArea(handler: (newVertexs: [leftTop: Coord, rightTop: Coord, bottomRight: Coord, bottomLeft: Coord], oldVertexs: [leftTop: Coord, rightTop: Coord, bottomRight: Coord, bottomLeft: Coord], row: number, col: number, rowIndex: number, colIndex: number) => void): void;
/**
* 生成贴图渲染所需的配置参数
*
* 这个方法会处理以下内容:
* 1. 计算变形网格和分割点
* 2. 处理画布尺寸限制和缩放
* 3. 准备渲染所需的画布和参数
*
* @returns 返回渲染所需的配置对象:
* - inputCanvas: 输入画布(原始图像或缓存的缩放画布)
* - outputCanvas: 输出画布(指定的实例画布或null)
* - options: 渲染配置参数
* - x: 渲染偏移量X
* - y: 渲染偏移量Y
* - width: 渲染宽度
* - height: 渲染高度
* - sourceScale: 输入画布的缩放比例
* - destinationScale: 输出画布的缩放比例
*/
private _generateCreateOptions;
/**
* 获取输入画布的像素数据
*
* 获取输入画布的原始像素数据,用于在 Web Worker 中进行渲染计算。
*
* @throws {Error} 当无法获取画布的 2D 上下文时抛出错误
*
* @returns {ImageData} 返回画布的像素数据对象
*/
private _getInputCanvasImageData;
/**
* 生成变形后的贴图画布
*
* 根据当前的变形参数,生成一个新的画布或在指定画布上渲染变形后的图像。
*
* @returns {HTMLCanvasElement} 返回变形后的画布元素
*
* @throws {Error}
* - 当渲染失败且未启用安全模式时抛出错误
* - 当画布创建失败时抛出错误
*
* @example
* const canvas = texture.create();
* document.body.appendChild(canvas);
*
* @remarks
* 性能建议:
* 1. 如果需要频繁更新,建议使用 useInstanceCanvas 复用输出画布
* 2. 如果遇到大图变形的性能问题,可以尝试切换渲染引擎或使用 createWithWorker
*
* @see useInstanceCanvas 设置复用画布
* @see createWithWorker 在 Worker 中异步渲染
*/
create(): HTMLCanvasElement;
/**
* 在 Web Worker 中异步生成变形贴图画布
*
* 在独立线程中执行贴图变形和渲染操作,避免阻塞主线程。
*
* @returns {Promise<HTMLCanvasElement>} 返回一个 Promise,解析为渲染后的画布元素
*
* @throws {Error}
* - 当 Worker 创建失败时抛出错误
* - 当渲染失败且未启用安全模式时抛出错误
* - 当画布创建失败时抛出错误
*
* @example
* // 异步渲染并等待结果
* try {
* const canvas = await texture.createWithWorker();
* document.body.appendChild(canvas);
* } catch (error) {
* console.error('渲染失败:', error);
* }
*
* @remarks
* 注意事项:
* 1. 相比 create 方法,此方法会消耗更多内存
* 2. 首次调用时可能有短暂延迟(Worker 初始化)
* 3. 不要在高频率循环中使用此方法
*
* @see create 同步渲染方法
* @see setRenderOptions 设置渲染选项
*/
createWithWorker(): Promise<HTMLCanvasElement>;
/**
* 销毁贴图实例
*
* 清理实例中的缓存和引用,释放内存。在不再需要贴图实例时调用此方法。
*
* @example
* // 销毁贴图实例
* texture.destroy();
* texture = null; // 解除引用
*/
destroy(): void;
}