PHPで、JPEGファイルのコメントデータやExif情報を削除する


[The PHP JPEG Metadata Toolkit]:http://www.ozhiker.com/electronics/pjmt/
[PHP Exif Library]:http://lsolesen.github.io/pel/
[PHP-PNG]:http://qiita.com/sounisi5011/items/e685ed1501a3cd979a3c
[関連記事]:#%E9%96%A2%E9%80%A3%E8%A8%98%E4%BA%8B

## 概要

JPEGファイルのコメントデータ及びExif情報を、**ライブラリを使用して削除します**。

前投稿「[PHPで、PNGファイルのコメントデータを削除する][PHP-PNG]」はPHP標準関数だけで処理しましたが、
PNGと違ってJPEGの直接操作は断念したためライブラリ使用の方法を投稿します。
前回同様、Windows版PHP 5.4.5での動作は確認できています。

他の画像形式のコメントデータを削除したい場合、[関連記事]を参照してください。

## 使用ライブラリ

[The PHP JPEG Metadata Toolkit]

PHP4での動作を前提とした設計となっており、かなり古米のライブラリです。一部修正が必要ですが、きちんと動作しました。
このライブラリそのものには、[PHP Exif Library]のようにExif情報の削除関数などは存在しません。
そこで、[The PHP JPEG Metadata Toolkit]の関数で取得したデータ配列を自前で加工し、削除します。

以下のファイル構成となっていることを前提とします。
`clean_jpeg.php`がテストコードです。

```text
clean_jpeg.php

The_PHP_JPEG_Metadata_Toolkit/
	EXIF.php
	EXIF_Makernote.php
	EXIF_Tags.php
	IPTC.php
	JFIF.php
	JPEG.php
	Photoshop_IRB.php
	PictureInfo.php
	PIM.php
	pjmt_utils.php
	Unicode.php
	XML.php
	XMP.php
	Makernotes/
		agfa.php
		canon.php
		casio.php
		epson.php
		fujifilm.php
		konica_minolta.php
		kyocera.php
		nikon.php
		olympus.php
		panasonic.php
		Pentax.php
		ricoh.php
		sony.php
```

※`JFIF.php`と`PictureInfo.php`は今回のコードでは使用されませんが、一応記載しておきます。
※`JFIF.php`と`PictureInfo.php`以外のファイルはライブラリにより読み込まれるため、全て必要です。

### 問題の一部修正

一部のファイルが`<?php`ではなく`<?`で始まるPHPコードとなっているため、修正しないとHTMLとして解釈されライブラリのコードが直接表示されていまいます。

…だったはずなのですが、再ダウンロードしてみたら全て`<?php`で始まっていました。
おかしいな…とりあえずメモ。

### なお、PHP Exif Libraryは…

Exif情報を削除するだけなら、[PHP Exif Library]の方がもっと簡単にできます。

しかし[PHP Exif Library]は、コメントデータの操作には対応していません。
携帯端末で再配布を防止するための`copy="NO"`や`kddi_copyright=on`の追加も不可能です。
一方、[The PHP JPEG Metadata Toolkit]はExif以外のJPEGファイル追加ヘッダの操作も可能です。


コメントデータの操作も行う場合、[The PHP JPEG Metadata Toolkit]が最適です。
~~化石と化したPHP4対応のコードですが…~~

## コード

