Subversion Repositories general

Rev

Rev 1074 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package ak.photoalbum.images.jiu;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.awt.image.ImageObserver;

import org.apache.log4j.Logger;

import ak.photoalbum.images.ImageResizer;

import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.geometry.Resample;

public class JiuResizer
  implements ImageResizer
{
  protected static final int DEFAULT_ALPHA = 0xff000000;
  protected static final int FILTER_TYPE   = Resample.FILTER_TYPE_HERMITE;
    /*
      Possible type          small, ms      medium, ms    quality
      -----------------------------------------------------------
      FILTER_TYPE_BOX           2.4           3.5         very bad
      FILTER_TYPE_TRIANGLE      2.9           5.2
      FILTER_TYPE_B_SPLINE      3.6           7.2
      FILTER_TYPE_BELL          3.5           6.1
      FILTER_TYPE_HERMITE       2.9           5.3
      FILTER_TYPE_LANCZOS3      4.7           9.7         the best
      FILTER_TYPE_MITCHELL      3.6           7.1
    */

  private static final Logger logger =  Logger.getLogger(JiuResizer.class);

  public JiuResizer()
  {
  }

  public BufferedImage resize(Image origin, int newWidth, int newHeight)
  {
        long timeStart = System.currentTimeMillis();

    try {
      RGB24Image image    = convertImageToRGB24Image(origin);
      Resample   resample;

      if(image == null) return null;
      if(image.getWidth() == newWidth && image.getHeight() == newHeight)
        return convertToAwtImage(image, DEFAULT_ALPHA);

      resample = new Resample();
      resample.setInputImage(image);
      resample.setSize(newWidth, newHeight);
      resample.setFilter(FILTER_TYPE);
      resample.process();

      return convertToAwtImage(resample.getOutputImage(), DEFAULT_ALPHA);
    }
    catch(Exception ex) {
      logger.warn("Cannot resize image", ex);

      throw new RuntimeException(ex.getMessage());
    }
        finally {
      if(logger.isDebugEnabled()) {
        logger.debug("resized in " + (System.currentTimeMillis() - timeStart) + " ms");
      }
    }
  }

  protected static BufferedImage convertToAwtImage(PixelImage image, int alpha)
  {
    if (image == null)
    {
      return null;
    }
    if (image instanceof RGB24Image)
    {
      return convertToAwtImage((RGB24Image)image, alpha);
    }
    else
    if (image instanceof Gray8Image)
    {
      return null; //convertToAwtImage((Gray8Image)image, alpha);
    }
    else
    if (image instanceof Paletted8Image)
    {
      return null; //convertToAwtImage((Paletted8Image)image, alpha);
    }
    else
    if (image instanceof BilevelImage)
    {
      return null; //convertToAwtImage((BilevelImage)image, alpha);
    }
    else
    {
      return null;
    }
  }

  protected static BufferedImage convertToAwtImage(RGB24Image image, int alpha)
  {
    if (image == null)
    {
      return null;
    }

    int width = image.getWidth();
    int height = image.getHeight();
    if (width < 1 || height < 1)
    {
      return null;
    }

    int[] pixels = new int[width];
    byte[] red = new byte[width];
    byte[] green = new byte[width];
    byte[] blue = new byte[width];

    BufferedImage newImage = new BufferedImage(width, height,
      BufferedImage.TYPE_INT_RGB);

    for (int y = 0; y < height; y++)
    {
      image.getByteSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0);
      image.getByteSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0);
      image.getByteSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0);
      convertFromRGB24(red, 0, green, 0, blue, 0, alpha, pixels, 0, width);

      for(int x = 0; x < width; x++)
        newImage.setRGB(x, y, pixels[x]);
    }

    return newImage;
  }

  protected static void convertFromRGB24(
    byte[] srcRed, int srcRedOffset,
    byte[] srcGreen, int srcGreenOffset,
    byte[] srcBlue, int srcBlueOffset,
    int alpha,
    int[] dest, int destOffset,
    int num)
  {
    while (num-- > 0)
    {
      dest[destOffset++] =
        alpha |
        (srcBlue[srcBlueOffset++] & 0xff) |
        ((srcGreen[srcGreenOffset++] & 0xff) << 8) |
        ((srcRed[srcRedOffset++] & 0xff) << 16);
    }
  }

  /**
   * Creates an {@link RGB24Image} from the argument AWT image instance.
   * @param image AWT image object to be converted to a {@link RGB24Image}
   * @return a {@link RGB24Image} object holding the
   *         image data from the argument image
   */
  protected static RGB24Image convertImageToRGB24Image(Image image)
  {
    if (image == null)
    {
      return null;
    }
    int width = image.getWidth(null);
    int height = image.getHeight(null);
    if (width < 1 || height < 1)
    {
      return null;
    }
    int[] pixels = new int[width * height];
    PixelGrabber pg = new PixelGrabber(
      image, 0, 0, width, height, pixels, 0, width);

    try
    {
      pg.grabPixels();
    }
    catch (InterruptedException e)
    {
      return null;
    }
    if ((pg.getStatus() & ImageObserver.ABORT) != 0)
    {
      //System.err.println("image fetch aborted or errored");
      return null;
    }
    RGB24Image result = new MemoryRGB24Image(width, height);
    int offset = 0;
    for (int y = 0; y < height; y++)
    {
      for (int x = 0; x < width; x++)
      {
        int pixel = pixels[offset++] & 0xffffff;
        result.putSample(RGBIndex.INDEX_RED, x, y, pixel >> 16);
        result.putSample(RGBIndex.INDEX_GREEN, x, y, (pixel >> 8) & 0xff);
        result.putSample(RGBIndex.INDEX_BLUE, x, y, pixel & 0xff);
      }
    }
    return result;
  }
}