◆JPEGのbaseline判定ツール(jpeg構造解析ソース付き)
JPEGベースライン形式とプログレッシブ形式
JPEGにはベースライン形式とプログレッシブ形式があります。
同じJPEGでも必ずしも全てのプログラムが取り扱える訳ではなく、例えばSONYのwalkmanではアートワーク画像がベースライン形式のJPEGまたはPNGである必要があり、プログレッシブ形式のJPEGの場合表示することが出来ません。
JPEG画像がベースラインかプログレッシブかを確かめる単純なツールを作成しました。PGNの判別もします。
jpgBLineChk.zip をダウンロードし、展開後、A05_run.batを起動すれば、Pictureフォルダ内のファイルをチェックし、ファイル名の後にPROGRESSIVEかBASE_LINEかを示します。1行に1ファイル、で複数行になります。 (JAVA8の実行環境が必要です)
mull.png: PNG R-1000405-1202393759_jpeg.jpg: PROGRESSIVE R-3344447-1326656338_jpeg.jpg: BASE_LINE zamp27.png: PNG 四季 _I MUSICI 1.jpg: BASE_LINE
◇iTunesのアートワークをAAC(.m4a)ファイルに含める の ネットから画像を拾って設定 作業ではとても重宝しました。殆どはBASE_LINEですが、たまにPROGRESSIVEがあります。
単純なものですのでソースコードを提示します。
JPEGベースライン形式判定ツール
JPEGは次の形式をしています。
SOIは0xFFD8、EOIは0xFFD9です。
セグメントは先頭に0xFF、次に1バイトのセグメント種別が続き、その後ろに2バイトの長さ情報があります。長さ情報の後ろに「長さ情報-2」バイトの内容が置かれます。
SOIの後、複数のセグメントがあり、最後がSOSセグメントとなります。SOSセグメントの後ろには画像データがあります。
画像データは長さデータで修飾されておらず、内容を解析しないと終端は分かりません。
画像データの後ろにEOIが置かれますが現実的には意味を持ちません。
セグメント種別でベースライン、プログレッシブの判断ができます。
0xC0 : ベースライン
0xC1 : シーケンシャル
0xC2 : プログレッシブ
0xC3 : 可逆DPCM
これ以外にも多くのセグメントがありますが、他は無視します。
プログラムはSOIを確認後、セグメント単位で読み飛ばしながら、0xC0~0xC1のセグメント出現で判断し、結果を戻します。
// JpgBLineChk.java import java.io.*; public class JpgBLineChk { final static boolean D=false;// デバグフラグ public enum Type{ BASE_LINE, SEQUENCIAL, PROGRESSIVE, DCPM, PNG, // JPEGではないがチェックする UNKOWN }; public static Type getType(BufferedInputStream bis_)throws Exception{ byte[] _buf2 = {0,0}; // SOI取得用 byte[] _buf4 = {0,0,0,0}; // SEGMENTマーカーと長さ取得用 // SOIの確認 if( bis_.read(_buf2)!=2 ) return Type.UNKOWN; if( (_buf2[0]&0xff)!=0xFF || (_buf2[1]&0xff)!=0xD8 ){ // PNGか調べる if( (_buf2[0]&0xff)==0x89 && (_buf2[1]&0xff)==0x50 ){ byte[] _buf6={0,0,0,0, 0,0}; if( bis_.read(_buf6)!=6 ) return Type.UNKOWN; if( (_buf6[0]&0xff)==0x4E && (_buf6[1]&0xff)==0x47 &&(_buf6[2]&0xff)==0x0D && (_buf6[3]&0xff)==0x0A &&(_buf6[4]&0xff)==0x1A && (_buf6[5]&0xff)==0x0A ){ return Type.PNG; } } return Type.UNKOWN; } while(true){ // セグメントマーカー確認 if( bis_.read(_buf4)!= 4 ) return Type.UNKOWN; if( (_buf4[0]&0xff)!=0xFF ) return Type.UNKOWN; long _slen = (long)(((_buf4[2]&0xFF)<<8)+(_buf4[3]&0xFF)-2); if(D) System.out.printf("SEGMENT:%02x%02x len:%d\n" ,_buf4[0],_buf4[1],_slen); switch( _buf4[1]&0xff ){ case 0xC0: return Type.BASE_LINE; case 0xC1: return Type.SEQUENCIAL; case 0xC2: return Type.PROGRESSIVE; case 0xC3: return Type.DCPM; case 0xDA: return Type.UNKOWN;//SOS(この後ろはSEGMENTではない) } // セグメント読み飛ばし long _len; while( _slen>0 && ((_len=bis_.skip(_slen))!=-1) ) _slen -= _len; } } public static Type getType(File file_)throws Exception{ try(BufferedInputStream _bis = new BufferedInputStream( new FileInputStream(file_));){ return getType(_bis); } } public static void main(String[] args_){ for(String _arg:args_){ try{ File[] _files= new File(_arg).listFiles(); if( _files!=null ){ for(File _file:_files){ try{ System.out.println(_file.getName()+": " +JpgBLineChk.getType(_file)); } catch(Exception _ex){ System.out.println(_ex); } } } } catch(Exception _ex){ System.out.println(_ex); } } } }
このプログラムでは先頭が0xFFD8でない場合補足的にPNGではないかのチェックも行っています。
main部はコマンド引数としてフォルダ名を受け、フォルダ内のファイルに関してチェックを行い結果を表示するものとなっています。
補足:
_bis.read(_buf)は長さ分読むのでくりかえしの必要はありません。
_bis.skip(_skip)は短い場合もあるので繰り返さなくてはなりません。
_bis.skip(_skip)は最後まで到達した後は-1を返します。
実行バッチ
実行用のバッチファイルA05_run.batは次のようになっています。
実行用バッチ
:: A05_run.bat @echo off set DIR=%UserProfile%\Pictures set MAIN=JpgBLineChk set JAVA=java.exe "%JAVA%" -cp . %MAIN% %DIR% pause
この例では変数DIRにユーザのMyPictureフォルダを与えています。
この部分を必要に応じ変更してください。
実行例
実行例を示します。(長いので一部抜粋)
71mnczFjxrL__SL1200_.jpg: BASE_LINE 81UnrBT5hgL__SL1200_.jpg: BASE_LINE 91jo6WhblIL__SL1418_.jpg: BASE_LINE desktop.ini: UNKOWN mull.png: PNG R-1000405-1202393759_jpeg.jpg: PROGRESSIVE R-3344447-1326656338_jpeg.jpg: BASE_LINE R1202393759.jpg: PROGRESSIVE R12_baseline.jpg: BASE_LINE zamp27.png: UNKOWN 四季 _I MUSICI 1.jpg: BASE_LINE 惑星 _Previn_Royal Phil.Orc..jpg: BASE_LINE 無題.png: PNG 続行するには何かキーを押してください . . .
これらは先の記事 ◇iTunesのアートワークをACC(.m4a)ファイルに含める の「ネットから画像を拾って設定」でiTunesを介してwalkmanに設定したアートワークファイルです。
赤がwalkmanでアートワーク表示できなかったファイルで青はPhotoShopでBASE_LINEに変換保存しwalkmanで表示できるようになったファイルです。
ソースと再ビルド
jpgBLineChk.zip にはソースコードとビルド用のバッチも入れてあります。
Java8の実行環境が必要です。
JDK8以降があれば、ソースに変更を加えて再ビルドすることができます。
ビルド用バッチ
:: A01_build.bat @echo off set SRCS=JpgBLineChk.java set JAVAC=javac.exe "%JAVAC%" -Xlint:unchecked -encoding utf8 %SRCS% if ERRORLEVEL 1 goto ERR echo === OK === goto END :ERR echo === SOME ERROR OCCURED === :END pause
クリア用バッチ(の見本)
:: A00_clear.bat del /q *.class > NULL 1>&2 pause
| 固定リンク
コメント