2010-11-18 1 views
38

После Javadocs, я попытался масштабировать BufferedImage без успеха здесь мой код:Как масштабировать BufferedImage

BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded); 
Graphics2D grph = image.createGraphics(); 
grph.scale(2.0, 2.0); 
grph.dispose(); 

Я не могу понять, почему он не работает, никакой помощи?

+1

свободно обучающая: http://www.glyphic.com/transform/applet/1intro.html –

+0

На это письмо, то Самый популярный ответ - неправильный ответ. Он масштабирует изображение вверх, но возвращает изображение того же размера с отсутствием 3/4 изображения. Это ответ, заданный trashgod. Он близок, но у него небольшая ошибка. – MiguelMunoz

ответ

55

AffineTransformOp предлагает дополнительную гибкость выбора типа интерполяции.

BufferedImage before = getBufferedImage(encoded); 
int w = before.getWidth(); 
int h = before.getHeight(); 
BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 
AffineTransform at = new AffineTransform(); 
at.scale(2.0, 2.0); 
AffineTransformOp scaleOp = 
    new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); 
after = scaleOp.filter(before, after); 

Некоторые родственные примеры рассматриваются here и here.

+1

Действительно ли необходимо выделить все память для 'after', когда у вас есть оператор вроде:' after = ... '? –

+3

