Изменение размера изображения при сохранении пропорций в Java

im пытается изменить размер буфера в памяти в java, но сохранить пропорции изображения im что-то вроде этого, но это не хорошо

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

Ответы

Ответ 1

Вы можете взглянуть на perils-of-image-getscaledinstance.html, который объясняет, почему следует getScaledInstance(), используемого в некоторых ответах.

В статье также представлен альтернативный код.

Ответ 2

Добавляя к точке Erik о getScaledInstance, если вы перешли от нее к использованию рекомендуемых механизмов масштабирования в Java2D, вы могли заметить, что ваши изображения выглядят значительно хуже.

Причина этого в том, что Java2D не поощрял использование getScaledInstance и AreaAveragingScaleFilter, они не заменяли его чем-либо простым в использовании в API, вместо этого мы были оставлены на наших собственных устройствах напрямую с использованием API Java2D. К счастью, Крис Кэмпбелл (из команды J2D) следил за рекомендацией использовать инкрементный метод масштабирования, который дает похожие результаты для AreaAveragingScaleFilter и работает быстрее; к сожалению, код имеет приличный размер и не затрагивает ваш первоначальный вопрос о соблюдении пропорций.

Около 6 месяцев назад я снова и снова рассматривал все эти вопросы по поводу "масштабирования изображений на 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-летнюю ошибку JDK BufferedImageOp для вас!)

Существует намного больше возможностей для масштабирования изображений в Java, успешно выполняемых для вас, например, всегда сохраняя изображение в одном из наилучших поддерживаемых типов изображений RGB или ARGB во время работы с ним. Под обложками конвейер обработки изображений Java2D возвращается к более низкому программному конвейеру, если тип изображения, используемый для любых операций с изображениями, плохо поддерживается.

Если бы все это звучало как большая головная боль, это вроде того... почему я написал библиотеку и открыл ее, поэтому люди могли просто изменять размеры своих изображений и продолжать свою жизнь, не беспокоясь об этом.

Надеюсь, что это поможет.

Ответ 3

Для начала - взгляните на строку 2. Не должно быть getHeight()?

Вам не нужен цикл while для изменения размера, вы хотите узнать коэффициент изменения размера, который является простым битом математики.

(width / height) = (new_width / new_height)

Если вы знаете один из "новых" размеров, другой может быть найден через умножение

new_height * (width / height) = new_width

Вы также можете использовать ленивый метод, предоставляемый BufferedImage's суперклассом Image, getScaledInstance() - использование -1 для ширины или высоты будет поддерживать соотношение сторон

ex:
scaledPic = picture.getScaledInstance(new_width, -1, Image.SCALE_FAST);

Ответ 4

Если ширина, высота источника и цель известны, используйте следующую функцию для определения масштаба изображения.

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

Ответ 5

Я использую эти два метода для масштабирования изображений, где 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;
}

Ответ 6

Если вы хотите изменить размер изображения 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);