【问题标题】:Transparent HTML5 canvas todataurl only rendering transparent background on mobile devices透明 HTML5 画布 todataurl 仅在移动设备上呈现透明背景
【发布时间】:2018-09-13 00:36:31
【问题描述】:

已编辑,见问题结尾。

在我的应用程序中,我有两个画布元素。一个显示分层的透明 png,另一个从文件输入中获取图像并将其屏蔽。选择的图像在没有被遮罩的地方是透明的。然后将此图像转换为 dataUrl,转换为适合第一个画布并添加为第一个画布的顶层。

在桌面浏览器上一切正常:Chrome OSX、Safari OSX。我只在加载时添加它,所以我确保不会发生竞争条件。

在 Android Chrome 和 Safari iOS 上,转换为 dataURL 的画布呈现透明。如果我将非透明图像添加到第二个画布,渲染的图像甚至会显示在移动设备上。

为了检查,我在正文中添加了所谓的透明画布。它在桌面上正确显示,但在移动浏览器上是透明的。这里是简化的 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 端找不到问题。

问题是我将一个临时画布复制到另一个画布上。添加的画布的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,该边界框正是为此目的而生成的。简而言之就是一个面具。

边界框是在应用启动时在另一个临时画布中计算的(基于此答案)。尽管掩码及其画布的所有尺寸均已正确设置,并且从未将画布添加到 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;

}

【问题讨论】:

    标签: javascript canvas html5-canvas fabricjs todataurl


    【解决方案1】:

    问题是我将一个临时画布复制到另一个画布上。添加的画布的比例和位置是通过在 png 中找到非透明像素的边界框来计算的,该边界框正是为此目的而生成的。简而言之就是一个面具。

    边界框是在应用启动时在另一个临时画布中计算的(基于此答案)。尽管掩码及其画布的所有尺寸均已正确设置,并且从未将画布添加到 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-02
      • 2022-11-15
      • 1970-01-01
      • 1970-01-01
      • 2015-03-18
      • 2016-04-21
      • 1970-01-01
      • 1970-01-01
      • 2019-03-31
      相关资源
      最近更新 更多