奇怪的压缩html图像

loading...


2

我想使用从WebGL中的服务器检索的base64编码的png . 为此,我将编码的png加载到html Image对象中 . 对于我的应用程序,我需要png数据绝对无损,但是着色器检索到的像素值在不同的浏览器中是不同的...(如果我将Image加载到画布并使用getImageData,则检索到的像素值是不同的浏览器) . 必须有一些奇怪的像素值过滤/压缩发生,但我无法弄清楚如何以及为什么 . 有谁熟悉这个问题?

从服务器加载图像:

var htmlImage = new Image();
htmlImage.src = BASE64_STRING_FROM_SERVER

将图像加载到着色器中:

ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGB, ctx.RGB, ctx.UNSIGNED_BYTE, 
htmlImage);

尝试使用画布读取像素值(跨浏览器的不同值):

var canvas = document.createElement('canvas');
canvas.width = htmlImage.width;
canvas.height = htmlImage.height;
canvas.getContext('2d').drawImage(htmlImage, 0, 0, htmlImage.width, 
htmlImage.height);

// This data is different in, for example, the latest version of Chrome and Firefox
var pixelData = canvas.getContext('2d').getImageData(0, 0, 
htmlImage.width, htmlImage.height).data;

loading...

1回答

  • 2

    正如@Sergiu指出的那样,默认情况下,浏览器可以对图像应用颜色校正,伽马校正,颜色配置文件或其他任何内容 .

    在WebGL中你可以关闭它 . 在将图像上传到纹理之前,使用 gl.UNPACK_COLORSPACE_CONVERSION_WEBGL 调用 gl.pixelStorei 并将其传递给 gl_NONE ,如同

    gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
    

    这将告诉浏览器不要应用色彩空间,伽玛等 . 这对WebGL很重要,因为许多3D应用程序使用纹理来传递图像以外的东西 . 示例包括法线贴图,高度贴图,环境遮挡贴图,辉光贴图,高光贴图和许多其他类型的数据 .

    默认设置为

    gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL);
    

    请注意,这可能仅在直接从图像中获取数据时有效,而不是在通过2D画布传递图像时 .

    请注意,如果您通过将数据绘制到2D画布中从WebGL画布获取数据,那么所有投注都将关闭 . 如果没有别的画布2D使用预乘alpha,那么如果alpha <255,则将数据复制到2D画布中和从2D画布复制数据总是有损的 . 如果您希望数据不受任何2D画布的影响,请使用 gl.readPixels .

    请注意,此方法的一个潜在问题是速度 . 浏览器可能会假设您下载的图像最终会显示 . 它无法预先知道它将用于纹理 . 因此,您创建一个图像标记,设置src属性,浏览器下载图像,解压缩,准备显示,然后发出加载事件,然后将该图像上传到具有 UNPACK_COLORSPACE_CONVERSION_WEBGL = NONE 的纹理 . 此时浏览器可能必须重新解压缩它,如果它还没有应用颜色空间转换 . 它's not likely a noticeable speed issue but it'也不是零 .

    为了解决这个问题,浏览器添加了ImageBitmap api . 此API解决了一些问题 .

    • 它可以在Web worker中使用,因为它不是像Image这样的DOM元素

    • 你可以传递一个子矩形,这样你就不必首先得到整个图像,只是为了最终得到它的一部分,如果它

    • 您可以在开始避免上述问题之前判断是否应用色彩空间校正 .

    不幸的是,截至2018年12月,只有Chrome完全支持 . Firefox有部分支持 . Safari没有 .

评论

暂时没有评论!