```php:clean_jpeg.php
<?php
/**
 * 変数定義
 */
//対象のJPEGファイル
$filename     = 'example.jpg';
//コメントデータおよびExif情報を削除したJPEGファイルのファイル名(作成するファイル名)
$out_filename = 'example.clean.jpg';





/**
 * ライブラリ読み込み
 */
require 'The_PHP_JPEG_Metadata_Toolkit/EXIF.php';





/**
 * 対象ファイルのJPEGヘッダを取得
 */
$jpeg_header_data=get_jpeg_header_data($filename);



/**
 * コメントデータを削除
 */
if(is_array($jpeg_header_data)){
	foreach($jpeg_header_data as $k=>$v){
		$seg_name=$v['SegName'];
		if(strcmp($seg_name,'COM')===0){
			unset($jpeg_header_data[$k]);
		}
	}
}



/**
 * Exif情報の配列を取得
 */
$exif_data=get_EXIF_JPEG($filename);
/**
 * Exif情報を削除
 * Exif情報の配列にある値から配列のものを探し、さらにその値の配列からキーが数値の値を削除する。
 * つまりどういうことかというと…
 *
 * Before:
 *
 *  Array(
 *  	[0] => Array(
 *  		[Tags Name] => TIFF
 *  		[Tiff Offset] => 7894
 *  		[274] => Array(
 *  			...
 *  		)
 *  		[0] => Array(
 *  			...
 *  		)
 *  		...
 *  	)
 *  	[1] => Array(
 *  		[Tags Name] => TIFF
 *  		[Tiff Offset] => 7894
 *  		[259] => Array(
 *  			...
 *  		)
 *  		...
 *  	)
 *  	[Makernote_Tag] => 
 *  	[Tags Name] => TIFF
 *  	[Byte_Align] => MM
 *  )
 *
 * After:
 *
 *  Array(
 *  	[0] => Array(
 *  		[Tags Name] => TIFF
 *  		[Tiff Offset] => 7894
 *  	)
 *  	[1] => Array(
 *  		[Tags Name] => TIFF
 *  		[Tiff Offset] => 7894
 *  	)
 *  	[Makernote_Tag] => 
 *  	[Tags Name] => TIFF
 *  	[Byte_Align] => MM
 *  )
 *
 * Note:
 *  この処理は適当にいじった結果うまく動作しているにすぎず、
 *  ライブラリの構造に則った最適な処理への変更が必要と思われる。
 */
if(is_array($exif_data)){
	foreach($exif_data as &$var){
		/* 値が配列の場合、キーが数値の値を削除 */
		if(is_array($var)){
			$var=array_intersect_ukey($var,$var,function($key){
				return !is_int($key) ? 0 : 1;
			});
		}
	}
}
/* JPEGヘッダに改変したExif情報を保存 */
$jpeg_header_data=put_EXIF_JPEG(
	$exif_data,
	$jpeg_header_data
);



/**
 * ファイルを保存
 */
put_jpeg_header_data(
	$filename,
	$out_filename,
	$jpeg_header_data
);
```

## やっていること

ライブラリにより取得したデータを弄り回しています。

コメントデータの削除は`put_jpeg_Comment`の内部処理を参考にしていますが、
Exif情報の削除は`get_EXIF_JPEG`関数の出力データを**適当にいじって動作させています**。
ライブラリの処理は追っていないため、これが正しい方法なのかは不明です。
とりあえず、Google Chromeと以下のソフトでエラーを吐かず読み込めるのでよしとしています。

* [F6 Exif Version 0.9.0b](http://www.ryouto.jp/f6exif/)
* [Multi Comment Editor 1.02](http://hp.vector.co.jp/authors/VA012780/)
* [Paint.NET V4.0.3](http://www.getpaint.net/)
* ペイント バージョン 6.1
* [IrfanView 4.25](http://www.irfanview.com/)
* [IrfanView 4.38](http://www.irfanview.com/)
* [XnView 1.97.8](http://www.xnview.com/)
* Windows フォト ビューアー

繰り返しますが、Exif情報の削除は**適当にいじって動作させています**。
ライブラリの処理に沿った正しい方法がある場合、コメントにてお知らせください。

## 参考サイト

* [The PHP JPEG Metadata Toolkit - PHP::PEAR - dozo PukiWiki](http://dozo.matrix.jp/pear/index.php/PHP/Liblary/The%20PHP%20JPEG%20Metadata%20Toolkit.html)  
  The PHP JPEG Metadata Toolkitを知ったサイトです。コメントデータの読み書きについてのコードが記載されています。
* [exif_read_data() の使えないPHPでExifを読み出す: Usoinfo blog](http://blog.usoinfo.info/article/181900261.html)  
  Exif情報の読み込みについてのコードと、必要ファイルについての記述があるサイトです。
* [The PHP JPEG Metadata Toolkit - Documentation](http://www.ozhiker.com/electronics/pjmt/library/documentation/example.html)  
  公式ドキュメントのサンプルページ。一番下の「Writing Metadata Information」を読んでいなければExif情報の書き込み方法が分からず、悶々としていたと思います。

## PNGにJPEGときたら…?

~~GIFについてはJPEGより先に仕様を調べていたのですが、PNGより難しそうなフォーマットであるために希望が見えません。
というより、PNGが簡単すぎてゆとりになってしまったのかも…
GIFのコメントデータ用ライブラリ無いかな…~~

<ins>GIFのコメントデータの削除方法について投稿しました。</ins>
[関連記事]を参照してください。

## 最後に

先人の創ったライブラリって、本当に便利ですね。
車輪を再発明し、あらゆる環境でテストする手間が省けます。

~~この調子でGIFのコメントデータ用ライブラリも見つからないかな…~~

## 関連記事

* [PHPで、PNGファイルのコメントデータを削除する - Qiita][PHP-PNG]
* [PHPで、GIFファイルのコメントデータを削除する - Qiita](http://qiita.com/sounisi5011/items/dad3ce14adc74f76f125)