feat: 添加喷枪笔刷类型,支持颗粒感和纹理效果

This commit is contained in:
bighuixiang
2025-08-04 23:01:39 +08:00
parent 336a982bbf
commit 24a98d215e
2 changed files with 319 additions and 53 deletions

View File

@@ -18,6 +18,7 @@ import { CustomPenBrush } from "./types/CustomPenBrush";
import { RibbonBrush } from "./types/RibbonBrush";
import { ShadedBrush } from "./types/ShadedBrush";
import { EraserStateManager } from "../EraserStateManager";
import { SprayBrush } from "./types/SprayBrush";
// import { SketchyBrush } from "./types/SketchyBrush";
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
@@ -116,6 +117,13 @@ export class BrushManager {
description: "阴影笔刷,适合创建渐变和阴影效果",
category: "基础笔刷",
});
brushRegistry.register("spray", SprayBrush, {
name: "spray",
description: "模拟喷枪效果,创建散点效果",
category: "基础笔刷",
});
// brushRegistry.register("sketchy", SketchyBrush);
// brushRegistry.register("spraypaint", SpraypaintBrush, {
// name: "Spraypaint",
@@ -123,47 +131,47 @@ export class BrushManager {
// category: "基础笔刷",
// });
// // 注册喷枪笔刷
brushRegistry.register(
"spray",
class SprayBrush extends PencilBrush {
constructor(canvas, options = {}) {
super(canvas, {
id: "spray",
name: "Spray",
description: "模拟喷枪效果,创建散点效果",
category: "基础笔刷",
...options,
});
}
// // // 注册喷枪笔刷
// brushRegistry.register(
// "spray",
// class SprayBrush extends PencilBrush {
// constructor(canvas, options = {}) {
// super(canvas, {
// id: "spray",
// name: "Spray",
// description: "模拟喷枪效果,创建散点效果",
// category: "基础笔刷",
// ...options,
// });
// }
create() {
this.brush = new fabric.SprayBrush(this.canvas);
this.configure(this.brush, this.options);
return this.brush;
}
// create() {
// this.brush = new fabric.SprayBrush(this.canvas);
// this.configure(this.brush, this.options);
// return this.brush;
// }
configure(brush, options = {}) {
super.configure(brush, options);
// configure(brush, options = {}) {
// super.configure(brush, options);
if (options.density !== undefined) {
brush.density = options.density;
}
// if (options.density !== undefined) {
// brush.density = options.density;
// }
if (options.randomOpacity !== undefined) {
brush.randomOpacity = options.randomOpacity;
}
// if (options.randomOpacity !== undefined) {
// brush.randomOpacity = options.randomOpacity;
// }
if (options.dotWidth !== undefined) {
brush.dotWidth = options.dotWidth;
}
}
},
{
name: "喷枪",
description: "模拟喷枪效果,创建散点效果",
}
);
// if (options.dotWidth !== undefined) {
// brush.dotWidth = options.dotWidth;
// }
// }
// },
// {
// name: "喷枪",
// description: "模拟喷枪效果,创建散点效果",
// }
// );
// 注册橡皮擦笔刷
brushRegistry.register(
"eraser",
@@ -380,23 +388,27 @@ export class BrushManager {
}
// 创建新笔刷实例
try {
const brushInstance = brushRegistry.createBrushInstance(brushId, this.canvas, {
color: brushId === "eraser" ? this.brushStore.state.color : undefined,
width: this.brushStore.state.size,
opacity: this.brushStore.state.opacity,
const brushInstance = brushRegistry.createBrushInstance(
brushId,
this.canvas,
{
color: brushId === "eraser" ? this.brushStore.state.color : undefined,
width: this.brushStore.state.size,
opacity: this.brushStore.state.opacity,
// 阴影相关配置
shadowEnabled: this.brushStore.state.shadowEnabled,
shadowColor: this.brushStore.state.shadowColor,
shadowWidth: this.brushStore.state.shadowWidth,
shadowOffsetX: this.brushStore.state.shadowOffsetX,
shadowOffsetY: this.brushStore.state.shadowOffsetY,
// 阴影相关配置
shadowEnabled: this.brushStore.state.shadowEnabled,
shadowColor: this.brushStore.state.shadowColor,
shadowWidth: this.brushStore.state.shadowWidth,
shadowOffsetX: this.brushStore.state.shadowOffsetX,
shadowOffsetY: this.brushStore.state.shadowOffsetY,
// 材质笔刷特有配置
textureEnabled: this.brushStore.state.textureEnabled,
texturePath: this.brushStore.state.texturePath,
textureScale: this.brushStore.state.textureScale,
});
// 材质笔刷特有配置
textureEnabled: this.brushStore.state.textureEnabled,
texturePath: this.brushStore.state.texturePath,
textureScale: this.brushStore.state.textureScale,
}
);
if (brushInstance) {
// 创建笔刷
@@ -645,7 +657,10 @@ export class BrushManager {
// 初始化橡皮擦状态管理器
if (this.canvas && this.layerManager) {
this.eraserStateManager = new EraserStateManager(this.canvas, this.layerManager);
this.eraserStateManager = new EraserStateManager(
this.canvas,
this.layerManager
);
}
}
@@ -885,7 +900,12 @@ export class BrushManager {
const imageData = ctx.getImageData(pointer.x, pointer.y, 1, 1).data;
// 将RGB转换为十六进制颜色
const color = `#${((1 << 24) + (imageData[0] << 16) + (imageData[1] << 8) + imageData[2])
const color = `#${(
(1 << 24) +
(imageData[0] << 16) +
(imageData[1] << 8) +
imageData[2]
)
.toString(16)
.slice(1)}`;

View File

@@ -0,0 +1,246 @@
import { BaseBrush } from "../BaseBrush";
/**
* 喷枪笔刷
* 模拟喷枪效果,具有颗粒感和纹理
*/
export class SprayBrush extends BaseBrush {
/**
* 构造函数
* @param {Object} canvas fabric画布实例
* @param {Object} options 配置选项
*/
constructor(canvas, options = {}) {
super(canvas, {
id: "crayon",
name: "喷枪",
description: "模拟喷枪效果,具有颗粒感和纹理",
category: "特效笔刷",
icon: "crayon",
...options,
});
// 喷枪笔刷特有属性
this._baseWidth = options._baseWidth || 15;
this._size = options._size || 0;
this._sep = options._sep || options._sep === 0 ? options._sep : 1;
this._inkAmount = options._inkAmount || 10;
this.randomness = options.randomness || 0.8; // 随机性
this.texture = options.texture || "default"; // 纹理类型
}
/**
* 创建笔刷实例
* @returns {Object} fabric笔刷实例
*/
create() {
if (!this.canvas) {
throw new Error("画布实例不存在");
}
// 创建fabric原生喷枪笔刷
this.brush = new fabric.CrayonBrush(this.canvas);
// 配置笔刷
this.configure(this.brush, this.options);
return this.brush;
}
/**
* 配置笔刷
* @param {Object} brush fabric笔刷实例
* @param {Object} options 配置选项
*/
configure(brush, options = {}) {
if (!brush) return;
options._sep = options._sep || this._sep;
options._inkAmount = options._inkAmount || this._inkAmount;
// 基础属性配置
if (options.width !== undefined) {
brush.width = options.width;
// 更新笔刷相关属性
this._baseWidth = options.width / 2;
this._size = options.width / 2 + this._baseWidth;
}
if (options.color !== undefined) {
brush.color = options.color;
}
if (options.opacity !== undefined) {
brush.opacity = options.opacity;
}
// 喷枪笔刷特有属性
if (options._baseWidth !== undefined) {
brush._baseWidth = options._baseWidth;
this._baseWidth = options._baseWidth;
this._size = this.width / 2 + this._baseWidth;
}
if (options._sep !== undefined) {
brush._sep = options._sep;
this._sep = options._sep;
}
if (options._inkAmount !== undefined) {
brush._inkAmount = options._inkAmount;
this._inkAmount = options._inkAmount;
}
}
/**
* 设置颗粒分离度
* @param {Number} sep 分离度值
*/
setSeparation(sep) {
this._sep = Math.max(0.5, Math.min(10, sep));
if (this.brush) {
this.brush._sep = this._sep;
}
return this._sep;
}
/**
* 设置墨量
* @param {Number} amount 墨量值
*/
setInkAmount(amount) {
this._inkAmount = Math.max(1, Math.min(50, amount));
if (this.brush) {
this.brush._inkAmount = this._inkAmount;
}
return this._inkAmount;
}
/**
* 设置随机性
* @param {Number} value 随机性值(0-1)
*/
setRandomness(value) {
this.randomness = Math.max(0, Math.min(1, value));
return this.randomness;
}
/**
* 设置纹理类型
* @param {String} type 纹理类型
*/
setTexture(type) {
this.texture = type;
// 实际应用可能需要更多的实现逻辑
return this.texture;
}
/**
* 获取笔刷可配置属性
* @returns {Array} 可配置属性描述数组
* @override
*/
getConfigurableProperties() {
// 获取基础属性
const baseProperties = super.getConfigurableProperties();
// 定义喷枪笔刷特有属性
const crayonProperties = [
{
id: "separation",
name: "颗粒分离度",
type: "slider",
defaultValue: this._sep,
min: 0.5,
max: 10,
step: 0.5,
description: "控制喷枪颗粒的分离程度",
category: "喷枪设置",
order: 100,
},
{
id: "inkAmount",
name: "墨量",
type: "slider",
defaultValue: this._inkAmount,
min: 1,
max: 50,
step: 1,
description: "控制喷枪的颜料量",
category: "喷枪设置",
order: 110,
},
{
id: "randomness",
name: "随机性",
type: "slider",
defaultValue: this.randomness,
min: 0,
max: 1,
step: 0.05,
description: "控制喷枪纹理的随机程度",
category: "喷枪设置",
order: 120,
},
{
id: "texture",
name: "纹理类型",
type: "select",
defaultValue: this.texture,
options: [
{ value: "default", label: "默认" },
{ value: "rough", label: "粗糙" },
{ value: "smooth", label: "平滑" },
],
description: "设置喷枪的纹理类型",
category: "喷枪设置",
order: 130,
},
];
// 合并并返回所有属性
return [...baseProperties, ...crayonProperties];
}
/**
* 更新笔刷属性
* @param {String} propId 属性ID
* @param {any} value 属性值
* @returns {Boolean} 是否更新成功
* @override
*/
updateProperty(propId, value) {
// 先检查基类能否处理此属性
if (super.updateProperty(propId, value)) {
return true;
}
// 处理喷枪笔刷特有属性
if (propId === "separation") {
this.setSeparation(value);
return true;
} else if (propId === "inkAmount") {
this.setInkAmount(value);
return true;
} else if (propId === "randomness") {
this.setRandomness(value);
return true;
} else if (propId === "texture") {
this.setTexture(value);
return true;
}
return false;
}
/**
* 获取预览图
* @returns {String} 预览图URL
*/
getPreview() {
return "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cmVjdCB4PSIxMCIgeT0iMTAiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48cmVjdCB4PSIyMCIgeT0iMjAiIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48cmVjdCB4PSIzMCIgeT0iMzAiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4=";
}
}