我有一个canvas
,上面加载了一个png
图片。我通过.toDataURL()
方法获取它的jpg
格式的base64字符串,代码如下:
$('#base64str').val(canvas.toDataURL("image/jpeg"));
但是新的jpg
图像中,png
图像的透明部分显示为黑色。
有没有解决方法可以将其改为白色?提前致谢。
我有一个canvas
,上面加载了一个png
图片。我通过.toDataURL()
方法获取它的jpg
格式的base64字符串,代码如下:
$('#base64str').val(canvas.toDataURL("image/jpeg"));
但是新的jpg
图像中,png
图像的透明部分显示为黑色。
有没有解决方法可以将其改为白色?提前致谢。
这种变黑的情况是因为将'image/jpeg'转换时会将所有画布像素的alpha设置为完全不透明(alpha = 255)。问题在于,透明的画布像素被着成了完全黑色但透明
。所以,当你将这些黑色像素变为不透明时,结果就是一个变黑的JPEG。
解决方法是手动将所有非不透明的画布像素更改为您想要的白色,而不是黑色。
这样,当它们变得不透明时,它们将显示为白色像素,而不是黑色像素。
以下是具体操作:
// change non-opaque pixels to white
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
for(var i=0;i<data.length;i+=4){
if(data[i+3]<255){
data[i]=255;
data[i+1]=255;
data[i+2]=255;
data[i+3]=255;
}
}
ctx.putImageData(imgData,0,0);
在花费了很多时间研究这个问题,尤其是这篇文章和相关解决方案都有点用,但我就是无法让画布看起来正确。不过,我在其他地方找到了一个解决方法,并想在这里发布,以防止其他人浪费几个小时试图将黑色背景变为白色并看起来像原始的。
public getURI(): string {
let canvas = <HTMLCanvasElement>document.getElementById('chartcanvas');
var newCanvas = <HTMLCanvasElement>canvas.cloneNode(true);
var ctx = newCanvas.getContext('2d');
ctx.fillStyle = "#FFF";
ctx.fillRect(0, 0, newCanvas.width, newCanvas.height);
ctx.drawImage(canvas, 0, 0);
return newCanvas.toDataURL("image/jpeg");
}
canvas.fillStyle = '#FFF';
。 - agm1984这个答案比较长,但我认为它更加“正确”,因为它处理这些事情时没有直接修改原始画布数据。我认为那是一种相当混乱和理论上不令人满意的解决方案。有内置函数可以实现这一点,应该使用它们。以下是我找到/盗用的解决方案:
function canvasToImage(backgroundColor){
var context = document.getElementById('canvas').getContext('2d');
canvas = context.canvas;
//cache height and width
var w = canvas.width;
var h = canvas.height;
var data;
//get the current ImageData for the canvas.
data = context.getImageData(0, 0, w, h);
//store the current globalCompositeOperation
var compositeOperation = context.globalCompositeOperation;
//set to draw behind current content
context.globalCompositeOperation = "destination-over";
//set background color
context.fillStyle = backgroundColor;
//draw background / rect on entire canvas
context.fillRect(0,0,w,h);
//get the image data from the canvas
var imageData = this.canvas.toDataURL("image/jpeg");
//clear the canvas
context.clearRect (0,0,w,h);
//restore it with original / cached ImageData
context.putImageData(data, 0,0);
//reset the globalCompositeOperation to what it was
context.globalCompositeOperation = compositeOperation;
//return the Base64 encoded data url string
return imageData;
}
基本上,您需要创建一个白色背景图像,并在画布下面加入它,然后打印它。这个函数主要是从某个人的博客抄袭过来的,但它需要进行一些修改-例如实际获取上下文-并直接从我的(可工作的)代码中复制,因此只要你的画布元素具有id 'canvas',你就应该能够复制/粘贴它并使其工作。
我修改它的博客文章如下:
我的函数比这个函数的优势在于它输出为jpeg而不是png,更有可能在chrome中工作良好,因为它的dataurl限制为2MB,并且它实际上获取了上下文,这是原始函数中一个明显的遗漏。
// change non-opaque pixels to white
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
for(var i=0;i<data.length;i+=4){
if(data[i+3]<255){
data[i] = 255 - data[i];
data[i+1] = 255 - data[i+1];
data[i+2] = 255 - data[i+2];
data[i+3] = 255 - data[i+3];
}
}
ctx.putImageData(imgData,0,0);
canvas.toDataURL("image/png");
// change non-opaque pixels to white
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
for(var i=0;i<data.length;i+=4){
if(data[i+3]<255){
data[i] = 255 - data[i];
data[i+1] = 255 - data[i+1];
data[i+2] = 255 - data[i+2];
data[i+3] = 255 - data[i+3];
}
resizeImage({ file, maxSize, backgroundColor }) {
const fr = new FileReader();
const img = new Image();
const dataURItoBlob = (dataURI) => {
const bytes = (dataURI.split(',')[0].indexOf('base64') >= 0)
? window.atob(dataURI.split(',')[1])
: window.unescape(dataURI.split(',')[1]);
const mime = dataURI.split(',')[0].split(':')[1].split(';')[0];
const max = bytes.length;
const ia = new Uint8Array(max);
for (let i = 0; i < max; i += 1) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ia], { type: mime });
};
const resize = () => {
// create a canvas element to manipulate
const canvas = document.createElement('canvas');
canvas.setAttribute('id', 'canvas');
const context = canvas.getContext('2d');
// setup some resizing definitions
let { width, height } = img;
const isTooWide = ((width > height) && (width > maxSize));
const isTooTall = (height > maxSize);
// resize according to `maxSize`
if (isTooWide) {
height *= maxSize / width;
width = maxSize;
} else if (isTooTall) {
width *= maxSize / height;
height = maxSize;
}
// resize the canvas
canvas.width = width;
canvas.height = height;
// place the image on the canvas
context.drawImage(img, 0, 0, width, height);
// get the current ImageData for the canvas
const data = context.getImageData(0, 0, width, height);
// store the current globalCompositeOperation
const compositeOperation = context.globalCompositeOperation;
// set to draw behind current content
context.globalCompositeOperation = 'destination-over';
// set background color
context.fillStyle = backgroundColor;
// draw background / rect on entire canvas
context.fillRect(0, 0, width, height);
// get the image data from the canvas
const imageData = canvas.toDataURL('image/jpeg');
// clear the canvas
context.clearRect(0, 0, width, height);
// restore it with original / cached ImageData
context.putImageData(data, 0, 0);
// reset the globalCompositeOperation to what it was
context.globalCompositeOperation = compositeOperation;
// return the base64-encoded data url string
return dataURItoBlob(imageData);
};
return new Promise((resolve, reject) => {
if (!file.type.match(/image.*/)) {
reject(new Error('VImageInput# Problem resizing image: file must be an image.'));
}
fr.onload = (readerEvent) => {
img.onload = () => resolve(resize());
img.src = readerEvent.target.result;
};
fr.readAsDataURL(file);
});
},
这是一个Vue JS实例方法,可以像这样使用:
// this would be the user-uploaded file from the input element
const image = file;
const settings = {
file: image,
maxSize: 192, // to make 192x192 image
backgroundColor: '#FFF',
};
// this will output a base64 string you can dump into your database
const resizedImage = await this.resizeImage(settings);
我的解决方案是将大约74个与客户端调整图像大小相关的StackOverflow答案组合在一起,最终的难点是处理透明PNG文件。
如果没有Laereom在这里的回答,我的答案将不可能实现。