[GD] 生成bmp格式的图片(imagebmp)

GD库里没有生成bmp图片的函数,所以自己写了一个,这个函数尚有一个压缩算法没有写,不过已经够用了。需要的同学可以看看。

int imagebmp ( resource image [, string filename [, int bit [, int compression]]] )

$im: 图像资源
$filename: 如果要另存为文件,请指定文件名,为空则直接在浏览器输出
$bit: 图像质量(1、4、8、16、24、32位)
$compression: 压缩方式,0为不压缩,1使用RLE8压缩算法进行压缩

注意:这个函数仍然需要GD库的支持。

Demo:

$im = imagecreatefrompng("test.png");
imagebmp($im);
imagedestroy($im);

Source: imagebmp.php

下载: imagebmp.php
  1. /**
  2. * 创建bmp格式图片
  3. *
  4. * @author: legend(legendsky@hotmail.com)
  5. * @link: http://www.ugia.cn/?p=96
  6. * @description: create Bitmap-File with GD library
  7. * @version: 0.1
  8. *
  9. * @param resource $im          图像资源
  10. * @param string   $filename    如果要另存为文件,请指定文件名,为空则直接在浏览器输出
  11. * @param integer  $bit         图像质量(1、4、8、16、24、32位)
  12. * @param integer  $compression 压缩方式,0为不压缩,1使用RLE8压缩算法进行压缩
  13. *
  14. * @return integer
  15. */
  16. function imagebmp(&$im, $filename = '', $bit = 8, $compression = 0)
  17. {
  18.     if (!in_array($bit, array(1, 4, 8, 16, 24, 32)))
  19.     {
  20.         $bit = 8;
  21.     }
  22.     else if ($bit == 32) // todo:32 bit
  23.     {
  24.         $bit = 24;
  25.     }
  26.  
  27.     $bits = pow(2, $bit);
  28.    
  29.     // 调整调色板
  30.     imagetruecolortopalette($im, true, $bits);
  31.     $width  = imagesx($im);
  32.     $height = imagesy($im);
  33.     $colors_num = imagecolorstotal($im);
  34.    
  35.     if ($bit <= 8)
  36.     {
  37.         // 颜色索引
  38.         $rgb_quad = '';
  39.         for ($i = 0; $i < $colors_num; $i ++)
  40.         {
  41.             $colors = imagecolorsforindex($im, $i);
  42.             $rgb_quad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
  43.         }
  44.        
  45.         // 位图数据
  46.         $bmp_data = '';
  47.  
  48.         // 非压缩
  49.         if ($compression == 0 || $bit < 8)
  50.         {
  51.             if (!in_array($bit, array(1, 4, 8)))
  52.             {
  53.                 $bit = 8;
  54.             }
  55.  
  56.             $compression = 0;
  57.            
  58.             // 每行字节数必须为4的倍数,补齐。
  59.             $extra = '';
  60.             $padding = 4 - ceil($width / (8 / $bit)) % 4;
  61.             if ($padding % 4 != 0)
  62.             {
  63.                 $extra = str_repeat("\0", $padding);
  64.             }
  65.            
  66.             for ($j = $height - 1; $j >= 0; $j --)
  67.             {
  68.                 $i = 0;
  69.                 while ($i < $width)
  70.                 {
  71.                     $bin = 0;
  72.                     $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0;
  73.  
  74.                     for ($k = 8 - $bit; $k >= $limit; $k -= $bit)
  75.                     {
  76.                         $index = imagecolorat($im, $i, $j);
  77.                         $bin |= $index << $k;
  78.                         $i ++;
  79.                     }
  80.  
  81.                     $bmp_data .= chr($bin);
  82.                 }
  83.                
  84.                 $bmp_data .= $extra;
  85.             }
  86.         }
  87.         // RLE8 压缩
  88.         else if ($compression == 1 && $bit == 8)
  89.         {
  90.             for ($j = $height - 1; $j >= 0; $j --)
  91.             {
  92.                 $last_index = "\0";
  93.                 $same_num   = 0;
  94.                 for ($i = 0; $i <= $width; $i ++)
  95.                 {
  96.                     $index = imagecolorat($im, $i, $j);
  97.                     if ($index !== $last_index || $same_num > 255)
  98.                     {
  99.                         if ($same_num != 0)
  100.                         {
  101.                             $bmp_data .= chr($same_num) . chr($last_index);
  102.                         }
  103.  
  104.                         $last_index = $index;
  105.                         $same_num = 1;
  106.                     }
  107.                     else
  108.                     {
  109.                         $same_num ++;
  110.                     }
  111.                 }
  112.  
  113.                 $bmp_data .= "\0\0";
  114.             }
  115.            
  116.             $bmp_data .= "\0\1";
  117.         }
  118.  
  119.         $size_quad = strlen($rgb_quad);
  120.         $size_data = strlen($bmp_data);
  121.     }
  122.     else
  123.     {
  124.         // 每行字节数必须为4的倍数,补齐。
  125.         $extra = '';
  126.         $padding = 4 - ($width * ($bit / 8)) % 4;
  127.         if ($padding % 4 != 0)
  128.         {
  129.             $extra = str_repeat("\0", $padding);
  130.         }
  131.  
  132.         // 位图数据
  133.         $bmp_data = '';
  134.  
  135.         for ($j = $height - 1; $j >= 0; $j --)
  136.         {
  137.             for ($i = 0; $i < $width; $i ++)
  138.             {
  139.                 $index  = imagecolorat($im, $i, $j);
  140.                 $colors = imagecolorsforindex($im, $index);
  141.                
  142.                 if ($bit == 16)
  143.                 {
  144.                     $bin = 0 << $bit;
  145.  
  146.                     $bin |= ($colors['red'] >> 3) << 10;
  147.                     $bin |= ($colors['green'] >> 3) << 5;
  148.                     $bin |= $colors['blue'] >> 3;
  149.  
  150.                     $bmp_data .= pack("v", $bin);
  151.                 }
  152.                 else
  153.                 {
  154.                     $bmp_data .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
  155.                 }
  156.                
  157.                 // todo: 32bit;
  158.             }
  159.  
  160.             $bmp_data .= $extra;
  161.         }
  162.  
  163.         $size_quad = 0;
  164.         $size_data = strlen($bmp_data);
  165.         $colors_num = 0;
  166.     }
  167.  
  168.     // 位图文件头
  169.     $file_header = "BM" . pack("V3", 54 + $size_quad + $size_data, 0, 54 + $size_quad);
  170.  
  171.     // 位图信息头
  172.     $info_header = pack("V3v2V*", 0x28, $width, $height, 1, $bit, $compression, $size_data, 0, 0, $colors_num, 0);
  173.    
  174.     // 写入文件
  175.     if ($filename != '')
  176.     {
  177.         $fp = fopen($filename, "wb");
  178.  
  179.         fwrite($fp, $file_header);
  180.         fwrite($fp, $info_header);
  181.         fwrite($fp, $rgb_quad);
  182.         fwrite($fp, $bmp_data);
  183.         fclose($fp);
  184.  
  185.         return 1;
  186.     }
  187.    
  188.     // 浏览器输出
  189.     header("Content-Type: image/bmp");
  190.     echo $file_header . $info_header;
  191.     echo $rgb_quad;
  192.     echo $bmp_data;
  193.    
  194.     return 1;
  195. }

