Java=のメモリ内のbufferdImageのサイズを変更しようとしていますが、画像のアスペクト比を維持するには、次のようなものがありますが、これは良くありません
int w = picture.getWidth();
int h = picture.getWidth();
int neww=w;
int newh=h;
int wfactor = w;
int hfactor = h;
if(w > DEFULT_PICTURE_WIDTH || h > DEFULT_PICTURE_HIGHT)
{
while(neww > DEFULT_PICTURE_WIDTH)
{
neww = wfactor /2;
newh = hfactor /2;
wfactor = neww;
hfactor = newh;
}
}
picture = Utils.resizePicture(picture,neww,newh);
perils-of-image-getscaledinstance.html を見ると、一部の回答で使用されているgetScaledInstance()
を避けなければならない理由がわかります。
この記事では、代替コードも提供しています。
ErikのgetScaledInstanceに関する要点に加えて、Java2Dで推奨されているスケーリングメカニズムを使用しないようにすると、画像が著しく悪化していることに気づいたかもしれません。
その理由は、Java2DがgetScaledInstanceとAreaAveragingScaleFilterの使用を推奨しなかったため、代わりにAPIで使用するのと同じように簡単に置き換えられなかったためです。 Java2D APIを直接使用する独自のデバイスに任されていました。さいわい、Chris Campbell(J2Dチーム)は、AreaAveragingScaleFilterに同様の外観の結果を提供し、より高速に実行できる増分スケーリング手法の使用を推奨しました。残念ながら、コードはまともなサイズであり、プロポーションを尊重するという元の質問には対応していません。
約6か月前、私はSO "Javaでの画像のスケーリング"について何度も何度もこれらの質問を見て、最終的にすべてのアドバイスを収集し、可能な限りすべての掘り下げと研究を行い、すべてをまとめました単一の「ベストプラクティス」に 画像スケーリングライブラリ 。
APIは1つのクラスと一連の静的メソッドしかないため、非常に単純です。基本的な使用法は次のようになります。
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画像タイプの1つに画像を維持します。これは、画像操作に使用される画像タイプのサポートが不十分な場合、Java2D画像処理パイプラインが下位のソフトウェアパイプラインにフォールバックすることをカバーしています。
それがすべて頭痛の種のように聞こえたとしたら、それは一種の...だから私はライブラリを作成してオープンソース化したので、人々は画像のサイズを変更して、心配することなく自分の生活を続けることができました。
お役に立てば幸いです。
ソースとターゲットの幅、高さがわかっている場合は、次の関数を使用して画像のスケールを決定します。
private double determineImageScale(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) {
double scalex = (double) targetWidth / sourceWidth;
double scaley = (double) targetHeight / sourceHeight;
return Math.min(scalex, scaley);
}
次に、このスケールを使用して、次のコードを使用して画像を拡大/縮小します
Image scaledImage = sourceBufferedImage.getScaledInstance((int) (width * scale), (int) (height * scale), Image.SCALE_SMOOTH);
まず、2行目を見てください。これはgetHeight()
である必要がありますか?
サイズ変更のwhileループは必要ありません。サイズ変更の比率を計算する必要があります。これは簡単な計算です。
_(width / height) = (new_width / new_height)
_
「新しい」サイズの1つがわかっている場合、もう1つは乗算で見つけることができます
_new_height * (width / height) = new_width
_
_BufferedImage's
_スーパークラス画像、getScaledInstance()
によって提供される遅延メソッドを使用することもできます-幅または高さのいずれかに-1を使用すると、アスペクト比が維持されます
例:scaledPic = picture.getScaledInstance(new_width, -1, Image.SCALE_FAST);
私はこれらの2つの方法を使用して画像をスケーリングします。ここで、maxは宛先画像のより大きな次元です。 100x100画像の場合は100、200x300画像の場合は300になります。
public static BufferedImage scale(InputStream is, int max) {
Image image = null;
try {
image = ImageIO.read(is);
} catch (IOException e) {
e.printStackTrace();
}
int width = image.getWidth(null);
int height = image.getHeight(null);
double dWidth = 0;
double dHeight = 0;
if (width == height) {
dWidth = max;
dHeight = max;
}
else if (width > height) {
dWidth = max;
dHeight = ((double) height / (double) width) * max;
}
else {
dHeight = max;
dWidth = ((double) width / (double) height) * max;
}
image = image.getScaledInstance((int) dWidth, (int) dHeight, Image.SCALE_SMOOTH);
BufferedImage bImage = toBufferedImage(image);
return bImage;
}
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
private static BufferedImage resize(BufferedImage img, int width, int height) {
double scalex = (double) width / img.getWidth();
double scaley = (double) height / img.getHeight();
double scale = Math.min(scalex, scaley);
int w = (int) (img.getWidth() * scale);
int h = (int) (img.getHeight() * scale);
Image tmp = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
BufferedImage resized = new BufferedImage(w, h, img.getType());
Graphics2D g2d = resized.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return resized;
}
縦横比を維持してw0 x h0からw1 x h1の画像のサイズを変更する場合は、縦と横のスケールを計算し、小さい方を選択します。
double scalex = 1;
double scaley = 1;
if (scalingMode == ScalingMode.WINDOW_SIZE) {
scalex = (double)getWidth() / frontbuffer.getWidth();
scaley = (double)getHeight() / frontbuffer.getHeight();
} else
if (scalingMode == ScalingMode.KEEP_ASPECT) {
double sx = (double)getWidth() / frontbuffer.getWidth();
double sy = (double)getHeight() / frontbuffer.getHeight();
scalex = Math.min(sx, sy);
scaley = scalex;
// center the image
g2.translate((getWidth() - (frontbuffer.getWidth() * scalex)) / 2,
(getHeight() - (frontbuffer.getHeight() * scaley)) / 2);
}
g2.scale(scalex, scaley);
if (interpolation != ImageInterpolation.NONE) {
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation.hint);
}
g2.drawImage(frontbuffer, 0, 0, null);