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

我一直在尝试找出一种使用 PHP 中的 GD 库将位图文件转换为 JPEG 格式的方法。

我尝试了许多实现,但似乎没有任何效果。我曾试图告诉我的客户他们不应该使用 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,我将回复其中一张图片。

标签: php bitmap gd jpeg


【解决方案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 掩码。

【解决方案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 编码图像。
猜你喜欢
  • 2020-04-24
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
相关资源
最近更新 更多