画布增加的新功能
This commit is contained in:
@@ -12,7 +12,7 @@ export class LiquifyCPUManager {
|
||||
sharpenAmount: 0.3, // 添加锐化强度参数
|
||||
...options,
|
||||
};
|
||||
console.log("CPU版本的液化管理器config",this.config);
|
||||
console.log("CPU版本的液化管理器config", this.config);
|
||||
|
||||
this.params = {
|
||||
size: 60, // 增大默认尺寸
|
||||
@@ -63,7 +63,8 @@ export class LiquifyCPUManager {
|
||||
// 新增:持续按压相关状态
|
||||
this.pressStartTime = 0; // 按压开始时间
|
||||
this.pressDuration = 0; // 按压持续时间
|
||||
this.accumulatedRotation = 0; // 累积旋转角度(用于顺时针/逆时针)
|
||||
this.accumulatedRotation = 0; // 累积旋转角度(用于顺时针/逆时针)--废除使用固定角度
|
||||
this.fixedRotationAngle = 0.32; // 固定旋转角度
|
||||
this.accumulatedScale = 0; // 累积缩放量(用于捏合/展开)
|
||||
this.lastApplyTime = 0; // 上次应用时间
|
||||
this.continuousApplyInterval = 50; // 持续应用间隔(毫秒)
|
||||
@@ -189,7 +190,7 @@ export class LiquifyCPUManager {
|
||||
this.isHolding = true;
|
||||
|
||||
// 启动持续效果定时器(对于所有模式都支持持续按压)
|
||||
this.startContinuousEffect();
|
||||
// this.startContinuousEffect();
|
||||
|
||||
console.log(`开始液化操作,初始点: (${x}, ${y})`);
|
||||
}
|
||||
@@ -220,7 +221,6 @@ export class LiquifyCPUManager {
|
||||
// 新增:启动持续效果
|
||||
startContinuousEffect() {
|
||||
this.stopContinuousEffect(); // 先停止已有的定时器
|
||||
|
||||
this.continuousTimer = setInterval(() => {
|
||||
if (this.isHolding && this.initialized) {
|
||||
// 更新持续时间
|
||||
@@ -273,7 +273,6 @@ export class LiquifyCPUManager {
|
||||
*/
|
||||
_applyEnhancedRotationDeformation(centerX, centerY, radius, strength, isClockwise) {
|
||||
if (!this.currentImageData) return;
|
||||
|
||||
const data = this.currentImageData.data;
|
||||
const width = this.currentImageData.width;
|
||||
const height = this.currentImageData.height;
|
||||
@@ -286,6 +285,7 @@ export class LiquifyCPUManager {
|
||||
const rotationAngle =
|
||||
(isClockwise ? 1 : -1) * baseRotationSpeed * pressure * power * (1.0 + timeFactor * 0.5);
|
||||
|
||||
console.log("持续应用旋转效果");
|
||||
// 累积旋转角度 - 关键:这确保了持续旋转效果
|
||||
this.accumulatedRotation += rotationAngle;
|
||||
|
||||
@@ -309,13 +309,14 @@ export class LiquifyCPUManager {
|
||||
|
||||
// 计算旋转后的源位置 - 关键算法
|
||||
const angle = Math.atan2(dy, dx);
|
||||
const newAngle = angle + this.accumulatedRotation * falloff;
|
||||
// const newAngle = angle + this.accumulatedRotation * falloff;
|
||||
const newAngle = angle + (isClockwise ? this.fixedRotationAngle : -this.fixedRotationAngle) * falloff;
|
||||
|
||||
const sourceX = centerX + Math.cos(newAngle) * distance;
|
||||
const sourceY = centerY + Math.sin(newAngle) * distance;
|
||||
|
||||
// 双线性插值采样 - 确保像素连续性
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
const color = this._bicubicInterpolate(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -376,7 +377,7 @@ export class LiquifyCPUManager {
|
||||
const sourceY = centerY + dy * scale;
|
||||
|
||||
// 双线性插值采样
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
const color = this._bicubicInterpolate(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -401,16 +402,17 @@ export class LiquifyCPUManager {
|
||||
*/
|
||||
_applyEnhancedPushDeformation(centerX, centerY, radius, strength) {
|
||||
if (!this.currentImageData) return;
|
||||
|
||||
const data = this.currentImageData.data;
|
||||
const width = this.currentImageData.width;
|
||||
const height = this.currentImageData.height;
|
||||
const tempData = new Uint8ClampedArray(data);
|
||||
|
||||
// 计算推拉方向
|
||||
const deltaX = this.currentMouseX - this.initialMouseX;
|
||||
const deltaY = this.currentMouseY - this.initialMouseY;
|
||||
const deltaX = this.currentMouseX - this.lastMouseX;
|
||||
const deltaY = this.currentMouseY - this.lastMouseY;
|
||||
const dragLength = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
this.lastMouseX = this.currentMouseX;
|
||||
this.lastMouseY = this.currentMouseY;
|
||||
|
||||
const processRadius = Math.min(radius, Math.min(width, height) / 2);
|
||||
const minX = Math.max(0, Math.floor(centerX - processRadius));
|
||||
@@ -426,6 +428,7 @@ export class LiquifyCPUManager {
|
||||
|
||||
for (let y = minY; y < maxY; y++) {
|
||||
for (let x = minX; x < maxX; x++) {
|
||||
// 此处循环4万次
|
||||
const dx = x - centerX;
|
||||
const dy = y - centerY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
@@ -442,7 +445,7 @@ export class LiquifyCPUManager {
|
||||
const sourceX = x - pushX;
|
||||
const sourceY = y - pushY;
|
||||
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
const color = this._bicubicInterpolate(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -461,9 +464,9 @@ export class LiquifyCPUManager {
|
||||
// 有拖拽时的推拉效果
|
||||
const dirX = deltaX / dragLength;
|
||||
const dirY = deltaY / dragLength;
|
||||
|
||||
for (let y = minY; y < maxY; y++) {
|
||||
for (let x = minX; x < maxX; x++) {
|
||||
// 此处循环4万次
|
||||
const dx = x - centerX;
|
||||
const dy = y - centerY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
@@ -473,13 +476,13 @@ export class LiquifyCPUManager {
|
||||
const falloff = 1 - normalizedDistance * normalizedDistance;
|
||||
const factor = falloff * strength;
|
||||
|
||||
const offsetX = dirX * factor * Math.min(dragLength * 0.3, 15);
|
||||
const offsetY = dirY * factor * Math.min(dragLength * 0.3, 15);
|
||||
const offsetX = dirX * factor * Math.min(dragLength * 2, 30);
|
||||
const offsetY = dirY * factor * Math.min(dragLength * 2, 30);
|
||||
|
||||
const sourceX = x - offsetX;
|
||||
const sourceY = y - offsetY;
|
||||
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
const color = this._bicubicInterpolate(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -527,7 +530,7 @@ export class LiquifyCPUManager {
|
||||
break;
|
||||
|
||||
case this.modes.PUSH:
|
||||
this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
// this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
break;
|
||||
|
||||
default: {
|
||||
@@ -553,101 +556,7 @@ export class LiquifyCPUManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用液化变形 - 主要入口,集成增强算法
|
||||
*/
|
||||
// applyDeformation(x, y) {
|
||||
// if (!this.initialized || !this.originalImageData) {
|
||||
// console.warn("液化管理器未初始化或缺少必要数据");
|
||||
// return this.currentImageData;
|
||||
// }
|
||||
|
||||
// // 更新鼠标位置
|
||||
// this.currentMouseX = x;
|
||||
// this.currentMouseY = y;
|
||||
|
||||
// // 计算拖拽参数
|
||||
// const deltaX = this.currentMouseX - this.initialMouseX;
|
||||
// const deltaY = this.currentMouseY - this.initialMouseY;
|
||||
// this.dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
// this.dragAngle = Math.atan2(deltaY, deltaX);
|
||||
|
||||
// // 获取当前参数
|
||||
// const { size, pressure, power } = this.params;
|
||||
// const mode = this.currentMode;
|
||||
// const radius = size;
|
||||
// const strength = pressure * power;
|
||||
|
||||
// // 根据模式选择算法
|
||||
// const pixelModes = [
|
||||
// this.modes.CLOCKWISE,
|
||||
// this.modes.COUNTERCLOCKWISE,
|
||||
// this.modes.PINCH,
|
||||
// this.modes.EXPAND,
|
||||
// this.modes.PUSH,
|
||||
// ];
|
||||
|
||||
// if (pixelModes.includes(mode)) {
|
||||
// // 使用增强的像素算法
|
||||
// switch (mode) {
|
||||
// case this.modes.CLOCKWISE:
|
||||
// this._applyEnhancedRotationDeformation(x, y, radius, strength, false);
|
||||
// break;
|
||||
// case this.modes.COUNTERCLOCKWISE:
|
||||
// this._applyEnhancedRotationDeformation(x, y, radius, strength, true);
|
||||
// break;
|
||||
// case this.modes.PINCH:
|
||||
// this._applyEnhancedPinchDeformation(x, y, radius, strength, true);
|
||||
// break;
|
||||
// case this.modes.EXPAND:
|
||||
// this._applyEnhancedPinchDeformation(x, y, radius, strength, false);
|
||||
// break;
|
||||
// case this.modes.PUSH:
|
||||
// this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // 更新最后应用时间
|
||||
// this.lastApplyTime = Date.now();
|
||||
// this.isFirstApply = false;
|
||||
|
||||
// return this.currentImageData;
|
||||
// } else {
|
||||
// // 使用原有的网格算法处理其他模式
|
||||
// if (!this.mesh) {
|
||||
// console.warn("网格未初始化");
|
||||
// return this.currentImageData;
|
||||
// }
|
||||
|
||||
// const finalStrength = (strength * this.config.maxStrength) / 100;
|
||||
|
||||
// // 应用变形
|
||||
// this._applyDeformation(
|
||||
// x,
|
||||
// y,
|
||||
// radius,
|
||||
// finalStrength,
|
||||
// mode,
|
||||
// this.params.distortion,
|
||||
// );
|
||||
|
||||
// // 平滑处理
|
||||
// if (this.config.smoothingIterations > 0) {
|
||||
// this._smoothMesh();
|
||||
// }
|
||||
|
||||
// // 更新图像数据
|
||||
// const result = this._applyMeshToImage();
|
||||
|
||||
// // 更新最后应用时间
|
||||
// this.lastApplyTime = Date.now();
|
||||
// this.isFirstApply = false;
|
||||
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 双线性插值采样 - 用于像素级算法
|
||||
* 双线性插值函数
|
||||
* @param {Uint8ClampedArray} data 图像数据
|
||||
* @param {number} width 图像宽度
|
||||
* @param {number} height 图像高度
|
||||
@@ -655,19 +564,55 @@ export class LiquifyCPUManager {
|
||||
* @param {number} y Y坐标
|
||||
* @returns {Array|null} RGBA颜色值数组或null
|
||||
*/
|
||||
_bilinearSample(data, width, height, x, y) {
|
||||
return this._bicubicInterpolate(data, width, height, x, y);
|
||||
_bilinearInterpolate(data, width, height, x, y) {
|
||||
const x1 = Math.floor(x);
|
||||
const y1 = Math.floor(y);
|
||||
const x2 = Math.min(width - 1, x1 + 1);
|
||||
const y2 = Math.min(height - 1, y1 + 1);
|
||||
|
||||
const dx = x - x1;
|
||||
const dy = y - y1;
|
||||
const dx1 = 1 - dx;
|
||||
const dy1 = 1 - dy;
|
||||
const index1 = (y1 * width + x1) * 4;
|
||||
const index2 = (y1 * width + x2) * 4;
|
||||
const index3 = (y2 * width + x1) * 4;
|
||||
const index4 = (y2 * width + x2) * 4;
|
||||
const r =
|
||||
data[index1] * dx1 * dy1 +
|
||||
data[index2] * dx * dy1 +
|
||||
data[index3] * dx1 * dy +
|
||||
data[index4] * dx * dy;
|
||||
const g =
|
||||
data[index1 + 1] * dx1 * dy1 +
|
||||
data[index2 + 1] * dx * dy1 +
|
||||
data[index3 + 1] * dx1 * dy +
|
||||
data[index4 + 1] * dx * dy;
|
||||
const b =
|
||||
data[index1 + 2] * dx1 * dy1 +
|
||||
data[index2 + 2] * dx * dy1 +
|
||||
data[index3 + 2] * dx1 * dy +
|
||||
data[index4 + 2] * dx * dy;
|
||||
const a =
|
||||
data[index1 + 3] * dx1 * dy1 +
|
||||
data[index2 + 3] * dx * dy1 +
|
||||
data[index3 + 3] * dx1 * dy +
|
||||
data[index4 + 3] * dx * dy;
|
||||
return [Math.round(r), Math.round(g), Math.round(b), Math.round(a)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 双三次插值实现 - 确保正确处理Alpha通道
|
||||
* @param {Uint8ClampedArray} data 图像数据
|
||||
* @param {number} width 图像宽度
|
||||
* @param {number} height 图像高度
|
||||
* @param {number} x X坐标
|
||||
* @param {number} y Y坐标
|
||||
* @returns {Array|null} RGBA颜色值数组或null
|
||||
*/
|
||||
* 三次插值实现 - 确保正确处理Alpha通道
|
||||
* @param {Uint8ClampedArray} data 图像数据
|
||||
* @param {number} width 图像宽度
|
||||
* @param {number} height 图像高度
|
||||
* @param {number} x X坐标
|
||||
* @param {number} y Y坐标
|
||||
* @returns {Array|null} RGBA颜色值数组或null
|
||||
*/
|
||||
_bicubicInterpolate(data, width, height, x, y) {
|
||||
// return this._bilinearInterpolate(data, width, height, x, y);
|
||||
|
||||
// 获取周围16个像素点
|
||||
const x1 = Math.floor(x) - 1;
|
||||
const y1 = Math.floor(y) - 1;
|
||||
|
||||
Reference in New Issue
Block a user