Source Code:

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