web-dev-qa-db-ja.com

Java

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);
17
user63898

perils-of-image-getscaledinstance.html を見ると、一部の回答で使用されているgetScaledInstance()を避けなければならない理由がわかります。

この記事では、代替コードも提供しています。

6
Erik

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画像処理パイプラインが下位のソフトウェアパイプラインにフォールバックすることをカバーしています。

それがすべて頭痛の種のように聞こえたとしたら、それは一種の...だから私はライブラリを作成してオープンソース化したので、人々は画像のサイズを変更して、心配することなく自分の生活を続けることができました。

お役に立てば幸いです。

69
Riyad Kalla

ソースとターゲットの幅、高さがわかっている場合は、次の関数を使用して画像のスケールを決定します。

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);
10
asingh

まず、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);

9
Max

私はこれらの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;
}
3
ZZ 5
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;
    }
0
naskar

縦横比を維持して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);
0
akarnokd