使用 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的主要内容,如果未能解决你的问题,请参考以下文章
php使用GD库将图片圆角 解决背景变黑问题 以及 图片丢失问题