如何在 PHP 中创建给定大小的尽可能小的透明 png/gif?

How to create the smallest possible transparent png/gif of a given size in PHP?

我编写了这段代码来为给定大小的透明 PNG 生成数据 uri:

function createTransparentDataURI($w = 1, $h = 1) {

    // Enable output buffering
    ob_start();

    $img = imagecreatetruecolor($w, $h);
    imagesavealpha($img, true);
    $color = imagecolorallocatealpha($img, 0, 0, 0, 127);
    imagefill($img, 0, 0, $color);
    imagepng($img);
    imagedestroy($img);

    // Capture the output
    $imagedata = ob_get_contents();
    // Clear the output buffer
    ob_end_clean();

    // REF: 
    return 'data:image/png;base64,' . base64_encode($imagedata);
}

示例 运行 和

echo createTransparentDataURI(1016, 312);

returns

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA/gAAAE4CAYAAADvrFgKAAAE40lEQVR4nO3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwZltVAAEv7IggAAAAAElFTkSuQmCC

有什么方法可以"compress"(PNG 是无损的,但有压缩选项?)这个数据 uri 有更好的编码或使用单色 GIF? PHP 的程序化图形不是我的强项。

考虑到图像将是透明的并且上面不会出现任何内容,因此您不需要它是无损的。这意味着您可以使用单一颜色的调色板,它将为此颜色创建一个索引并将该索引用于图像中的所有像素。要创建索引调色板 PNG,您应该在代码中使用 imagetruecolortopalette() 函数:http://php.net/manual/en/function.imagetruecolortopalette.php

您还可以将图像压缩级别设置为最高。

function createTransparentDataURI($w = 1, $h = 1) {
    //...
    //create image palette with one color, the dithering (the second argument) doesn't matter here
    imagetruecolortopalette($img, false, 1);
    imagepng($img, null, 9); //set the compression level to highest
    //...
}

这将图像 1016x312 的数据长度从 1308 字节减少到 133 字节,几乎减少了十分之一。

通过将二进制数据转换为base64,您可以肉眼看到还有压缩空间:

iVBORw0KGgoAAAANSUhEUgAAA/gAAAE4AQMAAADVYspJAAAAA1BMVEUEAgSVKDOdAAAAPUlEQVR42u3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/BicAAABWZX81AAAAABJRU5ErkJggg==

其中多个 "A" 是

您可以启用 http 的服务器 gzip 压缩,进一步压缩此响应。

GIF 不会做得更好,因为在我的测试中它的大小是 910 字节。