@Martijn: зависит от того, какой 'ColorModel' вы хотите в [' filter() '] (http://download.oracle.com/javase/6/docs/api/java/awt/image/AffineTransformOp.html# фильтр% 28java.awt.image.BufferedImage,% 20java.awt.image.BufferedImage% 29). Он возвращает ссылку, поэтому нет дополнительной памяти. – trashgod

+0

Есть ли способ сделать это с желаемой шириной и высотой вместо масштабного коэффициента? –

3

scale(..) работает несколько иначе. Вы можете использовать bufferedImage.getScaledInstance(..)

+0

Я пробовал этот путь, но getScaledInstance возвращает ToolkitImage, и для меня это не подходит мне. Благодаря –

+2

вы можете преобразовать его в BufferedImage, скопировав его растровый объект на новый BufferedImage. Serach for 'convert image to bufferedimage' – Bozho

+0

'Преобразование изображения в BufferedImage'> http://stackoverflow.com/a/13605411/439171 –

10

Как @Bozho говорит, вы, вероятно, захотите использовать getScaledInstance.

Чтобы понять, как работает grph.scale(2.0, 2.0) однако, вы могли бы посмотреть на этот код:

import java.awt.*; 
import java.awt.image.BufferedImage; 
import java.io.*; 

import javax.imageio.ImageIO; 
import javax.swing.ImageIcon; 


class Main { 
    public static void main(String[] args) throws IOException { 

     final int SCALE = 2; 

     Image img = new ImageIcon("duke.png").getImage(); 

     BufferedImage bi = new BufferedImage(SCALE * img.getWidth(null), 
              SCALE * img.getHeight(null), 
              BufferedImage.TYPE_INT_ARGB); 

     Graphics2D grph = (Graphics2D) bi.getGraphics(); 
     grph.scale(SCALE, SCALE); 

     // everything drawn with grph from now on will get scaled. 

     grph.drawImage(img, 0, 0, null); 
     grph.dispose(); 

     ImageIO.write(bi, "png", new File("duke_double_size.png")); 
    } 
} 

Учитывая duke.png:
enter image description here

он производит duke_double_size.png:
enter image description here

+0

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

+0

Не могли бы вы попробовать 'grph.setRenderingHint (RenderingHints.KEY_INTERPOLATION, интерполяция);' где 'интерполяция' является 'RenderingHints.VALUE_INTERPOLATION _...' например 'VALUE_INTERPOLATION_BICUBIC'? – aioobe

32

К сожалению, производительность getScaled Экземпляр() очень плохой, если не проблематичен.

Альтернативный подход - создать новый BufferedImage и нарисовать масштабированную версию оригинала на новой.

BufferedImage resized = new BufferedImage(newWidth, newHeight, original.getType()); 
Graphics2D g = resized.createGraphics(); 
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
    RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
g.drawImage(original, 0, 0, newWidth, newHeight, 0, 0, original.getWidth(), 
    original.getHeight(), null); 
g.dispose(); 

новыйWidth, newHeight указывает новый размер BufferedImage и должен быть правильно рассчитан. В случае коэффициента масштабирования:

int newWidth = new Double(original.getWidth() * widthFactor).intValue(); 
int newHeight = new Double(original.getHeight() * heightFactor).intValue(); 

EDIT: Нашел статью, иллюстрирующую проблему производительности: The Perils of Image.getScaledInstance()

+0

Я думаю, что теперь getScaledInstance() быстрее, по крайней мере, если у вас есть достойная графическая карта, благодаря оптимизированному конвейеру рендеринга Java2D. – ceklock

+0

FYI см. ** [здесь] (http://docs.oracle.com/javase/tutorial/2d/advanced/quality.html) ** другие возможные значения для 'RenderingHints.KEY_INTERPOLATION' – rustyx

9

Использование imgscalr – Java Image Scaling Library:

BufferedImage image = 
    Scalr.resize(originalImage, Scalr.Method.BALANCED, newWidth, newHeight); 

Это достаточно быстро для меня.

+1

Согласовано, это лучшее решение и позволяет избежать проблем с прозрачностью, неправильными переводами, неправильными цветами и т. Д. При использовании affinetransform и других методов. – zyamys

+1

Удивительный! Первое решение, которое я видел в этой теме, вызвало то, что мне нужно. – Shadoninja

+2

https://mvnrepository.com/artifact/org.imgscalr/imgscalr-lib/4.2 – kahonmlg

4

Если вы не против использования внешней библиотеки, Thumbnailator может выполнять масштабирование BufferedImage s.

Thumbnailator будет заботиться о обработке Java 2D обработки (например, с помощью Graphics2D и установки соответствующих rendering hints), так что простой беглый вызов API может быть использован для изменения размера изображения:

BufferedImage image = Thumbnails.of(originalImage).scale(2.0).asBufferedImage(); 

Хотя Thumbnailator, как его имя подразумевает, что он ориентирован на сжатие изображений, он также будет делать приличную работу, увеличивая изображения, используя билинейную интерполяцию в своей реализации resizer по умолчанию.


Отказ от ответственности: Я хранитель Thumbnailator библиотеки.

+0

Это отличная библиотека! Миниатюры просто потрясающие по сравнению с Graphics2D – Artem

1

Чтобы масштабировать изображение, вам нужно создать новое изображение и нарисовать его. Один из способов - использовать метод filter() для AffineTransferOp, как предложено here. Это позволяет выбрать метод интерполяции.

private static BufferedImage scale1(BufferedImage before, double scale) { 
    int w = before.getWidth(); 
    int h = before.getHeight(); 
    // Create a new image of the proper size 
    int w2 = (int) (w * scale); 
    int h2 = (int) (h * scale); 
    BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB); 
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale); 
    AffineTransformOp scaleOp 
     = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR); 

    scaleOp.filter(before, after); 
    return after; 
} 

Другой способ - просто нарисовать исходное изображение в новом изображении, используя операцию масштабирования для масштабирования. Этот метод очень похож, но он также иллюстрирует, как вы можете нарисовать все, что захотите, в конечном изображении. (Я положил в пустой строке, где два метода начинают отличаться.)

private static BufferedImage scale2(BufferedImage before, double scale) { 
    int w = before.getWidth(); 
    int h = before.getHeight(); 
    // Create a new image of the proper size 
    int w2 = (int) (w * scale); 
    int h2 = (int) (h * scale); 
    BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB); 
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale); 
    AffineTransformOp scaleOp 
     = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR); 

    Graphics2D g2 = (Graphics2D) after.getGraphics(); 
    // Here, you may draw anything you want into the new image, but we're 
    // drawing a scaled version of the original image. 
    g2.drawImage(before, scaleOp, 0, 0); 
    g2.dispose(); 
    return after; 
}