- PR -

画像のjpeg変換

投稿者投稿内容
未記入
ベテラン
会議室デビュー日: 2007/09/29
投稿数: 78
投稿日時: 2008-07-07 15:33
こんにちは。

今あるサイトから画像のjpeg変換を行っています。
ソースはこんな感じなのですが、8MB近いサイズの画像だと
ヒープオブメモリとエラーになってしまいます。

path = "c:/test";
filename = "upimage.bmp";
fis = new FileInputStream(path + "/" + filename);
image = ImageIO.read(fis);
int height = 1024;
int width = 1024;

fis.close();
BufferedImage shrinkImage = new BufferedImage(width,height, image.getType());
Graphics2D g2d = shrinkImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);
g2d.drawImage(image, 0, 0, width, height, null);

String newfilename = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()) + ".jpg"; //JPEG変換ファイル名
ImageIO.write(shrinkImage, "jpg", new File(path + "/" + newfilename));

この対処法として、適切なやり方はあるのでしょうか?
やっぱり、ハードのメモリ増設を行わないとだめでしょうか?
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-07-07 16:41
まずはVMの起動引数でVMの使用するメモリの上限を増やしてみましょう。

javaコマンドのドキュメントに書かれていますが、-Xmx引数で設定できます。
未記入
ベテラン
会議室デビュー日: 2007/09/29
投稿数: 78
投稿日時: 2008-07-07 19:22
ありがとうございます。

おっしゃる通り、256M - 512Mで試してみましたが、処理は重いままでした。
5MB近い画像ファイルではそれほど重く感じられないのですが、元画像ファイルが
ある一定サイズ以上は途端に重くなってしまいます。

パレメータで設定できそうなのもVALUE_COLOR_RENDER_SPEEDぐらいしかありませんし・・。
Java僧
ぬし
会議室デビュー日: 2003/11/06
投稿数: 261
投稿日時: 2008-07-08 08:43
引用:
おっしゃる通り、256M - 512Mで試してみましたが、処理は重いままでした。


ん?問題は処理が重いことじゃなくて、ヒープエラーじゃなかったの??

引用:
パレメータで設定できそうなのもVALUE_COLOR_RENDER_SPEEDぐらいしかありませんし・・。


それを指定しても速度は全く変わらないのですか?
次の値も有効だと思いますが、影響ないんですか?
VALUE_ALPHA_INTERPOLATION_SPEED
VALUE_RENDER_SPEED
VALUE_ANTIALIAS_OFF
VALUE_DITHER_DISABLE

_________________
「ご教授」はできません
ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2008-07-08 12:33
Xmxなんかいじらず、ブラウザとかメーラーとかいろいろ動いている環境(古いマシンなので搭載メモリは384M + 仮想記憶)で、正常かつ短時間で動作します(vmstatを見ると、(たぶん他のプロセスが)仮想記憶を相当使っていることが分かります)。
-------------------------------------------------------------
import javax.imageio.*;
import java.awt.image.*;
import java.io.*;
import java.awt.*;
import java.text.*;
import java.util.*;

public class Bmp2Jpg{
static BufferedImage image;

public static void main(String[] args){
try{
image = ImageIO.read(new File("big.bmp")); // 12 mega byte
}
catch (Exception e){
e.printStackTrace();
}

int width = image.getWidth();
int height = image.getHeight();

long start = System.currentTimeMillis();

BufferedImage shrinkImage
= new BufferedImage(width, height, image.getType());
Graphics2D g2d = shrinkImage.createGraphics();

g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);

g2d.drawImage(image, 0, 0, width, height, null);

long intm = System.currentTimeMillis();

String newfilename
= new SimpleDateFormat("yyyyMMddhhmmss").format(new Date())
+ ".jpg";

try{
ImageIO.write(shrinkImage, "jpg", new File(newfilename));
}
catch (Exception e){
e.printStackTrace();
}

long end = System.currentTimeMillis();

System.out.println("until draw : " + (intm - start));
System.out.println("until write: " + (end - intm));
System.out.println("total : " + (end - start));
}
}
------------------------------------------------------------
[出力]
until draw : 2944
until write: 1504
total : 4448

未記入
ベテラン
会議室デビュー日: 2007/09/29
投稿数: 78
投稿日時: 2008-07-08 15:15
ありがとうございます。

私もたくさんのサンプルで試しているわけではないのですが、デジカメでとった下記サイズの画像変換にとても時間がかかっております。
以前、メモリヒープの問題を起こしてましたが、環境を変えることでそれは退避できています。

環境は
CPU 3.2Ghz
メモリ 1GB
OS Windows2003 Server
TomcatのJavaのメモリ使用量は256M 〜 512MBです。
で、タスクマネージャーを見る限りCPU,メモリ共に100%まで達していません。

7.91MB (3575 * 4984) JPEG

オーバフローして止まっているわけではないのですが、この一枚の画像を変換するのに15分以上かかってしまいます。

画像の質によってこのような問題が出てくるということなのでしょうか?
よろしくお願いします。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-07-08 19:28
引用:

未記入さんの書き込み (2008-07-08 15:15) より:
TomcatのJavaのメモリ使用量は256M 〜 512MBです。
で、タスクマネージャーを見る限りCPU,メモリ共に100%まで達していません。



VMの上限メモリ内で処理が行われるため、タスクマネージャで見てもVMのメモリ上限+αよりメモリ使用量が増えることはありません。
jconsoleでも使ってVMの中でのメモリ使用率やGC発生率を見てください。
推測ですが、メモリを多量に使うことでFullGCが頻発している状況にあるのではないでしょうか。
ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2008-07-08 19:50
> 7.91MB (3575 * 4984) JPEG
BMP -> JPGでなくて、JPG -> JPGなら、もっと単純にスケーリングできるけど…。

スキルアップ/キャリアアップ(JOB@IT)