GD 利用、bitmap 形式画像の読み書き

side menu

  • めも一覧

  • GD 関連

    • GDによる画像読み書き簡易化関数の作成
    • GD 利用、bitmap 形式画像の読み書き
    • カウントダウン日数画像出力ソース配布と設置解説
  • SQL関連一覧

    • MySQLでの日付期間比較
    • SQLiteでの日付期間比較
    • SQLiteでの連続日付view作成=カレンダーテーブル
    • SQLiteでの曜日計算
    • MySQLでヒストグラム作成
    • 入れ子集合モデルでサイトマップ by SQLite
    • 入れ子集合モデルでサイトマップ by MySQL
    • ランク付け:by MySQL
    • 抜けデータ補完:by MySQL
    • カンマ区切りデータ:by MySQL
    • row_number関数を利用して当番表作成:by MySQL8,mariaDB10
    • window関数解説:by MySQL8,mariaDB10
  • その他

    • phpによる月齢計算クラス
  • miztools のサイトマップ
     このサイトのrss
    miztools の更新履歴

GD 利用、bitmap 形式画像の読み書き

オンラインの phpマニュアルには、user note として、各関数解説ページの下部に、利用法や、注意点などが載っている。 GD では未対応のビットマップを読み込んだり、書き出す関数が紹介されていたので、少々手を加えて、使いやすくしてみました。
GDによる画像読み書き簡易化関数のimagecreatefromfileやimage_outputで、ビットマップ形式も取り扱いたいときに、この2つの関数を「gd_bmp_util.php」で保存してincludeします。
利用上の注意: strlen や substr, strpos で1byte単位の作業を行う必要がありますが、 多バイト文字利用サイトでは、時に mbstring.func_overload が 0 以外のことがあります。
strlen や substr, strpos を多バイト対応にしてしまうと、バイト列作業が狂いますので、 「 Overload str*() functions」 少なくともこれはoffとしなければなりません。
よって、mbstring.func_overload は 0,1,4,5 のいずれかを指定してください。
この項目は、php.ini でしか設定出来ないけれど、共有サーバーだと、通常0になってるはず。一応 phpinfo() などでご確認下さい。

  • bitmap 形式画像の読み込み : ImageCreateFromBMP


    参考url http://jp2.php.net/manual/ja/function.imagecreate.php#53879 : 16bit 対応修正 http://jp2.php.net/manual/ja/function.imagecreate.php#81604

  • bitmap 形式画像を出力 : imageBMP

    出力形式は 24bit true color ビットマップ のみです。
    参考url http://php.benscom.com/manual/ja/ref.image.php#63689

  • bitmap 形式でモノクローム画像を出力 : imageMonoBMP

    モノクローム画像の要望もあるようなので、読み込み時の情報逆算で出力関数を作ってみました。
    とりあえず、パレットデータは、黒かそれ以外で判定、8ピクセルで1バイトデータになるので横幅は8の倍数限定として、細かい換算を省きました。

  • 4ビットや8ビットカラー出力用は、パレット番号変換が一般化しにくいので見送りです。 先にパレット番号へ変換した配列で画像データを与えて、pack していけばよさそうではあるけど。

  • 以下に3つの関数をまとめて表示します。
    /*
     *  GD 利用、bitmap 形式画像の読み込み
     * comment 編集miz [2009/04/25] →公開サイト移動 [2012/08/28]
     * @param $filename : 実行中phpからアクセスできる画像パス名
     * @return GD truecolor イメージオブジェクト
          作成失敗時 false
    /*********************************************/
    /* Fonction: ImageCreateFromBMP */
    /* Author: DHKold */
    /* Date: The 15th of June 2005 */
    /* Version: 2.0B */
    /* http://php.benscom.com/manual/ja/function.imagecreate.php#53879 */
    /*********************************************/
    function ImageCreateFromBMP($filename){
    //  画像ファイルをバイナリーモードでopen
    if (! $f1 = fopen($filename,"rb")) return FALSE;
    
    //1 : 概要データのロード:file_type, file_size, reserved, bitmap_offset
    $FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
    
    //1' : file type のチェック
    if ($FILE['file_type'] != 19778) return FALSE;
    // 19778=> 0x4D42 ->`MB`  先頭2バイトに BM と入っている、リトルエンディアンで読み出すとMB となる
    
    //2 : BMPデータのロード:
    $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']);
    
    //2' : 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;
    
    //3 : PALETTEデータのロード:
    //  16 bit images (= color 65536 )以上ではパレットを持っていないので、8bit colorまでを対象とする
    $PALETTE = array();
    if ($BMP['colors'] <  65536){
    	$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
    }
    
    //4 : imageデータのロード:ビットごとの色情報読みとり
    $IMG = fread($f1,$BMP['size_bitmap']);
    //4' : file からの読みとり完了
    fclose($f1);
    
    //5 : GD による TrueColor イメージ作成
    $res = imagecreatetruecolor($BMP['width'],$BMP['height']);
    $P = 0;
    $Y = $BMP['height']-1;
    $VIDE = chr(0);	//  桁合わせ用
    //5' :  TrueColor イメージの各ビットに色設定
    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){ 
    // 8bit palette mode, 256colors
    			$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]);
    		// 1 dot 処理完了
    		$X++;
    		$P += $BMP['bytes_per_pixel'];
    	}
    	//  x 方向完了
    	$Y--;
    	$P+=$BMP['decal'];
    }
    //  all line end
    
    //6 : 作業終了: TrueColor イメージを返す
    return $res;
    }
    
    /*
     * bitmap 形式画像を出力
     * @param $image : GD2.0 true color object (ImageCreateTrueColorなどで作ったイメージオブジェクトを指定)
     * @param $filename : 出力先ファイル名、省略時は、php://output =標準出力へ出力。
     * return 成功時 true ,  出力先に Windows BMP file(24bit true color 形式のみ対応) が出来る
         失敗時 false
    */
    function imageBMP (&$image, $filename = false){
    	if (!$image) return false;
    	if ( empty($filename) ) $filename = 'php://output';
    	$f = fopen ($filename, "w");
    	if ( false === $f) return false;	/*  データ型も比較  書き換え時に間違って!==としてたので修正 2015-10-18  */
    
    	//Image dimensions
    	$biWidth = imagesx($image);
    	$biHeight = imagesy($image);
    	$biBPLine = $biWidth * 3;
    	$biStride = ($biBPLine + 3) & ~3;
    	$biSizeImage = $biStride * $biHeight;
    	$bfOffBits = 54;
    	$bfSize = $bfOffBits + $biSizeImage;
    	//BITMAPFILEHEADER
    	fwrite ($f, 'BM', 2);
    	fwrite ($f, pack ('VvvV', $bfSize, 0, 0, $bfOffBits));
    	//BITMAPINFO (BITMAPINFOHEADER)
    	fwrite ($f, pack ('VVVvvVVVVVV', 40, $biWidth, $biHeight, 1, 24, 0, $biSizeImage, 0, 0, 0, 0));
    
    	$numpad = $biStride - $biBPLine;
    	for ($y = $biHeight - 1; $y >= 0; --$y){	// 画像の下端からデータ書き出し
    		for ($x = 0; $x < $biWidth; ++$x){
    			$col = imagecolorat ($image, $x, $y);
    			fwrite ($f, pack ('V', $col), 3);
    		}
    		for ($i = 0; $i < $numpad; ++$i)
    			fwrite ($f, pack ('C', 0));
    	}
    	fclose ($f);
    	return true;
    }
    
    /* 
     * モノクローム(1ビットカラー、2値画像) BMP出力 
     * *  width は8の倍数のみ としている , 8で割り切れないときは出力せずfalseを返す。
     * *  $palette = [0x000000, 0xffffff]; 黒以外は 白に置き換え
     * @param $image : GD2.0 object (ImageCreate などで作ったイメージオブジェクトを指定)
     * @param $filename : 出力先ファイル名、省略時は、php://output =標準出力へ出力。
     * return 成功時 true , 出力先に Windows BMP file(1bit color 形式) が出来る
         失敗時 false
    */
    function  imageMonoBMP(&$image,  $filename = false  ){
    	if (!$image) return false;
    	$bits_per_pixel = 1 ;
    	$palette = [0x000000, 0xffffff];
    	$colors  = 2;
    
    	if ( empty($filename) ) $filename = 'php://output';
    	$f = fopen ($filename, "w");
    	if ( false === $f) return false;
    	//Image dimensions
    	$biWidth = imagesx($image);
    	if(($biWidth % 8) !=0 ) return false;
    	$biHeight = imagesy($image);
    	$biBPLine = $biWidth / 8;	//  8pixel で 1 byte
    	$biStride = ($biBPLine + 3) & ~3;	//  1行を4の倍数幅に合わせる
    	$biSizeImage = $biStride * $biHeight;
    	$bfOffBits = 0x3e;
    		//  palette なしで 54 + palette あり monochrome 2*4bit =62 = 0x3e 
    
    	$bfSize = $bfOffBits + $biSizeImage;
    
    	//BITMAPFILEHEADER
    	fwrite ($f, 'BM', 2);
    	$str = pack ('VvvV', $bfSize, 0, 0, $bfOffBits);
    	fwrite ($f, $str);
    	//BITMAPINFO (BITMAPINFOHEADER)
    	$str =  pack ('VVVvvVVVVVV', 40, $biWidth, $biHeight, 1, $bits_per_pixel, 0, $biSizeImage, 0, 0, 0, 0);
    	fwrite ($f, $str);
    	//  PALETTEINFO
    	$str =  pack ('V'.$colors, $palette[0], $palette[1]) ;
    	fwrite ($f, $str);
    
    	// palette 番号で画像出力
    	$numpad = $biStride - $biBPLine;
    	for ($y = $biHeight - 1; $y >= 0; --$y){	// 画像の下端からデータ書き出し
    		for ($x = 0; $x < $biWidth; $x+=8){
    			$c = 0;
    			for($i=0; $i<8; $i++){	//  8ピクセルを1バイト数値にする
    			$col = imagecolorat ($image, $x+$i, $y);
    			$col = ($col==0)?0:1;
    			$c += $col << (7-$i) ;	//  左に ビットシフトする (各シフトは "2をかける" 意味 )
    			}
    			$str = pack ('V', $c) ;
    			fwrite ($f, $str, 1);	//  1 byte 分は書くように確保
    		}
    		for ($i = 0; $i < $numpad; ++$i)	fwrite ($f, pack ('C', 0));
    	}
    	fclose ($f);
    return true;
    }
    

[初回設置日 2012-08-28]
[修正日 2015-10-18] : imageBMP関数内の fopen返値を false との比較にしたとき 型考慮比較演算子の勘違い修正
[ 2015-10-18] : モノクローム画像出力関数も追加
[最終更新日 2018-02-12]

| ページtopへ | miztools top | site map | cake.org