package de.axone.gfx; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.IOException; import java.nio.file.Path; import java.util.Iterator; import java.util.Optional; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.FileImageOutputStream; public class ImageScalerAWT implements ImageScaler { private static final String imageioLock = "ImageIO read lock"; @Override public void scale( Path outPath, Path imagePath, Optional<Path> watermarkPath, int size, boolean hq ) throws IOException { // Read in BufferedImage inImage; try{ synchronized( imageioLock ){ // Prevent problems with liblcms2-2 inImage = ImageIO.read( imagePath.toFile() ); } } catch( Throwable e ){ throw new IOException( "Cannot read: " + imagePath, e ); } // Make watermark if( watermarkPath.isPresent() ) { BufferedImage watermarkImage; try { synchronized( imageioLock ){ // Prevent problems with liblcms2-2 watermarkImage = ImageIO.read( watermarkPath.get().toFile() ); } } catch( IOException e ){ throw new IOException( "Cannot read watermark: " + watermarkPath.get(), e ); } int ww = watermarkImage.getWidth(); int wh = watermarkImage.getHeight(); int iw = inImage.getWidth(); int ih = inImage.getHeight(); Graphics2D drawGraphics = inImage.createGraphics(); drawGraphics.drawImage( watermarkImage, iw - ww, ih - wh, ww, wh, null ); } // Scale Dim d = mkOuterbox( size, inImage.getWidth(), inImage .getHeight() ); BufferedImage resultImage = new BufferedImage( d.w, d.h, BufferedImage.TYPE_INT_RGB ); Image scaled = inImage.getScaledInstance( d.w, d.h, Image.SCALE_SMOOTH ); Graphics2D g2 = resultImage.createGraphics(); g2.drawImage( scaled, 0, 0, d.w, d.h, null ); // Quality can be higher for smaller images float quality; if( hq ) { quality = 1f; } else { if( size <= 200 ) { quality = .9f; } else if( size <= 400 ) { quality = .7f; } else if( size <= 700 ) { quality = .5f; } else { quality = .4f; } } // ImageIO.write( resultImage, "jpeg", cache ); // Code from: // http://www.universalwebservices.net/web-programming-resources/java/adjust-jpeg-image-compression-quality-when-saving-images-in-java // Let you choose compression level Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName( "jpeg" ); ImageWriter writer = iter.next(); ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode( ImageWriteParam.MODE_EXPLICIT ); iwp.setProgressiveMode( ImageWriteParam.MODE_DEFAULT ); iwp.setCompressionQuality( quality ); IIOImage image = new IIOImage( resultImage, null, null ); try( FileImageOutputStream output = new FileImageOutputStream( outPath.toFile() ) ){ writer.setOutput( output ); synchronized( imageioLock ){ // Just in case writing is as buggy as reading writer.write( null, image, iwp ); } } } private static class Dim { int w, h; } private static Dim mkOuterbox( int size, int originalWidth, int originalHeight ) { Dim res = new Dim(); double max = originalWidth > originalHeight ? originalWidth : originalHeight; res.w = (int) ( ( originalWidth / max ) * size ); res.h = (int) ( ( originalHeight / max ) * size ); return res; } private static ImageScaler instance; public synchronized static ImageScaler instance() { if( instance == null ) { instance = new ImageScalerAWT(); } return instance; } }