package org.sejda.core.writer.model;

import com.sun.imageio.plugins.jpeg.JPEGImageWriter;
import org.apache.commons.io.IOUtils;
import org.imgscalr.Scalr;
import org.w3c.dom.Element;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class ImageOptimizer {

    /**
     * Takes an image and creates an optimized version of it.
     *
     * If the image is larger than maxWidthOrHeight pixels, it is downsized to fit the maxWidthOrHeight rectangle (keeping its aspect ratio).
     * Image is saved as JPEG with specified quality (1.0 is best/leave unchanged, 0.0 is worst).
     * Image DPI is changed to dpi specified.
     */
    public static File optimize(BufferedImage bufferedImage, float quality, int dpi, int maxWidthOrHeight) throws IOException {
        File outputFile = File.createTempFile("pdfimage", ".jpeg");
        FileOutputStream fos = new FileOutputStream(outputFile);

        try {
            if (bufferedImage.getHeight() > maxWidthOrHeight || bufferedImage.getWidth() > maxWidthOrHeight) {
                bufferedImage = Scalr.resize(bufferedImage, Scalr.Method.AUTOMATIC, maxWidthOrHeight);
            }

            JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix("jpeg").next();
            ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
            imageWriter.setOutput(ios);

            IIOMetadata imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bufferedImage), null);

            //new metadata
            Element tree = (Element) imageMetaData.getAsTree("javax_imageio_jpeg_image_1.0");
            Element jfif = (Element)tree.getElementsByTagName("app0JFIF").item(0);
            jfif.setAttribute("Xdensity", Integer.toString(dpi));
            jfif.setAttribute("Ydensity", Integer.toString(dpi));

            JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
            jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
            jpegParams.setCompressionQuality(quality);

            try {
                imageWriter.write(imageMetaData, new IIOImage(bufferedImage, null, null), jpegParams);
            } finally {
                IOUtils.closeQuietly(ios);
                imageWriter.dispose();
            }

            return outputFile;
        } finally {
            IOUtils.closeQuietly(fos);
            bufferedImage.flush();
        }
    }
}

@@ -149,16 +149,73 @@
 .Scalr;%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A
 import o
@@ -474,32 +474,51 @@
 geOutputStream;%0A
+import java.awt.*;%0A
 import java.awt.
@@ -652,16 +652,102 @@
 izer %7B%0A%0A
+    private static final Logger LOG = LoggerFactory.getLogger(ImageOptimizer.class);%0A%0A
     /**%0A
@@ -1606,32 +1606,332 @@
 %0A            %7D%0A%0A
+            // PNG read fix when converting to JPEG%0A            BufferedImage imageRGB = new BufferedImage(bufferedImage.getWidth(),%0A                    bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);%0A%0A            imageRGB.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);%0A%0A
             JPEG
@@ -2236,29 +2236,24 @@
 ecifier(
-bufferedI
+i
 mage
+RGB
 ), null)
@@ -2247,32 +2247,54 @@
 geRGB), null);%0A%0A
+            try %7B%0A    
             //ne
@@ -2304,16 +2304,20 @@
 etadata%0A
+    
         
@@ -2406,32 +2406,36 @@
 %22);%0A            
+    
 Element jfif = (
@@ -2442,16 +2442,17 @@
 Element)
+ 
 tree.get
@@ -2494,32 +2494,36 @@
 0);%0A            
+   
+ 
 jfif.setAttribut
@@ -2564,32 +2564,36 @@
 ));%0A            
+    
 jfif.setAttribut
@@ -2629,16 +2629,155 @@
 g(dpi));
+%0A            %7D catch(Exception e) %7B%0A                LOG.warn(%22Failed to set DPI for image, metadata manipulation failed%22, e);%0A            %7D
 %0A%0A      
@@ -3087,29 +3087,24 @@
 IOImage(
-bufferedI
+i
 mage
+RGB
 , null, 

Improve OptimizeTask: don't fail when the image metadata manipulation fails. Don't crash on PNG with alpha to JPEG conversion.