使用 FabricJS 对大图像应用滤镜
Applying filters to large images using FabricJS
我正在尝试对 FabricJS 中的大图像应用滤镜。
图像大约为 3000 x 4000,超过了默认的 2048 纹理大小。我可以将它增加到 4096,它适用于这张图片。
目前,当应用滤镜时,图像被剪切。我尝试使用以下方法减小图像的大小:
let obj = this.canvas.getActiveObject();
if (Math.max(obj.width, obj.height) > 2048) {
let scale = 2048 / Math.max(obj.width, obj.height);
obj.filters.push(
new fabric.Image.filters.Resize({ scaleX: scale, scaleY: scale })
);
}
obj.filters.push(new fabric.Image.filters.Grayscale());
obj.applyFilters();
this.canvas.renderAll();
但这对我不起作用。图像仍然被剪切和旋转。
这就是我将图片添加到 canvas:
的方式
//in a parent component
let url = URL.createObjectURL(e.target.files[0]);
fabric.Image.fromURL(url, (image) => {
this.setState({
image,
});
});
//following is in a child component
let canvasWidth = this.canvasWrapperRef.current.clientWidth;
let canvasHeight = this.canvasWrapperRef.current.clientHeight;
//create canvas
this.canvas = new fabric.Canvas("canvas", {
selection: false,
backgroundColor: "black",
hoverCursor: "context-menu",
height: canvasHeight,
width: canvasWidth,
});
let image = this.props.image;
image.set({ selectable: false });
this.canvas.centerObject(image);
this.canvas.setActiveObject(image);
this.canvas.add(image);
this.canvas.renderAll();
有什么方法可以减少原始图像的 size/quality,以便对其应用滤镜?
我花了几天时间,但我终于找到了解决我遇到的问题的方法。似乎当您使用 fabric 调整图像大小时,它会保留原始大小。为了解决这个问题,我将图像添加到可以处理过滤器的 canvas 大小,然后将 canvas 作为图像导出并以通常的方式将其添加到结构中。
对我来说,这似乎是一个有点老套的解决方案,它确实有效,但如果有人知道更好的解决方案,请告诉我。
//handle the image uploading process
handleImageUpload = async (e) => {
if (e.target.files.length < 1) return;
let objectUrl = URL.createObjectURL(e.target.files[0]);
//resize if needed
let imageUrl = await this.resizeImage(this.textureSize, objectUrl);
fabric.Image.fromURL(imageUrl, (image) => {
this.setState({
image,
});
});
};
//resize the image if one of the sides of the image exceeds the max texture size
//if the image requires resizing, create a canvas element but don't attach to DOM
//size the canvas with the largest size being equal to the max texture size
//then scale the image down to the correct size when adding to the canvas
resizeImage = (maxSize, imageUrl) => {
return new Promise((resolve) => {
let image = new Image();
image.src = imageUrl;
image.onload = (img) => {
//check if resizing is required
if (Math.max(img.target.width, img.target.height) > maxSize) {
//create canvas
let canvas = document.createElement("canvas");
//scale image
if (img.target.height >= img.target.width) {
canvas.height = maxSize;
canvas.width = (maxSize / img.target.height) * img.target.width;
} else {
canvas.width = maxSize;
canvas.height = (maxSize / img.target.width) * img.target.height;
}
//draw to canvas
let context = canvas.getContext("2d");
context.drawImage(img.target, 0, 0, canvas.width, canvas.height);
//assign new image url
resolve(context.canvas.toDataURL());
}
resolve(imageUrl);
};
});
};
我使用 2048 作为我的最大纹理尺寸。任何高于此的值和过滤器都会开始剪切和旋转图像。我认为这是由硬件决定的,我使用 2048 作为一个相对安全的限制。请参阅此处了解更多信息:http://fabricjs.com/fabric-filters
当您使用上述方法缩小图像时,您的图像质量可能会下降。更好的解决方案可能是使用 fabric 内置的缩小图像的方法(我没有测试过这个,但我想 fabric 会比上述方法更好地处理重新缩放),然后导出并重新导入类似于上面的方法。然而,由于这只是一个以学习 React 为目的的个人项目,我很高兴能够对图像质量产生影响并显示警告,指出大图像尺寸会被调整大小并且可能会降低质量。
我正在尝试对 FabricJS 中的大图像应用滤镜。
图像大约为 3000 x 4000,超过了默认的 2048 纹理大小。我可以将它增加到 4096,它适用于这张图片。
目前,当应用滤镜时,图像被剪切。我尝试使用以下方法减小图像的大小:
let obj = this.canvas.getActiveObject();
if (Math.max(obj.width, obj.height) > 2048) {
let scale = 2048 / Math.max(obj.width, obj.height);
obj.filters.push(
new fabric.Image.filters.Resize({ scaleX: scale, scaleY: scale })
);
}
obj.filters.push(new fabric.Image.filters.Grayscale());
obj.applyFilters();
this.canvas.renderAll();
但这对我不起作用。图像仍然被剪切和旋转。
这就是我将图片添加到 canvas:
的方式//in a parent component
let url = URL.createObjectURL(e.target.files[0]);
fabric.Image.fromURL(url, (image) => {
this.setState({
image,
});
});
//following is in a child component
let canvasWidth = this.canvasWrapperRef.current.clientWidth;
let canvasHeight = this.canvasWrapperRef.current.clientHeight;
//create canvas
this.canvas = new fabric.Canvas("canvas", {
selection: false,
backgroundColor: "black",
hoverCursor: "context-menu",
height: canvasHeight,
width: canvasWidth,
});
let image = this.props.image;
image.set({ selectable: false });
this.canvas.centerObject(image);
this.canvas.setActiveObject(image);
this.canvas.add(image);
this.canvas.renderAll();
有什么方法可以减少原始图像的 size/quality,以便对其应用滤镜?
我花了几天时间,但我终于找到了解决我遇到的问题的方法。似乎当您使用 fabric 调整图像大小时,它会保留原始大小。为了解决这个问题,我将图像添加到可以处理过滤器的 canvas 大小,然后将 canvas 作为图像导出并以通常的方式将其添加到结构中。
对我来说,这似乎是一个有点老套的解决方案,它确实有效,但如果有人知道更好的解决方案,请告诉我。
//handle the image uploading process
handleImageUpload = async (e) => {
if (e.target.files.length < 1) return;
let objectUrl = URL.createObjectURL(e.target.files[0]);
//resize if needed
let imageUrl = await this.resizeImage(this.textureSize, objectUrl);
fabric.Image.fromURL(imageUrl, (image) => {
this.setState({
image,
});
});
};
//resize the image if one of the sides of the image exceeds the max texture size
//if the image requires resizing, create a canvas element but don't attach to DOM
//size the canvas with the largest size being equal to the max texture size
//then scale the image down to the correct size when adding to the canvas
resizeImage = (maxSize, imageUrl) => {
return new Promise((resolve) => {
let image = new Image();
image.src = imageUrl;
image.onload = (img) => {
//check if resizing is required
if (Math.max(img.target.width, img.target.height) > maxSize) {
//create canvas
let canvas = document.createElement("canvas");
//scale image
if (img.target.height >= img.target.width) {
canvas.height = maxSize;
canvas.width = (maxSize / img.target.height) * img.target.width;
} else {
canvas.width = maxSize;
canvas.height = (maxSize / img.target.width) * img.target.height;
}
//draw to canvas
let context = canvas.getContext("2d");
context.drawImage(img.target, 0, 0, canvas.width, canvas.height);
//assign new image url
resolve(context.canvas.toDataURL());
}
resolve(imageUrl);
};
});
};
我使用 2048 作为我的最大纹理尺寸。任何高于此的值和过滤器都会开始剪切和旋转图像。我认为这是由硬件决定的,我使用 2048 作为一个相对安全的限制。请参阅此处了解更多信息:http://fabricjs.com/fabric-filters
当您使用上述方法缩小图像时,您的图像质量可能会下降。更好的解决方案可能是使用 fabric 内置的缩小图像的方法(我没有测试过这个,但我想 fabric 会比上述方法更好地处理重新缩放),然后导出并重新导入类似于上面的方法。然而,由于这只是一个以学习 React 为目的的个人项目,我很高兴能够对图像质量产生影响并显示警告,指出大图像尺寸会被调整大小并且可能会降低质量。