Как повысить производительность метода g.drawImage () для изменения размеров изображений

У меня есть приложение, в котором пользователи могут загружать изображения в альбомы, но, естественно, загружаемые изображения необходимо изменить, чтобы также были доступны большие пальцы, а показанные изображения также попадали на страницу (например, 800×600). Способ изменения размера выглядит следующим образом:

Image scaledImage = img.getScaledInstance((int)width, (int)height, Image.SCALE_SMOOTH); BufferedImage imageBuff = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_RGB); Graphics g = imageBuff.createGraphics(); g.drawImage(scaledImage, 0, 0, new Color(0,0,0), null); g.dispose(); 

И это работает нормально. Моя единственная проблема заключается в том, что метод g.drawImage() кажется очень медленным, и я просто не могу представить, что пользователь достаточно терпелив, чтобы дождаться загрузки 20 снимков 20 * 10 секунд ~ 3 минуты. Фактически, на моем компьютере требуется около 40 секунд для создания трех разных размеров для одной картинки.

Это не очень хорошо, и я ищу более быстрое решение. Мне интересно, может ли кто-нибудь рассказать мне о лучшем в Java или, вызвав сценарий оболочки, команду, какой бы хак вам не известен, это должно быть быстрее, все остальное не имеет значения на этот раз.

Вы можете использовать ImageMagick для создания эскизов .

 convert -define jpeg:size=500x180 hatching_orig.jpg -auto-orient \ -thumbnail 250x90 -unsharp 0x.5 thumbnail.gif 

Чтобы использовать его с Java, вы можете попробовать JMagick, который предоставляет интерфейс Java (JNI) для ImageMagick. Или вы можете просто вызвать команды ImageMagick напрямую с помощью Runtime.exec или ProcessBuilder .

Я использую код, похожий на следующий, для масштабирования изображений, я удалил часть, которая имеет дело с сохранением пропорции. Производительность была определенно лучше, чем 10 с на изображение, но я не помню никаких точных цифр. Чтобы архивировать лучшее качество при масштабировании, вы должны масштабироваться в несколько шагов, если исходное изображение более чем в два раза превышает размер требуемого эскиза, каждый шаг должен масштабировать предыдущее изображение примерно до половины его размера.

 public static BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException { int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); double scaleX = (double)width/imageWidth; double scaleY = (double)height/imageHeight; AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY); AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR); return bilinearScaleOp.filter( image, new BufferedImage(width, height, image.getType())); } 

Вам действительно нужно качество, которое обеспечивается с помощью Image.SCALE_SMOOTH? Если вы этого не сделаете, вы можете попробовать использовать Image.SCALE_FAST . Вы можете найти эту статью полезной, если хотите придерживаться чего-то, предоставляемого Java.

Ну, мы с Джейкобом хотели resize изображения, а не BufferedImage. Итак, мы закончили с этим кодом:

 /** * we want the x and o to be resized when the JFrame is resized * * @param originalImage an x or an o. Use cross or oh fields. * * @param biggerWidth * @param biggerHeight */ private Image resizeToBig(Image originalImage, int biggerWidth, int biggerHeight) { int type = BufferedImage.TYPE_INT_ARGB; BufferedImage resizedImage = new BufferedImage(biggerWidth, biggerHeight, type); Graphics2D g = resizedImage.createGraphics(); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.drawImage(originalImage, 0, 0, biggerWidth, biggerHeight, this); g.dispose(); return resizedImage; } 

Основной вопрос заключался в производительности масштабирования изображений на Java . Другие ответы показали разные подходы, не оценивая их дальше. Мне также было интересно об этом, поэтому я попытался написать небольшой тест производительности. Тем не менее, тестирование масштабирования изображения надежно , разумно и объективно сложно. Слишком много факторов, которые необходимо учитывать:

  • Размер входного изображения
  • Размер выходного изображения
  • Интерполяция (т.е. «качество»: ближайший сосед, билинейный, бикубический)
  • BufferedImage.TYPE_* входного изображения
  • BufferedImage.TYPE_* выходного изображения
  • Версия JVM и операционная система
  • Наконец: метод, который фактически используется для выполнения операции.

