概要
PNGファイルのコメントデータを、PHPの標準関数だけで削除してみます。
PNGファイルの操作ライブラリが見つからなかったため、半日かけて仕様とか色々と調べ、とりあえず動くものはできました。
なお、これを書くまでバイナリデータ操作なんてやったことも無いので、パフォーマンスについては分からないし、もしかしたらエラーが発生するかもしれないので、
ここがおかしいとか、エラーが出るとかあったらコメントにて報告してください。
一応、Windows版PHP 5.4.5での動作は確認できています。
また、正常にコメントデータが削除でき、削除したファイルも問題なく取り扱えるようです。
他の画像形式のコメントデータを削除したい場合、関連記事を参照してください。
注意
私はバイナリデータ操作を行う処理の実装経験がありません。
このため、本投稿で紹介する処理はメモリ使用率・速度・パフォーマンスなどの点で劣っている可能性があり、実用的でない恐れがあります。
コード
<?php
/**
* 変数定義
*/
//対象のPNGファイル
$filename = 'example.png';
//コメントデータを削除したPNGファイルのファイル名(作成するファイル名)
$out_filename = 'example.clean.png';
/**
* 定数定義
*/
//PNGシグネチャ
define('PNG_SIGNATURE', "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a");
/* 対象のPNGファイルを展開 */
$fp = fopen($filename, 'rb');
/* PNGシグネチャが一致するかチェック */
if(fread($fp, 8) !== PNG_SIGNATURE){
/* 一致しない場合、エラーメッセージを出し強制終了 */
echo '指定されたファイルはPNG形式ではありません';
//ファイルを閉じる
fclose($fp);
exit;
}
//新しいファイルデータ保存用の変数を定義
//予めPNGシグネチャを代入しておく
$new_png_data = PNG_SIGNATURE;
/* PNGファイルをチャンクデータ毎に読み込み、コメント部分を除いたPNGデータを取得する */
/**
* チャンクデータの構造:
* Length: データ本体の長さ。CRCは含めない。常に4バイト
* Chunk Type: チャンクデータの種別。常に4バイト
* Chunk Data: データ本体
* CRC: データの種別とデータ本体を元に計算したもの…らしい。常に4バイト
*/
while( $chunkHeader = fread($fp, 8) ){
//先頭8バイトから、チャンクデータの長さと種別を取得する
$chunk = unpack('Nsize/a4type', $chunkHeader);
//チャンクデータの種別
$type = $chunk['type'];
//チャンクデータの長さ
$size = $chunk['size'];
//チャンクデータ本体
//Note: サイズ0の場合、fread関数がエラーを出すため空文字とする
$data = (0 < $size) ? fread($fp, $size) : '';
//CRC
$crc = fread($fp, 4);
/**
* チャンクデータの種別が "tEXt" "zTXt" "iTXt" のいずれかの場合、コメントデータとしてスキップし、
* 新しいファイルデータに追加しない。
*/
if(
$type === "\x74\x45\x58\x74" ||
$type === "\x7a\x54\x58\x74" ||
$type === "\x69\x54\x58\x74"
){
continue;
}
//現在のチャンクデータを新しいファイルのデータに追加する
$new_png_data .= $chunkHeader . $data . $crc;
}
//ファイルを閉じる
fclose($fp);
/**
* ファイルを保存
*/
file_put_contents($out_filename, $new_png_data);
やっていること
PNGファイルは先頭8バイトのPNGシグネチャに続き、チャンクデータが順に続く構造になっています。
このコードでは、各チャンクデータを順に読み込み、コメントデータを保存しているチャンクデータを除いたPNGデータをファイルに出力するようにしています。
参考サイト
-
How can I read PNG Metadata from PHP? - Stack Overflow
このコードが全ての始まりだったといっても過言ではありません。
このコードを見つけなければ、きっとPNGの仕様を調べようとは思わず、今頃ライブラリが無いか知恵袋で聞いていたはずです。
Andrew Mooreさん、ありがとうございます! -
PNG ファイルフォーマット
結構参考にしました。
とてもわかり易くオススメなのですが、このサイトのドメインwww14.ocn.ne.jpにアクセスすると「OCN Page ON サービス終了」というメッセージが出るので、近々閉鎖してしまうかも知れません… -
Python PNG画像を自力で出力する その1 : fujishinko 雑記帳
CRCの求め方について参考にしました。
…本当に参考にしていたのかは、出来たコードを見る限り不明ですが…
JPEGやGIFについて
このコードは元々、PNGファイルのコメントデータに携帯端末用の再配布禁止命令kddi_copyright=on
を加えるため書いたものです。
作れたら、JPEGやGIFのコメントデータ操作についても書きます。
JPEGとGIFのコメントデータ及びExif情報の削除方法について投稿しました。
関連記事を参照してください。
最後に
PNGファイルの構造が、とても扱いやすいものと実感出来ました、マル
(GIFファイルの構造は…なんかややこしそう…orz)