LoginSignup
6
9

More than 5 years have passed since last update.

PHPで、PNGファイルのコメントデータを削除する

Last updated at Posted at 2014-07-31

概要

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データをファイルに出力するようにしています。

参考サイト

JPEGやGIFについて

このコードは元々、PNGファイルのコメントデータに携帯端末用の再配布禁止命令kddi_copyright=onを加えるため書いたものです。
作れたら、JPEGやGIFのコメントデータ操作についても書きます。

JPEGとGIFのコメントデータ及びExif情報の削除方法について投稿しました。

関連記事を参照してください。

最後に

PNGファイルの構造が、とても扱いやすいものと実感出来ました、マル
(GIFファイルの構造は…なんかややこしそう…orz)

関連記事

6
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
9