Я попытался охватить те, которые я считал самыми важными. Настройка была:

  • Вход представляет собой простую «среднюю» фотографию (в частности, это «Изображение дня» из Википедии размером 2560×1706 пикселей)

  • Основные типы интерполяции тестируются, а именно, используя RenderingHints где ключ INTERPOLATION был установлен на значения NEAREST_NEIGHBOR , BICUBIC и BICUBIC

  • Входное изображение было преобразовано в разные типы:

    • BufferedImage.TYPE_INT_RGB : тип, который обычно используется, поскольку он «обычно» показывает лучшие характеристики производительности

    • BufferedImage.TYPE_3BTE_BGR : это тип, который он считывает по умолчанию, когда просто читает его с помощью ImageIO

  • Размер целевого изображения варьировался между шириной 10000 (таким образом, масштабируя изображение вверх ) и 100 (таким образом, масштабируя изображение до размера миниатюры)

Тесты выполнялись на Win64 / AMD K10 с 3.7 ГГц и JDK 1.8u31 с -Xmx4000m -server .

Проверенные методы:

  • Используя AffineTransformOp , как в ответе Йорна Хорстмана
  • Использование Graphics , как в ответе johnstosh
  • Использование Image#getScaledInstance

Код тестов показан здесь:

 import java.awt.Graphics2D; import java.awt.Image; import java.awt.MediaTracker; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Supplier; import javax.imageio.ImageIO; import javax.swing.JLabel; public class ImageScalingPerformance { private static int blackHole = 0; public static void main(String[] args) throws IOException { // Image with size 2560 x 1706, from https://upload.wikimedia.org/ // wikipedia/commons/4/41/Pitta_moluccensis_-_Kaeng_Krachan.jpg BufferedImage image = ImageIO.read( new File("Pitta_moluccensis_-_Kaeng_Krachan.jpg")); int types[] = { BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_INT_RGB, }; Object interpolationValues[] = { RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, RenderingHints.VALUE_INTERPOLATION_BILINEAR, RenderingHints.VALUE_INTERPOLATION_BICUBIC, }; int widths[] = { 10000, 5000, 2500, 1000, 500, 100 }; System.out.printf("%10s%22s%6s%18s%10s\n", "Image type", "Interpolation", "Size", "Method", "Duration (ms)"); for (int type : types) { BufferedImage currentImage = convert(image, type); for (Object interpolationValue : interpolationValues) { for (int width : widths) { List> tests = createTests(currentImage, interpolationValue, width); for (Supplier test : tests) { double durationMs = computeMs(test); System.out.printf("%10s%22s%6s%18s%10s\n", stringForBufferedImageType(type), stringForInterpolationValue(interpolationValue), String.valueOf(width), String.valueOf(test), String.format(Locale.ENGLISH, "%6.3f", durationMs)); } } } } System.out.println(blackHole); } private static List> createTests( BufferedImage image, Object interpolationValue, int width) { RenderingHints renderingHints = new RenderingHints(null); renderingHints.put( RenderingHints.KEY_INTERPOLATION, interpolationValue); double scale = (double) width / image.getWidth(); int height = (int)(scale * image.getHeight()); Supplier s0 = new Supplier() { @Override public BufferedImage get() { return scaleWithAffineTransformOp( image, width, height, renderingHints); } @Override public String toString() { return "AffineTransformOp"; } }; Supplier s1 = new Supplier() { @Override public Image get() { return scaleWithGraphics( image, width, height, renderingHints); } @Override public String toString() { return "Graphics"; } }; Supplier s2 = new Supplier() { @Override public Image get() { return scaleWithGetScaledInstance( image, width, height, renderingHints); } @Override public String toString() { return "GetScaledInstance"; } }; List> tests = new ArrayList>(); tests.add(s0); tests.add(s1); tests.add(s2); return tests; } private static double computeMs(Supplier supplier) { int runs = 5; long before = System.nanoTime(); for (int i=0; i 

Во-первых, относительно getScaledInstance : Как getScaledInstance Крис Кэмпбелл в своей (известной) статье о The Perils of Image.getScaledInstance (), которая уже была связана с другими ответами, метод Image#getScaledInstance несколько нарушен и имеет плохая производительность для большинства конфигураций. Кроме того, он имеет недостаток в том, что он не имеет такого мелкозернистого контроля над типом интерполяции. Это следует учитывать при следующем сравнении производительности . Качество полученных изображений может отличаться, что не рассматривается здесь. Например, метод «усреднения области» метода getScaledInstance не дает хорошего качества изображения при увеличении размера изображения.

(Самый серьезный недостаток Image#getScaledInstance - это ИМХО, что он предоставляет только Image , а не BufferedImage , но если изображение должно быть только расписано в Graphics , это может быть неважно)

Я просто отправлю вывод программы здесь для справки, некоторые подробности будут приведены ниже:

 Image type Interpolation Size MethodDuration (ms) 3BYTE_BGR NEAREST/REPLICATE 10000 AffineTransformOp 197.287 3BYTE_BGR NEAREST/REPLICATE 10000 Graphics 184.427 3BYTE_BGR NEAREST/REPLICATE 10000 GetScaledInstance 1869.759 3BYTE_BGR NEAREST/REPLICATE 5000 AffineTransformOp 38.354 3BYTE_BGR NEAREST/REPLICATE 5000 Graphics 40.220 3BYTE_BGR NEAREST/REPLICATE 5000 GetScaledInstance 1088.448 3BYTE_BGR NEAREST/REPLICATE 2500 AffineTransformOp 10.153 3BYTE_BGR NEAREST/REPLICATE 2500 Graphics 9.461 3BYTE_BGR NEAREST/REPLICATE 2500 GetScaledInstance 613.030 3BYTE_BGR NEAREST/REPLICATE 1000 AffineTransformOp 2.137 3BYTE_BGR NEAREST/REPLICATE 1000 Graphics 1.956 3BYTE_BGR NEAREST/REPLICATE 1000 GetScaledInstance 464.989 3BYTE_BGR NEAREST/REPLICATE 500 AffineTransformOp 0.861 3BYTE_BGR NEAREST/REPLICATE 500 Graphics 0.750 3BYTE_BGR NEAREST/REPLICATE 500 GetScaledInstance 407.751 3BYTE_BGR NEAREST/REPLICATE 100 AffineTransformOp 0.206 3BYTE_BGR NEAREST/REPLICATE 100 Graphics 0.153 3BYTE_BGR NEAREST/REPLICATE 100 GetScaledInstance 385.863 3BYTE_BGR BILINEAR/AREA_AVG 10000 AffineTransformOp 830.097 3BYTE_BGR BILINEAR/AREA_AVG 10000 Graphics 1501.290 3BYTE_BGR BILINEAR/AREA_AVG 10000 GetScaledInstance 1627.934 3BYTE_BGR BILINEAR/AREA_AVG 5000 AffineTransformOp 207.816 3BYTE_BGR BILINEAR/AREA_AVG 5000 Graphics 376.789 3BYTE_BGR BILINEAR/AREA_AVG 5000 GetScaledInstance 1063.942 3BYTE_BGR BILINEAR/AREA_AVG 2500 AffineTransformOp 52.362 3BYTE_BGR BILINEAR/AREA_AVG 2500 Graphics 95.041 3BYTE_BGR BILINEAR/AREA_AVG 2500 GetScaledInstance 612.660 3BYTE_BGR BILINEAR/AREA_AVG 1000 AffineTransformOp 9.121 3BYTE_BGR BILINEAR/AREA_AVG 1000 Graphics 15.749 3BYTE_BGR BILINEAR/AREA_AVG 1000 GetScaledInstance 452.578 3BYTE_BGR BILINEAR/AREA_AVG 500 AffineTransformOp 2.593 3BYTE_BGR BILINEAR/AREA_AVG 500 Graphics 4.237 3BYTE_BGR BILINEAR/AREA_AVG 500 GetScaledInstance 407.661 3BYTE_BGR BILINEAR/AREA_AVG 100 AffineTransformOp 0.275 3BYTE_BGR BILINEAR/AREA_AVG 100 Graphics 0.297 3BYTE_BGR BILINEAR/AREA_AVG 100 GetScaledInstance 381.835 3BYTE_BGR BICUBIC/AREA_AVG 10000 AffineTransformOp 3015.943 3BYTE_BGR BICUBIC/AREA_AVG 10000 Graphics 5431.703 3BYTE_BGR BICUBIC/AREA_AVG 10000 GetScaledInstance 1654.424 3BYTE_BGR BICUBIC/AREA_AVG 5000 AffineTransformOp 756.136 3BYTE_BGR BICUBIC/AREA_AVG 5000 Graphics 1359.288 3BYTE_BGR BICUBIC/AREA_AVG 5000 GetScaledInstance 1063.467 3BYTE_BGR BICUBIC/AREA_AVG 2500 AffineTransformOp 189.953 3BYTE_BGR BICUBIC/AREA_AVG 2500 Graphics 341.039 3BYTE_BGR BICUBIC/AREA_AVG 2500 GetScaledInstance 615.807 3BYTE_BGR BICUBIC/AREA_AVG 1000 AffineTransformOp 31.351 3BYTE_BGR BICUBIC/AREA_AVG 1000 Graphics 55.914 3BYTE_BGR BICUBIC/AREA_AVG 1000 GetScaledInstance 451.808 3BYTE_BGR BICUBIC/AREA_AVG 500 AffineTransformOp 8.422 3BYTE_BGR BICUBIC/AREA_AVG 500 Graphics 15.028 3BYTE_BGR BICUBIC/AREA_AVG 500 GetScaledInstance 408.626 3BYTE_BGR BICUBIC/AREA_AVG 100 AffineTransformOp 0.703 3BYTE_BGR BICUBIC/AREA_AVG 100 Graphics 0.825 3BYTE_BGR BICUBIC/AREA_AVG 100 GetScaledInstance 382.610 INT_RGB NEAREST/REPLICATE 10000 AffineTransformOp 330.445 INT_RGB NEAREST/REPLICATE 10000 Graphics 114.656 INT_RGB NEAREST/REPLICATE 10000 GetScaledInstance 2784.542 INT_RGB NEAREST/REPLICATE 5000 AffineTransformOp 83.081 INT_RGB NEAREST/REPLICATE 5000 Graphics 29.148 INT_RGB NEAREST/REPLICATE 5000 GetScaledInstance 1117.136 INT_RGB NEAREST/REPLICATE 2500 AffineTransformOp 22.296 INT_RGB NEAREST/REPLICATE 2500 Graphics 7.735 INT_RGB NEAREST/REPLICATE 2500 GetScaledInstance 436.779 INT_RGB NEAREST/REPLICATE 1000 AffineTransformOp 3.859 INT_RGB NEAREST/REPLICATE 1000 Graphics 2.542 INT_RGB NEAREST/REPLICATE 1000 GetScaledInstance 205.863 INT_RGB NEAREST/REPLICATE 500 AffineTransformOp 1.413 INT_RGB NEAREST/REPLICATE 500 Graphics 0.963 INT_RGB NEAREST/REPLICATE 500 GetScaledInstance 156.537 INT_RGB NEAREST/REPLICATE 100 AffineTransformOp 0.160 INT_RGB NEAREST/REPLICATE 100 Graphics 0.074 INT_RGB NEAREST/REPLICATE 100 GetScaledInstance 126.159 INT_RGB BILINEAR/AREA_AVG 10000 AffineTransformOp 1019.438 INT_RGB BILINEAR/AREA_AVG 10000 Graphics 1230.621 INT_RGB BILINEAR/AREA_AVG 10000 GetScaledInstance 2721.918 INT_RGB BILINEAR/AREA_AVG 5000 AffineTransformOp 254.616 INT_RGB BILINEAR/AREA_AVG 5000 Graphics 308.374 INT_RGB BILINEAR/AREA_AVG 5000 GetScaledInstance 1269.898 INT_RGB BILINEAR/AREA_AVG 2500 AffineTransformOp 68.137 INT_RGB BILINEAR/AREA_AVG 2500 Graphics 80.163 INT_RGB BILINEAR/AREA_AVG 2500 GetScaledInstance 444.968 INT_RGB BILINEAR/AREA_AVG 1000 AffineTransformOp 13.093 INT_RGB BILINEAR/AREA_AVG 1000 Graphics 15.396 INT_RGB BILINEAR/AREA_AVG 1000 GetScaledInstance 211.929 INT_RGB BILINEAR/AREA_AVG 500 AffineTransformOp 3.238 INT_RGB BILINEAR/AREA_AVG 500 Graphics 3.689 INT_RGB BILINEAR/AREA_AVG 500 GetScaledInstance 159.688 INT_RGB BILINEAR/AREA_AVG 100 AffineTransformOp 0.329 INT_RGB BILINEAR/AREA_AVG 100 Graphics 0.277 INT_RGB BILINEAR/AREA_AVG 100 GetScaledInstance 127.905 INT_RGB BICUBIC/AREA_AVG 10000 AffineTransformOp 4211.287 INT_RGB BICUBIC/AREA_AVG 10000 Graphics 4712.587 INT_RGB BICUBIC/AREA_AVG 10000 GetScaledInstance 2830.749 INT_RGB BICUBIC/AREA_AVG 5000 AffineTransformOp 1069.088 INT_RGB BICUBIC/AREA_AVG 5000 Graphics 1182.285 INT_RGB BICUBIC/AREA_AVG 5000 GetScaledInstance 1155.663 INT_RGB BICUBIC/AREA_AVG 2500 AffineTransformOp 263.003 INT_RGB BICUBIC/AREA_AVG 2500 Graphics 297.663 INT_RGB BICUBIC/AREA_AVG 2500 GetScaledInstance 444.497 INT_RGB BICUBIC/AREA_AVG 1000 AffineTransformOp 42.841 INT_RGB BICUBIC/AREA_AVG 1000 Graphics 48.605 INT_RGB BICUBIC/AREA_AVG 1000 GetScaledInstance 209.261 INT_RGB BICUBIC/AREA_AVG 500 AffineTransformOp 11.004 INT_RGB BICUBIC/AREA_AVG 500 Graphics 12.407 INT_RGB BICUBIC/AREA_AVG 500 GetScaledInstance 156.794 INT_RGB BICUBIC/AREA_AVG 100 AffineTransformOp 0.817 INT_RGB BICUBIC/AREA_AVG 100 Graphics 0.790 INT_RGB BICUBIC/AREA_AVG 100 GetScaledInstance 128.700 

Можно видеть, что почти во всех случаях getScaledInstance работает плохо по сравнению с другими подходами (и несколько случаев, когда он, кажется, работает лучше, можно объяснить более низким качеством при масштабировании).

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

Суть заключается в следующем: метод, использующий AffineTransformOp , как и в ответе Йорна Хорстмана , кажется тем, который предлагает лучшую производительность для большинства случаев применения.

это работает для меня:

 private BufferedImage getScaledImage(BufferedImage src, int w, int h){ int original_width = src.getWidth(); int original_height = src.getHeight(); int bound_width = w; int bound_height = h; int new_width = original_width; int new_height = original_height; // first check if we need to scale width if (original_width > bound_width) { //scale width to fit new_width = bound_width; //scale height to maintain aspect ratio new_height = (new_width * original_height) / original_width; } // then check if we need to scale even with the new height if (new_height > bound_height) { //scale height to fit instead new_height = bound_height; //scale width to maintain aspect ratio new_width = (new_height * original_width) / original_height; } BufferedImage resizedImg = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = resizedImg.createGraphics(); g2.setBackground(Color.WHITE); g2.clearRect(0,0,new_width, new_height); g2.drawImage(src, 0, 0, new_width, new_height, null); g2.dispose(); return resizedImg; } 

также я добавил белый фон для png

Самый быстрый способ масштабирования изображения в java без потери качества изображения – использовать Bilinear scaling. Bilinear только хорош, если вы масштабируете изображение на 50% за раз из-за того, как он работает. Следующий код от «Filthy rich clients» от Чет Хаазе. Он объясняет несколько методов в книге, но у этого есть наивысшая эффективность для качественного компромисса.

Он поддерживает все типы BufferedImages, поэтому не беспокойтесь о совместимости. Он также позволяет аппарату java2D ускорить ваш образ, потому что вычисления выполняются с помощью Java2D. Не беспокойтесь, если вы не понимаете эту последнюю часть. Самое главное, что это самый быстрый способ сделать это.

 public static BufferedImage getFasterScaledInstance(BufferedImage img, int targetWidth, int targetHeight, boolean progressiveBilinear) { int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; BufferedImage ret = (BufferedImage) img; BufferedImage scratchImage = null; Graphics2D g2 = null; int w, h; int prevW = ret.getWidth(); int prevH = ret.getHeight(); if(progressiveBilinear) { w = img.getWidth(); h = img.getHeight(); }else{ w = targetWidth; h = targetHeight; } do { if (progressiveBilinear && w > targetWidth) { w /= 2; if(w < targetWidth) { w = targetWidth; } } if (progressiveBilinear && h > targetHeight) { h /= 2; if (h < targetHeight) { h = targetHeight; } } if(scratchImage == null) { scratchImage = new BufferedImage(w, h, type); g2 = scratchImage.createGraphics(); } g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null); prevW = w; prevH = h; ret = scratchImage; } while (w != targetWidth || h != targetHeight); if (g2 != null) { g2.dispose(); } if (targetWidth != ret.getWidth() || targetHeight != ret.getHeight()) { scratchImage = new BufferedImage(targetWidth, targetHeight, type); g2 = scratchImage.createGraphics(); g2.drawImage(ret, 0, 0, null); g2.dispose(); ret = scratchImage; } System.out.println("ret is "+ret); return ret; } 

У вас всегда будет компромисс между скоростью изменения размера и качеством результирующего изображения. Вы можете попробовать другой алгоритм масштабирования JDK.

Лучшим и наиболее гибким инструментом для редактирования изображений AFAIK является ImageMagick .

Для языка Java существуют два интерфейса:

  • JMagick – это интерфейс JNI для ImageMagick. См. Проекты Wiki для получения дополнительной информации.
  • im4java – это интерфейс командной строки для ImageMagick. Это не так, как JMagick, основанный на JNI.

Вы должны предпочесть im4java, прежде чем использовать командную строку непосредственно для вызова ImageMagick.

Старый вопрос, но в случае, если кто-то еще сталкивается с этой проблемой: я профилировал ваш код, и вашим самым большим узким местом является вызов:

 Image.getScaledInstance() 

Этот вызов, как известно, ужасно медленный. Пожалуйста, убедитесь, прочитав этот документ:

Опасности Image.getScaledInstance ()

Самое простое / лучшее решение для резкого повышения производительности – это замена этого вызова. Вы можете использовать метод из ответа dpineda (см. Его ответ / код выше):

 private BufferedImage getScaledImage(BufferedImage src, int w, int h){ 

Я тестировал его метод, и он работает очень хорошо. В моем тестировании его реализация (которая позволяет избежать медленного Image.getScaledInstance ()), побрит 80% времени обработки!

Некоторое улучшение производительности (возможно, небольшое, возможно, незначительное, возможно, за счет качества) может быть достигнуто путем настройки подсказок рендеринга. Например

  g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 

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

Но если вы хотите использовать чистое Java-решение, вы можете попробовать и другие решения, такие как Graphics2D.scale и Image.getScaledInstance . Я использовал их в прошлом, но не могу вспомнить, какие из них были лучше или лучше выглядели, извините.

Попробуйте их и посмотрите, какой из них лучше всего подходит вашим потребностям.

Я использовал im4java с GraphicsMagick , чтобы иметь действительно более быстрые результаты (быстрее, чем ImageIO).

Используется такой код:

 public static void createFilePreview(final File originalFile, final String originalFileMimeType, final File destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException { runThumbnail(new ConvertCmd(), originalFile.getAbsolutePath(), originalFileMimeType, destinationPreviewFile.getAbsolutePath(), maxWidth, maxHeight); } public static void createFilePreview(final InputStream originalFileInputStream, final String originalFileMimeType, final File destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException { final ConvertCmd cmd = new ConvertCmd(); cmd.setInputProvider(new Pipe(originalFileInputStream, null)); runThumbnail(cmd, "-", originalFileMimeType, destinationPreviewFile.getAbsolutePath(), maxWidth, maxHeight); } private static void runThumbnail(final ConvertCmd cmd, final String originalFile, final String originalFileMimeType, final String destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException { final IMOperation operation = new IMOperation(); // if it is a PDF, will add some optional parameters to get nicer results if (originalFileMimeType.startsWith("application/pdf")) { operation.define("pdf:use-trimbox=true"); // as it is said here http://www.prepressure.com/pdf/basics/page_boxes "The imposition programs and workflows that I know all use the TrimBox as the basis for positioning pages on a press sheet." operation.density(300, 300); // augment the rendering from 75 (screen size) to 300 dpi in order to create big preview with good quality } operation.addImage("[0]"); // if it is a PDF or other multiple image source, will extract the first page / image, else it is ignored operation.autoOrient(); // Auto-orient the image if it contains some orientation information (typically JPEG with EXIF header) operation.thumbnail(maxWidth, maxHeight); operation.addImage(); cmd.run(operation, originalFile, destinationPreviewFile); } 
  • OpenCv 2.3 C - Как изолировать объект внутри изображения
  • Как измерить сходство между двумя изображениями?
  • подключенных компонентов в OpenCV
  • Загрузка изображений с помощью node.js
  • Как найти Waldo с Mathematica?
  • Ускорение преобразования точечного изображения в bitmap, является ли OpenMP опцией в C #?
  • OpenCV: Как рассчитать расстояние между камерой и объектом с помощью изображения?
  • import com.sun.image.codec.jpeg. *
  • 3d индексирование ядра CUDA для фильтрации изображений?
  • Как определить текстовую область из изображения?
  • Как поворачивать изображения JPEG на основе метаданных ориентации?
  • Interesting Posts

    Android: проблемы с Unicode / Charset при отправке SMS (sendTextMessage)

    Флэш-диск .docx исчезли файлы

    Как подключить программу к панели задач Windows 7 с параметрами?

    По-прежнему необходимо отключить компьютеры?

    Как игнорировать ошибку «git pull» о моих локальных изменениях будет перезаписано слиянием?

    ReSharper «не может разрешить символ» даже при сборке проекта

    Как настроить напоминания Outlook Calendar на первое место в Windows 7

    Разница между селекторами div + p (plus) и div ~ p (тильда)

    Как сказать, что находится в одном векторе, а не в другом?

    java socket / output stream пишет: блокируют ли они?

    Изменение имени пространства в Mac OS X Lion

    Пустой PDF даже с самым простым Jasperreport jrxml

    Указание файла для обработки на один слот Perl

    Сохранение в JobExecutionContext из тасклета и доступ к нему в другом таскеле

    Используйте светодиод Caps Lock в качестве индикатора жесткого диска (или пользовательского)

    Давайте будем гением компьютера.