/*
 * Copyright 2017 by Eduard Weissmann
 * 
 * This file is part of the Sejda source code
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.sejda.core.writer.model;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;

import org.apache.commons.io.IOUtils;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

public class ImageOptimizer {

    private static final Logger LOG = LoggerFactory.getLogger(ImageOptimizer.class);

    /**
     * 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 width, int height)
            throws IOException {
        File outputFile = File.createTempFile("pdfimage", ".jpeg");
        outputFile.deleteOnExit();

        try {
            int relevantDelta = 20;
            boolean isResizeRelevant = Math.abs(bufferedImage.getWidth() - width) > relevantDelta
                    && Math.abs(bufferedImage.getHeight() - height) > relevantDelta;
            boolean isShirinking = bufferedImage.getHeight() > height || bufferedImage.getWidth() > width;

            if (isResizeRelevant && isShirinking) {
                // we resize down, we don't resize up
                LOG.debug("Resizing image from {}x{} to {}x{}", bufferedImage.getWidth(), bufferedImage.getHeight(),
                        width, height);
                bufferedImage = Scalr.resize(bufferedImage, Scalr.Method.BALANCED, width, height);
            }

            // PNG read fix when converting to JPEG
            BufferedImage imageRGB = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            imageRGB.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);

            ImageWriter imageWriter = ImageIO.getImageWritersBySuffix("jpeg").next();
            ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile);
            imageWriter.setOutput(ios);

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

            IIOMetadata imageMetaData = null;
            try {
                // new metadata
                imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(imageRGB), jpegParams);
                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));
                jfif.setAttribute("resUnits", "1");
                imageMetaData.setFromTree("javax_imageio_jpeg_image_1.0", tree);
            } catch (Exception e) {
                LOG.warn("Failed to set DPI for image, metadata manipulation failed", e);
            }

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

            return outputFile;
        } finally {
            bufferedImage.flush();
        }
    }
}

@@ -819,16 +819,44 @@
 .Color;%0A
+import java.awt.Graphics2D;%0A
 import j
@@ -3028,24 +3028,41 @@
 %0A           
+ Graphics2D g2d =
  imageRGB.cr
@@ -3075,16 +3075,33 @@
 aphics()
+;%0A            g2d
 .drawIma
@@ -3143,16 +3143,43 @@
 , null);
+%0A            g2d.dispose();
 %0A%0A      

dispose the g2d