Transparent HTML5 canvas todataurl 仅在移动设备上呈现透明背景
Transparent HTML5 canvas todataurl only rendering transparent background on mobile devices
已编辑,请参阅问题结尾。
在我的应用程序中,我有两个 canvas 元素。一个显示分层的透明 png,另一个从文件输入中获取图像并对其进行遮罩。所选图像在未被遮盖的地方是透明的。然后将此图像转换为 dataUrl,转换以适合第一个 canvas 并添加为第一个 canvas.
的顶层
在桌面浏览器上一切正常:Chrome OSX、Safari OSX。我只在加载时添加它,所以我确保不会出现竞争条件。
在 Android Chrome 和 Safari iOS 上,转换为数据 URL 的 canvas 呈现透明。如果我将非透明图像添加到第二个 canvas,渲染图像甚至会在移动设备上显示。
为了检查,我在正文中添加了所谓的透明 canvas。它在桌面上正确显示,但在移动浏览器上是透明的。这里是简化的 JS。为方便起见,我使用 fabric.js,但没有 lib 问题是一样的。我什至添加了背景颜色。然后只有颜色会显示。知道为什么移动浏览器上的 todataurl 只呈现透明像素吗?
<body>
<canvas id="canv"></canvas>
<script src="fabric.js"></script>
<script>
// main canvas
var c = new fabric.Canvas('canv');
c.setWidth(200);
c.setHeight(200);
var i = document.createElement('img');
i.src = 'dummy.jpg';
// i.src = 'dummy1.png';
i.onload = function(e) {
//document.body.appendChild(i);
scale = 1; // resizes the image
var ci = new fabric.Image(i);
ci.set({
left: 0,
top: 0,
scaleX: scale,
scaleY: scale,
originX: 'left',
originY: 'top'
}).setCoords();
// temporary canvas, will be converted to dataurl, contains transformed image
var tmpCanvas = new fabric.Canvas();
tmpCanvas.setWidth(100);
tmpCanvas.setHeight(100);
ci.scaleToWidth(100);
tmpCanvas.add(ci);
tmpCanvas.renderAll();
// create image from temporary canvas
var customImage = new fabric.Image.fromURL(tmpCanvas.toDataURL({ format: 'png' }), function (cImg) {
// add it to original canvas
c.clear();
c.add(cImg);
c.renderAll();
data = c.toDataURL({ format: 'png' });
// resized image
var newc = new fabric.StaticCanvas().setWidth(300).setHeight(300);
var newImg = new fabric.Image.fromURL(data, function (c1Img) {
newc.add(c1Img);
newc.renderAll();
// append to body to check if canvas is rendered correctly
document.body.appendChild(newc.lowerCanvasEl);
});
});
}
</script>
编辑:我解决了问题,但找不到 Javascript 方面的问题。
问题是我将临时 canvas 复制到另一个 canvas 上。添加的 canvas 的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,这正是为此目的而生成的。简称口罩。
边界框是在应用启动时在另一个临时 canvas 中计算的(基于此答案)。尽管掩码的所有尺寸及其 canvas 都已正确设置并且 canvas 从未添加到 DOM,但在小屏幕上加载时,边界框的结果与全屏结果。经过大量测试后,我发现这在桌面上也是如此。
因为我已经在这个问题上花了很多时间,所以我决定尝试计算 PHP 中的边界并将其放入数据属性中。效果很好!
对于那些对 PHP 解决方案感兴趣的人:
function get_bounding_box($imgPath) {
$img = imagecreatefrompng($imgPath);
$w = imagesx($img);
$h = imagesy($img);
$bounds = [
'left' => $w,
'right' => 0,
'top' => $h,
'bottom' => 0
];
// get alpha of every pixel, if it is not fully transparent, write it to bounds
for ($yPos = 0; $yPos < $h; $yPos++) {
for ($xPos = 0; $xPos < $w; $xPos++) {
// Check, ob Pixel nicht vollständig transparent ist
$rgb = imagecolorat($img, $xPos, $yPos);
if (imagecolorsforindex($img, $rgb)['alpha'] < 127) {
if ($xPos < $bounds['left']) {
$bounds['left'] = $xPos;
}
if ($xPos > $bounds['right']) {
$bounds['right'] = $xPos;
}
if ($yPos < $bounds['top']) {
$bounds['top'] = $yPos;
}
if ($yPos > $bounds['bottom']) {
$bounds['bottom'] = $yPos;
}
}
}
}
return $bounds;
}
问题是我将临时 canvas 复制到另一个 canvas 上。添加的 canvas 的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,这正是为此目的而生成的。简称口罩。
边界框是在应用启动时在另一个临时 canvas 中计算的(基于此答案)。尽管掩码的所有尺寸及其 canvas 都已正确设置并且 canvas 从未添加到 DOM,但在小屏幕上加载时,边界框的结果与全屏结果。经过大量测试后,我发现这在桌面上也是如此。
因为我已经在这个问题上花了很多时间,所以我决定尝试计算 PHP 中的边界并将其放入数据属性中。效果很好!
对于那些对 PHP 解决方案感兴趣的人:
function get_bounding_box($imgPath) {
$img = imagecreatefrompng($imgPath);
$w = imagesx($img);
$h = imagesy($img);
$bounds = [
'left' => $w,
'right' => 0,
'top' => $h,
'bottom' => 0
];
// get alpha of every pixel, if it is not fully transparent, write it to bounds
for ($yPos = 0; $yPos < $h; $yPos++) {
for ($xPos = 0; $xPos < $w; $xPos++) {
// Check, ob Pixel nicht vollständig transparent ist
$rgb = imagecolorat($img, $xPos, $yPos);
if (imagecolorsforindex($img, $rgb)['alpha'] < 127) {
if ($xPos < $bounds['left']) {
$bounds['left'] = $xPos;
}
if ($xPos > $bounds['right']) {
$bounds['right'] = $xPos;
}
if ($yPos < $bounds['top']) {
$bounds['top'] = $yPos;
}
if ($yPos > $bounds['bottom']) {
$bounds['bottom'] = $yPos;
}
}
}
}
return $bounds;
}
已编辑,请参阅问题结尾。
在我的应用程序中,我有两个 canvas 元素。一个显示分层的透明 png,另一个从文件输入中获取图像并对其进行遮罩。所选图像在未被遮盖的地方是透明的。然后将此图像转换为 dataUrl,转换以适合第一个 canvas 并添加为第一个 canvas.
的顶层在桌面浏览器上一切正常:Chrome OSX、Safari OSX。我只在加载时添加它,所以我确保不会出现竞争条件。
在 Android Chrome 和 Safari iOS 上,转换为数据 URL 的 canvas 呈现透明。如果我将非透明图像添加到第二个 canvas,渲染图像甚至会在移动设备上显示。
为了检查,我在正文中添加了所谓的透明 canvas。它在桌面上正确显示,但在移动浏览器上是透明的。这里是简化的 JS。为方便起见,我使用 fabric.js,但没有 lib 问题是一样的。我什至添加了背景颜色。然后只有颜色会显示。知道为什么移动浏览器上的 todataurl 只呈现透明像素吗?
<body>
<canvas id="canv"></canvas>
<script src="fabric.js"></script>
<script>
// main canvas
var c = new fabric.Canvas('canv');
c.setWidth(200);
c.setHeight(200);
var i = document.createElement('img');
i.src = 'dummy.jpg';
// i.src = 'dummy1.png';
i.onload = function(e) {
//document.body.appendChild(i);
scale = 1; // resizes the image
var ci = new fabric.Image(i);
ci.set({
left: 0,
top: 0,
scaleX: scale,
scaleY: scale,
originX: 'left',
originY: 'top'
}).setCoords();
// temporary canvas, will be converted to dataurl, contains transformed image
var tmpCanvas = new fabric.Canvas();
tmpCanvas.setWidth(100);
tmpCanvas.setHeight(100);
ci.scaleToWidth(100);
tmpCanvas.add(ci);
tmpCanvas.renderAll();
// create image from temporary canvas
var customImage = new fabric.Image.fromURL(tmpCanvas.toDataURL({ format: 'png' }), function (cImg) {
// add it to original canvas
c.clear();
c.add(cImg);
c.renderAll();
data = c.toDataURL({ format: 'png' });
// resized image
var newc = new fabric.StaticCanvas().setWidth(300).setHeight(300);
var newImg = new fabric.Image.fromURL(data, function (c1Img) {
newc.add(c1Img);
newc.renderAll();
// append to body to check if canvas is rendered correctly
document.body.appendChild(newc.lowerCanvasEl);
});
});
}
</script>
编辑:我解决了问题,但找不到 Javascript 方面的问题。
问题是我将临时 canvas 复制到另一个 canvas 上。添加的 canvas 的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,这正是为此目的而生成的。简称口罩。
边界框是在应用启动时在另一个临时 canvas 中计算的(基于此答案)。尽管掩码的所有尺寸及其 canvas 都已正确设置并且 canvas 从未添加到 DOM,但在小屏幕上加载时,边界框的结果与全屏结果。经过大量测试后,我发现这在桌面上也是如此。
因为我已经在这个问题上花了很多时间,所以我决定尝试计算 PHP 中的边界并将其放入数据属性中。效果很好!
对于那些对 PHP 解决方案感兴趣的人:
function get_bounding_box($imgPath) {
$img = imagecreatefrompng($imgPath);
$w = imagesx($img);
$h = imagesy($img);
$bounds = [
'left' => $w,
'right' => 0,
'top' => $h,
'bottom' => 0
];
// get alpha of every pixel, if it is not fully transparent, write it to bounds
for ($yPos = 0; $yPos < $h; $yPos++) {
for ($xPos = 0; $xPos < $w; $xPos++) {
// Check, ob Pixel nicht vollständig transparent ist
$rgb = imagecolorat($img, $xPos, $yPos);
if (imagecolorsforindex($img, $rgb)['alpha'] < 127) {
if ($xPos < $bounds['left']) {
$bounds['left'] = $xPos;
}
if ($xPos > $bounds['right']) {
$bounds['right'] = $xPos;
}
if ($yPos < $bounds['top']) {
$bounds['top'] = $yPos;
}
if ($yPos > $bounds['bottom']) {
$bounds['bottom'] = $yPos;
}
}
}
}
return $bounds;
}
问题是我将临时 canvas 复制到另一个 canvas 上。添加的 canvas 的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,这正是为此目的而生成的。简称口罩。
边界框是在应用启动时在另一个临时 canvas 中计算的(基于此答案)。尽管掩码的所有尺寸及其 canvas 都已正确设置并且 canvas 从未添加到 DOM,但在小屏幕上加载时,边界框的结果与全屏结果。经过大量测试后,我发现这在桌面上也是如此。
因为我已经在这个问题上花了很多时间,所以我决定尝试计算 PHP 中的边界并将其放入数据属性中。效果很好!
对于那些对 PHP 解决方案感兴趣的人:
function get_bounding_box($imgPath) {
$img = imagecreatefrompng($imgPath);
$w = imagesx($img);
$h = imagesy($img);
$bounds = [
'left' => $w,
'right' => 0,
'top' => $h,
'bottom' => 0
];
// get alpha of every pixel, if it is not fully transparent, write it to bounds
for ($yPos = 0; $yPos < $h; $yPos++) {
for ($xPos = 0; $xPos < $w; $xPos++) {
// Check, ob Pixel nicht vollständig transparent ist
$rgb = imagecolorat($img, $xPos, $yPos);
if (imagecolorsforindex($img, $rgb)['alpha'] < 127) {
if ($xPos < $bounds['left']) {
$bounds['left'] = $xPos;
}
if ($xPos > $bounds['right']) {
$bounds['right'] = $xPos;
}
if ($yPos < $bounds['top']) {
$bounds['top'] = $yPos;
}
if ($yPos > $bounds['bottom']) {
$bounds['bottom'] = $yPos;
}
}
}
}
return $bounds;
}