Javaで画像をスケーリングする最良の方法は何ですか?
-
03-07-2019 - |
質問
Java(Spring、Hibernate / JPA、Struts2)で書かれたWebアプリケーションがあり、ユーザーは画像をアップロードしてファイルシステムに保存できます。これらの画像をスケーリングして、サイトに表示するためのサイズが一定になるようにします。どのライブラリまたは組み込み関数が最良の結果を提供しますか?この順序で決定を行う際に、次の基準を検討します。
- 無料/オープンソース(必須)
- 実装が簡単
- 結果の品質
- パフォーマンス
- 実行可能ファイルのサイズ
解決
Java Image I /をご覧ください。 O API で画像を読み書きします。次に、 AffineTransform を使用して、サイズを変更します。
また、こちらを使用した完全な例java.awt.Image。
他のヒント
imgscalr をご覧になることをお勧めします。
Apache 2ライセンスの下でリリースされ、 GitHub でホストされ、既にいくつかのWebアプリケーションに展開されており、非常にシンプルですが、教育的に文書化されたAPI には機能するコードがありますJDKの2つの主要なイメージバグが透過的にわかります。これは、突然「黒」になり始めた場合にのみ気付くものです。スケール操作後の画像または恐ろしい結果は、Javaで利用可能な最高の結果を提供し、MavenおよびZIPを介して利用でき、単一のクラスです。
基本的な使用方法は次のとおりです。
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 320);
これは、ライブラリが品質で最高の推測を行い、画像のプロポーションを尊重し、320x320の境界ボックス内に結果を収める最も単純な呼び出しです。注:画像の縦横比が考慮されるため、バウンディングボックスは使用される最大のW / Hに過ぎません。結果の画像は、たとえば320x200のままです。
自動モードをオーバーライドして、見栄えの良い結果を表示するように強制し、さらに結果に非常に穏やかなアンチエイリアスフィルターを適用して、さらに良く見えるようにする(特にサムネイルに適している)場合、その呼び出しは次のようになります:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY,
150, 100, Scalr.OP_ANTIALIAS);
これらはすべて単なる例であり、APIは幅広く、非常に単純な使用例から非常に特殊なものまですべてをカバーしています。独自のBufferedImageOpsを渡して画像に適用することもできます(ライブラリは6年間のBufferedImageOp JDKバグを自動的に修正します!)
Javaでの画像のスケーリングには、ライブラリが提供するものよりもはるかに多くの機能があります。たとえば、操作中は常に画像をサポートされている最適なRGBまたはARGB画像タイプのいずれかに維持します。カバーの下では、画像操作に使用される画像タイプが十分にサポートされていない場合、Java2D画像処理パイプラインは下位のソフトウェアパイプラインにフォールバックします。
それが頭痛の種のように聞こえるのであれば、それは...です。だから私はライブラリを書いてそれをオープンソースにしたので、人々は心配することなく画像のサイズを変更して生活を続けることができました。
役立つこと。
java-image-scaling ライブラリもご覧ください。 ImageIOよりも高品質の画像を作成しました。
これは非常に古い質問であることは知っていますが、標準Java APIを使用してこれに対する独自の解決策を得ました
import java.awt.*;
import java.awt.event.*;
import javax.imageio.*
import java.awt.image.*;
BufferedImage im, bi, bi2;
Graphics2D gfx;
int imWidth, imHeight, dstWidth, dstHeight;
int DESIRED_WIDTH = 500, DESIRED_HEIGHT = 500;
im = ImageIO.read(new File(filePath));
imWidth = im.getWidth(null);
imHeight = im.getHeight(null);
dstWidth = DESIRED_WIDTH;
dstHeight = (dstWidth * imHeight) / imWidth;
bi = new BufferedImage(dstWidth, dstHeight, im.getType());
gfx = bi.createGraphics();
gfx.drawImage(im, 0, 0, dstWidth, dstHeight, 0, 0, imWidth, imHeight, null);
bi2 = new BufferedImage(DESIRED_WIDTH, DESIRED_HEIGHT, im.getType());
gfx = bi2.createGraphics();
gfx.drawImage(bi, 0, 0, DESIRED_WIDTH, DESIRED_HEIGHT, null);
ImageIO.write(bi2, "jpg", new File(filePath));
改善および適応できると確信しています。
画像編集に最適なツールは ImageMagick であり、オープンソースです。
Java言語には2つのインターフェースがあります:
JMagick ImageMagickへのJNIインターフェイスを使用
and
im4java ImageMagickのコマンドラインインターフェイスとは
標準のJava 1.6と比較してimgscalrを試しましたが、より良いとは言えません。
試したことは
BufferedImage bufferedScaled = Scalr.resize(sourceImage, Method.QUALITY, 8000, height);
and
Image scaled = sourceImage.getScaledInstance(-1, height, Image.SCALE_SMOOTH);
BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
bufferedScaled.getGraphics().drawImage(scaled, 0, 0, null);
私の目に行った5分間のテストでは、2番目の(純粋なJava 1.6)の方が良い結果が得られるという印象を受けました。
これが高速であることがわかりました:
public static BufferedImage getScaledInstance(final BufferedImage img, final int targetWidth, final int targetHeight,
final Object hint) {
final int type = BufferedImage.TYPE_INT_RGB;
int drawHeight = targetHeight;
int drawWidth = targetWidth;
final int imageWidth = img.getWidth();
final int imageHeight = img.getHeight();
if ((imageWidth <= targetWidth) && (imageHeight <= targetHeight)) {
logger.info("Image " + imageWidth + "/" + imageHeight + " within desired scale");
return img;
}
final double sar = ((double) imageWidth) / ((double) imageHeight);
if (sar != 0) {
final double tar = ((double) targetWidth) / ((double) targetHeight);
if ((Math.abs(tar - sar) > .001) && (tar != 0)) {
final boolean isSoureWider = sar > (targetWidth / targetHeight);
if (isSoureWider) {
drawHeight = (int) (targetWidth / sar);
}
else {
drawWidth = (int) (targetHeight * sar);
}
}
}
logger.info("Scaling image from " + imageWidth + "/" + imageHeight + " to " + drawWidth + "/" + drawHeight);
final BufferedImage result = new BufferedImage(drawWidth, drawHeight, type);
try {
final Graphics2D g2 = result.createGraphics();
try {
if (hint != null) {
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
}
g2.drawImage(img, 0, 0, drawWidth, drawHeight, null);
}
finally {
g2.dispose();
}
return result;
}
finally {
result.flush();
}
}