JFIFを消すのはまずいかもしれんので、APP0だけは許容する。
以前にJPEGの仕様を見て、パーサーを作って、HTMLのテーブルをドットに使ってコピペできない画像みたいに出力した事があるので、
JPEGに関してはあまり苦労せずにできたが、バイナリ文字列を数値へ変換したりすることを忘れてて躓いたry
a.pl
use strict; my ($fh_in, $fh_out); my ($marker, $length, $buffer); my $JPEG_MARKER = "\xFF\xD8"; my $SOI_MARKER = "\xFF\xDA"; print "in : $ARGV[0]\n"; print "out: $ARGV[1]\n"; open($fh_in, '<', $ARGV[0]) || die 'cant open file'; read($fh_in, $marker, 2); if($marker ne $JPEG_MARKER){ die 'not jpeg file'; } open($fh_out, '>', $ARGV[1]) || die 'cant open file'; binmode($fh_in); binmode($fh_out); print $fh_out "$JPEG_MARKER"; while(1){ # read Marker read($fh_in, $marker, 2) || die 'error file'; if($marker eq $SOI_MARKER){ print $fh_out "$marker"; last; } #read Length read($fh_in, $length, 2); my $len = vec($length, 0, 16); printf("MARKER:%s, LENGTH:%04X\n", uc(unpack("H*", $marker)), $len); #read Data (datasize = length - lengthdata(2byte)) read($fh_in, $buffer, $len - 2); # no output APP1-15, COMMENT if(not($marker ge "\xFF\xE1" && $marker le "\xFF\xE9") || $marker ne "\xFF\xFE"){ print $fh_out "$marker"; print $fh_out "$length"; print $fh_out "$buffer"; }else{ print "DELETE!!\n"; } } while(read($fh_in, $buffer, 4096)){ print $fh_out "$buffer"; } close($fh_in); close($fh_out);
実行
ある画像に対して行うとこんな感じ。
>perl a.pl a.jpg b.jpg
in : a.jpg
out: b.jpg
MARKER:FFE0, LENGTH:0010
MARKER:FFE1, LENGTH:0022
DELETE!!
MARKER:FFDB, LENGTH:0043
MARKER:FFDB, LENGTH:0043
MARKER:FFC0, LENGTH:0011
MARKER:FFC4, LENGTH:001F
MARKER:FFC4, LENGTH:00B5
MARKER:FFC4, LENGTH:001F
MARKER:FFC4, LENGTH:00B5
基本はコピーするだけなので、複雑な処理はない。
ただ、一部のマーカーは画像には関係ないので切り捨てるだけ。
確認のために出したログが不恰好だが、MARKERは全てFFxxとなっており、しっかりマーカーを読み取れている。
作成したデータも36byte小さくなり、FFE1部分が書き出されていない事が確認できた。
めも
2chのPerl質問スレ44の>>445を見て書きたくなったので書いた。公開はしている。
ともかく、Perlでバイナリ処理は向いてない。速度的にも。
C言語やってると、readしたものはprintするよりもwriteしたい。謎
C言語のほうが分かりやすくかけそうだけど、バッファ長を意識する必要がでる。
画像データ内から該当するマーカーを全検索で探すのもいいが、
バッファフローを避けるために、決まったサイズづつ読み取って検索していくのであれば、境界に入り込まないように工夫する必要がある。
...xx xx FF | E1 00 22 xx xx..... となると、FF E1というマーカーが存在しているのに、読めない場合がある。
また、Jpegの規格でイメージデータ中にFFを出力する際、FF 00 と出力する決まりがあるので、
イメージデータ中にマーカーがマッチすることは、RSTマーカー以外はない(はずだ)が、
COMMENTや他のマーカーのデータ部分等に FF E1などが存在する場合、
JPEGを作成するソフトウェアによっては、マッチしてしまうかもしれない。
でも、上からマーカー辿って、seekさせていったほうが早いと思う。検索するだけなら。
プログレッシブやその他一般的でないJPEG(ロスレスとか)の場合は知らない。