使用 PHP 中的 GD 库将位图文件转换为 JPEG

Posted

技术标签:

【中文标题】使用 PHP 中的 GD 库将位图文件转换为 JPEG【英文标题】:Convert Bitmap Files into JPEG using the GD library in PHP 【发布时间】:2009-10-18 21:35:21 【问题描述】:

我一直在尝试找出一种 格式的方法。

我尝试了许多实现,但似乎没有任何效果。我曾试图告诉我的客户他们不应该使用 Bitmap 文件,但他坚持并且坦率地说对计算机的理解不够,无法自行将它们转换为 JPG。

我无法在此服务器上使用 ImageMagick,我需要一个纯 GD 解决方案。提前感谢您的任何帮助。

编辑:

正在使用的位图图像是 16 位的,这就是问题所在。

我有这个功能,我正在工作....有点:

function ImageCreateFromBMP($filename) 
    if (! $f1 = fopen($filename,"rb")) return FALSE;

    $FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
    if ($FILE['file_type'] != 19778) return FALSE;

    $BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
        '/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
        '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
    $BMP['colors'] = pow(2,$BMP['bits_per_pixel']);

    if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
    $BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
    $BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
    $BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
    $BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
    $BMP['decal'] = 4-(4*$BMP['decal']);
    if ($BMP['decal'] == 4) $BMP['decal'] = 0;

    $PALETTE = array();
    if ($BMP['colors'] < 16777216 && $BMP['colors'] != 65536) 
        $PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
    

    $IMG = fread($f1,$BMP['size_bitmap']);
    $VIDE = chr(0);

    $res = imagecreatetruecolor($BMP['width'],$BMP['height']);
    $P = 0;
    $Y = $BMP['height']-1;
    while ($Y >= 0) 
        $X=0;
        while ($X < $BMP['width']) 
            if ($BMP['bits_per_pixel'] == 24)
                $COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
            elseif ($BMP['bits_per_pixel'] == 16) 
                $COLOR = unpack("v",substr($IMG,$P,2));
                $blue  = ($COLOR[1] & 0x001f) << 3;
                $green = ($COLOR[1] & 0x07e0) >> 3;
                $red   = ($COLOR[1] & 0xf800) >> 8;
                $COLOR[1] = $red * 65536 + $green * 256 + $blue;
            
            elseif ($BMP['bits_per_pixel'] == 8) 
                $COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
                $COLOR[1] = $PALETTE[$COLOR[1]+1];
            
            elseif ($BMP['bits_per_pixel'] == 4) 
                $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
                if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
                $COLOR[1] = $PALETTE[$COLOR[1]+1];
            
            elseif ($BMP['bits_per_pixel'] == 1) 
                $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
                if     (($P*8)%8 == 0) $COLOR[1] =  $COLOR[1]        >>7;
                elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
                elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
                elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
                elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
                elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
                elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
                elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
                $COLOR[1] = $PALETTE[$COLOR[1]+1];
            
            else
                return FALSE;

            imagesetpixel($res,$X,$Y,$COLOR[1]);

            $X++;
            $P += $BMP['bytes_per_pixel'];
        
        $Y--;
        $P+=$BMP['decal'];
    

    fclose($f1);
    return $res;

生成的图像是这样的:

如果您查看左侧的图像,您会发现生成的图像没有正确排列。小条子属于右手边。代码哪里出错了?问题出现在 16 位 else-if 中。

再次感谢大家的帮助。

【问题讨论】:

查看了您的代码,似乎是正确的。您确定 BMP 格式符合预期(54 字节,无调色板数据,图像数据如下)?由于这是一些奇异的 BMP 变体,因此标头中可能有更多/更少的数据导致此“移位”错误。 老实说,我不太确定图像发生了什么。如果有办法通过电子邮件将其中一张图片发送给您,以便您查看...我现在比以往任何时候都对这些图像文件的情况更感兴趣。可以联系我的电子邮件是 g mail dot com 的 dphoebus,我将回复其中一张图片。 【参考方案1】:

使用此功能:

http://www.programmierer-forum.de/function-imagecreatefrombmp-welche-variante-laeuft-t143137.htm

