Javaでファイルをロードする前に画像の大きさを調べる

プログラミング
スポンサーリンク

BMP, PNG, JPEG, GIF画像を読み込む前に画像の横幅と縦幅を調べるサンプル。

ソースコードを「ソースコード HTML化 コンバーター「唐辛子」」で変換してます
半角スペース、全角スペース、&nbsp、preが使用できないのでインデントが使えません。
各自、ソフトでインデントの修正コマンドなどを使用して下さい。すみません><

追記:ImageInputStreamImageReaderを使ったほうが良かったかも。
こちらだとロード前に画像の大きさの他に、画像のカラーモデルもわかるみたい。

入力引数
file … ファイルパス
stream … ファイルのInputStream
length … ファイルサイズ

public class X {

public static void check(File file,InputStream stream,int length) {
if((file == null)||(stream == null)||(length<0)) {
return(null);
}
Loader loader = new Loader(file, stream, length);
int[] imagesize = getImageSize(loader);
System.out.println(imagesize[0] + ” “+ imagesize[1]);
loader.close();
return(null);
}

public static int[] getImageSize(Loader loader) {
//最初の2バイトを調べる
byte[] head = loader.getByte(0, 2);
if(head == null) {
loader.close();
return(null);
}
//受け取りのデータ確保
int[] imagesize = new int[2];
for(int i = 0;i < imagesize.length;i++) imagesize[i] = –1;
//検索
if(!getImageSizeJPEG(head, loader, imagesize)) {
if(!getImageSizePNG(head, loader, imagesize)) {
if(!getImageSizeGIF(head, loader, imagesize)) {
getImageSizeBMP(head, loader, imagesize);
}
}
}
if((imagesize[0] == –1)||(imagesize[1] == –1)) {
return(null);
}
else {
return(imagesize);
}
}

public static boolean getImageSizeBMP(byte[] head,Loader loader,int[] type) {
//bfType
if((head[0] != (byte)0x42)||((head[1] != (byte)0x4D))) {
return(false);
}
byte[] binary;
int length = 0;
//ファイル長のテスト
binary = loader.getByte(0, 4);
if(binary == null) return(true);
length = ((binary[3]&0xff) << 24) | ((binary[2]&0xff) << 16) | ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
if(length != loader.getByteSize()) {
return(true);
}
if(!loader.setOffset(8)) return(true);
//情報ヘッダのサイズ
binary = loader.getByte(0, 4);
if(binary == null) return(true);
length = ((binary[3]&0xff) << 24) | ((binary[2]&0xff) << 16) | ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
//BMPCOREHEADER構造体
if(length == 12) {
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[0] = ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[1] = ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
}
//BITMAPINFOHEADER構造体
else if(length == 40) {
binary = loader.getByte(0, 4);
if(binary == null) return(true);
type[0] = ((binary[3]&0xff) << 24) | ((binary[2]&0xff) << 16) | ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
binary = loader.getByte(0, 4);
if(binary == null) return(true);
type[1] = ((binary[3]&0xff) << 24) | ((binary[2]&0xff) << 16) | ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
type[1] = Math.abs(type[1]);//負数の場合はデータは上から下へ
}
return(true);
}

public static boolean getImageSizeGIF(byte[] head,Loader loader,int[] type) {
//シグネーチャ
if((head[0] != (byte)0x47)||((head[1] != (byte)0x49))) {
return(false);
}
if(!loader.setOffset(4)) return(true);
byte[] binary;
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[0] = ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[1] = ((binary[1]&0xff) << 8) | (binary[0] & 0xff);
//このあとブロックが並ぶ
return(true);
}

public static boolean getImageSizePNG(byte[] head,Loader loader,int[] type) {
//PNG ファイルシグネチャ
if((head[0] != (byte)0x89)||((head[1] != (byte)0x50))) {
return(false);
}
if(!loader.setOffset(6)) return(true);
byte[] binary;
int marker;
int length = 0;
//探索回数
for(int i = 0;i < 100;i++) {
//チャンク全体のデータサイズ
binary = loader.getByte(0, 4);
if(binary == null) return(true);
length = ((binary[0]&0xff) << 24) | ((binary[1]&0xff) << 16) | ((binary[2]&0xff) << 8) | (binary[3] & 0xff);
//チャンクの種類
binary = loader.getByte(0, 4);
if(binary == null) return(true);
marker = ((binary[0]&0xff) << 24) | ((binary[1]&0xff) << 16) | ((binary[2]&0xff) << 8) | (binary[3] & 0xff);
//System.out.printf(“%08X %d\n”, marker,length);
switch(marker) {
case 0x49484452: //IHDR (イメージヘッダ)
binary = loader.getByte(0, 4);
if(binary == null) return(true);
type[0] = ((binary[0]&0xff) << 24) | ((binary[1]&0xff) << 16) | ((binary[2]&0xff) << 8) | (binary[3] & 0xff);
binary = loader.getByte(0, 4);
if(binary == null) return(true);
type[1] = ((binary[0]&0xff) << 24) | ((binary[1]&0xff) << 16) | ((binary[2]&0xff) << 8) | (binary[3] & 0xff);
return(true);
case 0x49444154: //SOS(イメージデータ)
return(true);
}
//次のセグメントへ(CRC(4byte)を追加)
if(!loader.setOffset(length + 4)) return(true);
}
return(true);
}

public static boolean getImageSizeJPEG(byte[] head,Loader loader,int[] type) {
//SOI(Start of Image) 0xFFD8
if((head[0] != (byte)0xFF)||((head[1] != (byte)0xD8))) {
return(false);
}
byte[] binary;
int marker;
int length = 0;
//探索回数
for(int i = 0;i < 100;i++) {
//セグメントのマーカー
binary = loader.getByte(0, 2);
if(binary == null) return(true);
marker = ((binary[0] << 8) | binary[1]) &0xffff;
//セグメント全体のデータサイズ
binary = loader.getByte(0, 2);
if(binary == null) return(true);
length = ((binary[0]&0xff) << 8) | (binary[1] & 0xff);
//System.out.printf(“%08X %d\n”, marker,length);
switch(marker) {
case 0xFFC0: //SOF0
case 0xFFC1: //SOF1
case 0xFFC2: //SOF2
case 0xFFC3: //SOF3
case 0xFFC5: //SOF5
case 0xFFC6: //SOF6
case 0xFFC7: //SOF7
case 0xFFC9: //SOF9
case 0xFFCA: //SOF10
case 0xFFCB: //SOF11
case 0xFFCD: //SOF13
case 0xFFCE: //SOF14
case 0xFFCF: //SOF15
if(!loader.setOffset(1)) return(true);
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[1] = ((binary[0]&0xff) << 8) | (binary[1] & 0xff);
binary = loader.getByte(0, 2);
if(binary == null) return(true);
type[0] = ((binary[0]&0xff) << 8) | (binary[1] & 0xff);
return(true);
case 0xFFDA: //SOS(イメージデータ開始)
return(true);
}
//次のセグメントへ(length(2byte)を除く)
if(!loader.setOffset(length – 2)) return(true);
}
return(true);
}

/**
* 簡易ロード<br>
* シークが動かせないものや、ファイルとして読み込んでいるもの、再ロードできないものなどを<br>
* 色々なデータに関して、同じように扱えるようにする。
*/

private static class Loader {
private File file = null;
private static final int defaultBufferSize = 65536;
private InputStream inputstream = null;
private FileInputStream fileinputstream = null;
private int length = 0;
private int seek = 0;
private byte[] data = null;
public Loader(File file,InputStream stream,int length) {
this.file = file;
this.length = length;
this.inputstream = stream;
//ファイルとして扱える
if(this.inputstream instanceof FileInputStream) {
this.fileinputstream = (FileInputStream) stream;
this.fileinputstream.mark(defaultBufferSize);
return;
}
//シーク位置が動かせる
if(this.inputstream.markSupported()) {
this.inputstream.mark(defaultBufferSize);
return;
}
//一度しかロードできないのでロードしておく。
this.data = getByte();
}
/**
* 終了処理必ず行う。
*/

public void closeStream() {
if(inputstream != null) {
try {
inputstream.close();
} catch (IOException e) {
}
inputstream = null;
fileinputstream = null;
}
}
/**
* 終了処理必ず行う。
*/

public void close() {
closeStream();
data = null;
file = null;
}
/**
* 一部を切り出す。シークがずれます。
* @param offset
* @param length
* @return
*/

public byte[] getByte(int offset,int length) {
if((this.seek + offset + length) >= this.length) {
return(null);
}
this.seek += offset;
byte[] out = new byte[length];
if(data != null) {//既にロード済みなら
System.arraycopy(data, this.seek, out, 0, length);
}
else {//ロードしていないので通常動作
try {
this.inputstream.read(out, offset, length);
} catch (IOException e) {
return(null);
}
}
this.seek += length;
return(out);
}
/**
* seek位置をずらす
* @param seek
* @return
*/

public boolean setOffset(int offset) {
return(this.setSeek(this.seek + offset));
}
/**
* seek位置を設定します
* @param seek
* @return
*/

public boolean setSeek(int seek) {
if(this.length <= seek) {//範囲外
return(false);
}
if(data != null) {//データ取得済み
this.seek = seek;
return(true);
}
if(this.seek <= seek) {//スキップ
try {
this.inputstream.skip(seek – this.seek);
} catch (IOException e) {
return(false);
}
this.seek = seek;
return(true);
}
//最初から読み込み直し
if(this.fileinputstream != null) {//ファイルの場合
closeStream();
try {
this.fileinputstream = new FileInputStream(file);
this.inputstream = this.fileinputstream;
} catch (FileNotFoundException e) {
}
}
else if(this.inputstream.markSupported()) {//シークを移動できるなら
try {
this.inputstream.reset();
} catch (IOException e) {
}
}
else {//それ以外は無理
return(false);
}
this.seek = seek;
try {
this.inputstream.skip(this.seek);
} catch (IOException e) {
return(false);
}
return(true);
}
/**
* ファイルサイズを取得する。
* @return
*/

public int getByteSize() {
return(this.length);
}
/**
* ファイルのバイナリを取得する。
* シーク位置が0になります。
* @return
*/

public byte[] getByte() {
if(data != null) {//既にロード済みなら
return(data);
}
this.setSeek(0);
BufferedInputStream bufferedstream = null;
try {
bufferedstream = new BufferedInputStream(inputstream, defaultBufferSize);
byte[] binary = new byte[length];
bufferedstream.read(binary);
data = binary;
}
catch (FileNotFoundException e) {/*e.printStackTrace();*/}
catch (IOException e) {/*e.printStackTrace();*/}
finally {
try {
if(bufferedstream != null) {
bufferedstream.close();
}
}
catch (Exception e) {
}
}
return(data);
}
}
}

コメント

タイトルとURLをコピーしました