[php]修正iPhone里的png文件为标准格式

本想“借”用一下iphone里漂亮的天气图标,没想到在pc上无法使用。google了一下才知道iphone里的png文件并不是标准格式,不知道什么原因,apple在png文件头之后加了一个非标准的CgBI数据段,IDAT段图像数据也没有传统的压缩数据头和尾,并且红色和蓝色是反的。国外已经有了把iphone上的png文件转换为标准格式的代码,我不太会编译,所以自己用php照猫画虎写了个转换函数。


转换后的效果:
png

使用方法:

iphone_fix_png($path);

运行后,修正后的图片会放到fixed文件夹内。

如果要修正一个目录下的所有png文件,可以这样做:

foreach (glob($path . '/*.png') as $image)
{
    
iphone_fix_png($image);
}

iphone_fix_png函数代码如下:

  1. /**
  2. * fix iPhone PNGs to PNG-compatible format
  3. *
  4. * @author: legend <legendsky@hotmail.com>
  5. * @copyright   UGiA.CN
  6. * @link: http://www.ugia.cn/?p=134 
  7. *
  8. * usage:
  9. * include('iphone_fix_png.php');
  10. *
  11. * iphone_fix_png($path);
  12. */
  13. function iphone_fix_png($file)
  14. {
  15.     $png_header = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; // PNG
  16.     $data_chunk = "\x49\x44\x41\x54"; // IDAT
  17.     $end_chunk  = "\x49\x45\x4e\x44"; // IEND
  18.     $cgbi_chunk = "\x43\x67\x42\x49"; // CgBI
  19.  
  20.     // read chunks
  21.     $size = filesize($file);
  22.     $fp = fopen($file, "r");   
  23.   
  24.     // check png header
  25.     $header = fread($fp, 8);   
  26.     if ($header != $png_header)
  27.     {
  28.         trigger_error("Not a PNG file!", E_USER_ERROR);
  29.         return false;
  30.     }
  31.    
  32.     // generate output path
  33.     $base = dirname($file);
  34.     preg_match("/(.+?)(\.png)$/i", basename($file), $m);
  35.     $filename   = $m[1];
  36.     $suffix     = $m[2];
  37.    
  38.     if (is_dir($base . "/fixed") || false != @mkdir($base . "/fixed", 0700))
  39.     {
  40.         $path = $base . "/fixed/" . basename($file);
  41.     }
  42.     else
  43.     {
  44.         $path = $base . "/" . $filename . "_fixed" . $suffix;
  45.     }
  46.    
  47.     // output stream
  48.     $fd = fopen($path, "w");
  49.     fwrite($fd, $png_header);
  50.    
  51.     $offset = 8;
  52.  
  53.     // do
  54.     while ($offset < $size)
  55.     {
  56.         $length = current(unpack('N', fread($fp, 4)));
  57.         $chunk = array (
  58.             'length' => pack('N', $length),
  59.             'name' => fread($fp, 4),
  60.             'data' => $length > 0 ? fread($fp, $length) : '',
  61.             'crc' => fread($fp, 4)
  62.         );
  63.        
  64.         $offset += 4 + 4 + $length + 4;
  65.        
  66.         // fix IDAT chunk
  67.         if ($chunk['name'] == $data_chunk)
  68.         {
  69.             $inflated = gzinflate($chunk['data']);
  70.             $deflated = gzcompress($inflated);
  71.  
  72.             $chunk['data'] = $deflated;
  73.             $chunk['length'] = pack('N', strlen($deflated));
  74.             $chunk['crc'] = pack('N', crc32($data_chunk . $deflated));
  75.         }      
  76.        
  77.         // drop cgbi chunk
  78.         if ($chunk['name'] != $cgbi_chunk)
  79.         {
  80.             fwrite($fd, join("", $chunk));
  81.         }
  82.     }
  83.  
  84.     fclose($fp);
  85.     fclose($fd);
  86.    
  87.     // flip the red/blue channels
  88.     $im = imagecreatefrompng($path);
  89.     imagesavealpha($im, true); // save alpha
  90.  
  91.     for ($i = 0; $i < imagesx($im); $i++)
  92.     {
  93.         for ($j = 0; $j < imagesy($im); $j++)
  94.         {
  95.             $rgba = imagecolorat($im, $i, $j);
  96.  
  97.             $a = ($rgba & 0x7F000000) >> 24;
  98.             $r = ($rgba & 0xFF0000) >> 16;
  99.             $g = ($rgba & 0x00FF00) >> 8;
  100.             $b = ($rgba & 0x0000FF);
  101.  
  102.             $color = imagecolorallocatealpha($im, $b, $g, $r, $a);
  103.  
  104.             imagesetpixel($im, $i, $j, $color);
  105.         }
  106.     }
  107.  
  108.     imagepng($im, $path);
  109. }

参考:
The iPhone Dev Wiki: PNG Images
iPhone PNG fixer-upper
The iPhone Dev Wiki: Apple Embedded Images
PNG文件结构分析

6 Comments »

  1. Hick said,

    December 31, 2007 @ 3:18 pm

    突然发现,小伙的 logo 很有水准!嘿嘿

  2. kiddd said,

    February 1, 2008 @ 12:39 pm

    文章不错,留记号

  3. test said,

    August 4, 2011 @ 2:41 pm

    娃哈哈

  4. bigmonstercai said,

    February 18, 2012 @ 3:43 pm

    没接触过php语言,不知道怎么运行这个脚本啊?直接在cmd中输入iphone_fix_png($path)吗?

  5. bigmonstercai said,

    August 15, 2013 @ 11:44 am

    测试过了,没用,还是只能还原一半。

  6. 崔允局匠 said,

    December 8, 2013 @ 11:13 am

    杭州最好的夜场是杭州东方魅力www.dongfangmeili.cn
    杭州最好的ktv是哪儿?是杭州东方魅力www.dongfangmeili.cn

    杭州夜场招聘首选杭州东方魅力www.dongfangmeili.com.cn

    杭州最好的夜总会是杭州东方魅力www.dongfangmeili.com.cn

    杭州东方魅力官方网站欢迎你 联系电话:13666653761 官方微信:dongfangmeili
    杭州最好的ktv是www.dongfangmeili.cn
    杭州夜场招聘杭州夜场招聘www.dongfangmeili.cn

RSS feed for comments on this post

Leave a Comment