package org.summercool.gif;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.AreaAveragingScaleFilter;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.ConvolveOp;
import java.awt.image.ImagingOpException;
import java.awt.image.IndexColorModel;
import java.awt.image.Kernel;
import java.awt.image.RasterFormatException;
import java.awt.image.RescaleOp;
import javax.imageio.ImageIO;
/**
* Class used to implement performant, high-quality and intelligent image
* scaling and manipulation algorithms in native Java 2D.
* <p/>
* This class utilizes the Java2D "best practices" for image manipulation,
* ensuring that all operations (even most user-provided {@link BufferedImageOp}
* s) are hardware accelerated if provided by the platform and host-VM.
* <p/>
* <h3>Image Quality</h3>
* This class implements a few different methods for scaling an image, providing
* either the best-looking result, the fastest result or a balanced result
* between the two depending on the scaling hint provided (see {@link Method}).
* <p/>
* This class also implements an optimized version of the incremental scaling
* algorithm presented by Chris Campbell in his <a href="http://today.java
* .net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html">Perils of
* Image.getScaledInstance()</a> article in order to give the best-looking image
* resize results (e.g. generating thumbnails that aren't blurry or jagged).
* <p>
* The results generated by imgscalr using this method, as compared to a single
* {@link RenderingHints#VALUE_INTERPOLATION_BICUBIC} scale operation look much
* better, especially when using the {@link Method#ULTRA_QUALITY} method.
* <p/>
* Only when scaling using the {@link Method#AUTOMATIC} method will this class
* look at the size of the image before selecting an approach to scaling the
* image. If {@link Method#QUALITY} is specified, the best-looking algorithm
* possible is always used.
* <p/>
* Minor modifications are made to Campbell's original implementation in the
* form of:
* <ol>
* <li>Instead of accepting a user-supplied interpolation method,
* {@link RenderingHints#VALUE_INTERPOLATION_BICUBIC} interpolation is always
* used. This was done after A/B comparison testing with large images
* down-scaled to thumbnail sizes showed noticeable "blurring" when BILINEAR
* interpolation was used. Given that Campbell's algorithm is only used in
* QUALITY mode when down-scaling, it was determined that the user's expectation
* of a much less blurry picture would require that BICUBIC be the default
* interpolation in order to meet the QUALITY expectation.</li>
* <li>After each iteration of the do-while loop that incrementally scales the
* source image down, an explicit effort is made to call
* {@link BufferedImage#flush()} on the interim temporary {@link BufferedImage}
* instances created by the algorithm in an attempt to ensure a more complete GC
* cycle by the VM when cleaning up the temporary instances (this is in addition
* to disposing of the temporary {@link Graphics2D} references as well).</li>
* <li>Extensive comments have been added to increase readability of the code.</li>
* <li>Variable names have been expanded to increase readability of the code.</li>
* </ol>
* <p/>
* <strong>NOTE</strong>: This class does not call {@link BufferedImage#flush()}
* on any of the <em>source images</em> passed in by calling code; it is up to
* the original caller to dispose of their source images when they are no longer
* needed so the VM can most efficiently GC them.
* <h3>Image Proportions</h3>
* All scaling operations implemented by this class maintain the proportions of
* the original image unless a mode of {@link Mode#FIT_EXACT} is specified; in
* which case the orientation and proportion of the source image is ignored and
* the image is stretched (if necessary) to fit the exact dimensions given.
* <p/>
* When not using {@link Mode#FIT_EXACT}, in order to maintain the
* proportionality of the original images, this class implements the following
* behavior:
* <ol>
* <li>If the image is LANDSCAPE-oriented or SQUARE, treat the
* <code>targetWidth</code> as the primary dimension and re-calculate the
* <code>targetHeight</code> regardless of what is passed in.</li>
* <li>If image is PORTRAIT-oriented, treat the <code>targetHeight</code> as the
* primary dimension and re-calculate the <code>targetWidth</code> regardless of
* what is passed in.</li>
* <li>If a {@link Mode} value of {@link Mode#FIT_TO_WIDTH} or
* {@link Mode#FIT_TO_HEIGHT} is passed in to the <code>resize</code> method,
* the image's orientation is ignored and the scaled image is fit to the
* preferred dimension by using the value passed in by the user for that
* dimension and recalculating the other (regardless of image orientation). This
* is useful, for example, when working with PORTRAIT oriented images that you
* need to all be the same width or visa-versa (e.g. showing user profile
* pictures in a directory listing).</li>
* </ol>
* <h3>Optimized Image Handling</h3>
* Java2D provides support for a number of different image types defined as
* <code>BufferedImage.TYPE_*</code> variables, unfortunately not all image
* types are supported equally in the Java2D rendering pipeline.
* <p/>
* Some more obscure image types either have poor or no support, leading to
* severely degraded quality and processing performance when an attempt is made
* by imgscalr to create a scaled instance <em>of the same type</em> as the
* source image. In many cases, especially when applying {@link BufferedImageOp}
* s, using poorly supported image types can even lead to exceptions or total
* corruption of the image (e.g. solid black image).
* <p/>
* imgscalr specifically accounts for and automatically hands
* <strong>ALL</strong> of these pain points for you internally by shuffling all
* images into one of two types:
* <ol>
* <li>{@link BufferedImage#TYPE_INT_RGB}</li>
* <li>{@link BufferedImage#TYPE_INT_ARGB}</li>
* </ol>
* depending on if the source image utilizes transparency or not. This is a
* recommended approach by the Java2D team for dealing with poorly (or non)
* supported image types. More can be read about this issue <a href=
* "http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg05621.html"
* >here</a>.
* <p/>
* This is also the reason we recommend using
* {@link #apply(BufferedImage, BufferedImageOp...)} to apply your own ops to
* images even if you aren't using imgscalr for anything else.
* <h3>GIF Transparency</h3>
* Unfortunately in Java 6 and earlier, support for GIF's
* {@link IndexColorModel} is sub-par, both in accurate color-selection and in
* maintaining transparency when moving to an image of type
* {@link BufferedImage#TYPE_INT_ARGB}; because of this issue when a GIF image
* is processed by imgscalr and the result saved as a GIF file (instead of PNG),
* it is possible to lose the alpha channel of a transparent image or in the
* case of applying an optional {@link BufferedImageOp}, lose the entire picture
* all together in the result (long standing JDK bugs are filed for all of these
* issues).
* <p/>
* imgscalr currently does nothing to work around this manually because it is a
* defect in the native platform code itself. Fortunately it looks like the
* issues are half-fixed in Java 7 and any manual workarounds we could attempt
* internally are relatively expensive, in the form of han