参考资料:BMP文件格式分析 (出处没有找到…)

写完这个之后,freeman告诉俺一个网址:http://jpexs.wz.cz/?page=php&Language=eng。这里已经对读写bmp、ico、ani、cur等文件都写全了。本来还想继续写ico的,现在不用写了。

原创文章,转载请注明出处。

9 Comments »

  1. andot said,

    March 24, 2006 @ 10:35 pm

    太牛了!不过还是不知道跟图标有什么关系。

  2. 五帝 said,

    March 25, 2006 @ 9:24 am

    强~~
    不过我想更多的时候人们希望 GD 能读取 BMP。

  3. 靓华 said,

    March 27, 2006 @ 5:47 pm

    不知道可否写一个支持动态GIF的呢?嘻嘻~~~

  4. legend said,

    March 27, 2006 @ 6:15 pm

    gif格式太复杂了,也没有找到详细的中文格式文档。

  5. chuangyi-gs said,

    April 21, 2006 @ 3:37 pm

    我觉得生成icon的很好用 可以根据个人头像生成16×16 的favicon.ico显示在浏览器的url前面

  6. corsak said,

    April 28, 2006 @ 3:13 am

    http://phpthumb.sourceforge.net

    这里也有类似的.

  7. corsak said,

    April 28, 2006 @ 3:16 am

    生成网站ICON的系统, 直接用就可以了. 我好多客户的icon是用这个生成的.

    http://www.html-kit.com/favicon/gallery/

  8. macleo said,

    May 11, 2006 @ 6:23 am

    嗯。厉害,研究的很透彻!不错!佩服啊!佩服!

  9. 不好用啊 said,

    April 24, 2012 @ 5:35 pm

    图像质量设置不了啊。

RSS feed for comments on this post

Leave a Comment