它支持多种比特率,例如 16 位和 32 位。此外,它还包含一些关于丢失文件大小、负调色板、错误输出、额外的 16 位掩码标题(这是 16 位的主要问题)和减少调色板 (biClrUsed) 的错误修正。

希望你喜欢;)

2015 年更新:此功能现在是 DOMPDF 的一部分(在页面上搜索“imagecreatefrombmp”),并已完善。现在它涵盖了压缩的 4 位和 8 位,忽略了不重要的标头,并且还支持特殊的 16 位 565 掩码。

【讨论】:

新网址:github.com/dompdf/dompdf/blob/master/src/Helpers.php#L555【参考方案2】:

虽然 GD 本身不支持 BMP,但谷歌搜索提供了一个 fewuserlandimplementations 的 imagecreatefrombmp() 函数。

我没有尝试过,但我相信其中至少有一个对你有用。

【讨论】:

再次感谢。我都试过了。同样,当我进行一些测试时,我发现正在提交的位图是 16 位文件。在任何这些实现​​中都没有考虑 16 位图像。【参考方案3】:

imagejpeg 函数怎么样?

bool imagejpeg ( 资源 $image [, 字符串 $filename [, int $quality ]] )

imagejpeg() 创建一个 JPEG 文件 给定的图像。

如需帮助支持 GD 中的 BMP 格式,请查看here,例如。

编辑:这不支持 16 位图像,这是正确的,因为原始位图规范不支持它。在您的情况下,请找出用于对颜色值进行编码的位模式。我假设 R 和 B 为 5 位,G 为 6 位,并且此解决方案中的顺序为 BGR(请插入我上面链接的代码):

else if ($bits == 16) 
$gd_scan_line = "";
$j = 0;
while($j < $scan_line_size) 
$byte1 = $scan_line$j++;
$byte2 = $scan_line$j++;
$b = chr($byte1 >> 3) * (255 / 31); 
$g = (chr($byte1 & 0x07) + chr($byte2 >> 5)) * (255 / 63);
$r = chr($byte2 & 0x1F) * (255 / 31);
$gd_scan_line .= "\x00$r$g$b";

请注意,我没有测试此代码(具体来说,我不确定是否缩放到 0..255)并且它仅在使用 5-6-5 位模式时才有效(嗯,它会也可以和其他人一起工作,但颜色会出错)。

【讨论】:

感谢您的快速回复,但我一直遇到同样的问题。我的客户端使用的位图文件是 16 位位图文件。我发现的每个实现(包括您展示的那个)都涉及 24 位、8 位、4 位和 1 位位图。 再次感谢您。我试过这个解决方案。返回的结果文件是一个纯黑色图像,水平绿线在图像的整个长度上等距间隔。【参考方案4】:

在我的头顶:

function convert_to_jpeg( $input_path, $output_path )

    $image = imagecreatefromstring(file_get_contents($input_path));
    imagejpeg($image, $output_path);
    imagedestroy($image);

它将采用 GD 可以处理的任何格式作为输入,并输出一个 jpeg 文件。我不知道你们使用的是什么版本的 GD,但我的 .bmp 处理得很好,我们在我工作的前一家公司使用的版本也是如此。 (分别在 Mac OS X 10.6 和 CentOS 5 上)

编辑:忘记了 imagedestroy!哎哟!

【讨论】:

希望它也适用于 16 位 BMP 文件...这将是最快、最优雅的解决方案。 感谢您的帮助。我试了一下,得到了这个错误: imagecreatefromstring() [function.imagecreatefromstring]: Data is not in a identify format.这可能是由于我的客户正在使用该死的 16 位位图。 我不认为我遇到过 16 位图像,但它似乎适用于 24 位,甚至 RLE 编码图像。

以上是关于使用 PHP 中的 GD 库将位图文件转换为 JPEG的主要内容,如果未能解决你的问题,请参考以下文章

如何将 jp2 图像转换为 jpg 文件?

将 GD-Sharp 流转换为位图

php使用GD库将图片圆角 解决背景变黑问题 以及 图片丢失问题

如何使用 php mpdf 库将多个 PDF 文件合并为一个 PDF

PHP 将 GD 图像转换为用于验证码的 CSS 代码

使用 PHP GD 转换为 alpha