| /* ImageConverter.java -- Loads images asynchronously |
| Copyright (C) 2008 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.java.awt.image; |
| |
| import gnu.java.awt.image.AsyncImage; |
| |
| import java.awt.GraphicsEnvironment; |
| import java.awt.Image; |
| import java.awt.Transparency; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.ColorModel; |
| import java.awt.image.DataBuffer; |
| import java.awt.image.ImageConsumer; |
| import java.awt.image.IndexColorModel; |
| import java.awt.image.ImageObserver; |
| import java.awt.image.SinglePixelPackedSampleModel; |
| import java.awt.image.WritableRaster; |
| import java.util.Hashtable; |
| |
| /** |
| * Convert an Image to a BufferedImage. |
| * |
| * @author Roman Kennke (kennke@aicas.com) |
| */ |
| public class ImageConverter implements ImageConsumer |
| { |
| |
| public static final String IMAGE_TRANSPARENCY_PROPERTY = |
| "gnu.awt.image.transparency"; |
| |
| public static final String IMAGE_PROPERTIES_PROPERTY = |
| "gnu.awt.image.properties"; |
| |
| private AsyncImage image; |
| private BufferedImage bImage; |
| private Hashtable imageProperties; |
| private int width, height; |
| private ColorModel colorModel; |
| private ColorModel targetColorModel; |
| |
| public ImageConverter() |
| { |
| width = 0; |
| height = 0; |
| image = new AsyncImage(); |
| } |
| |
| public void setDimensions(int w, int h) |
| { |
| width = w; |
| height = h; |
| } |
| |
| public void setProperties(Hashtable props) |
| { |
| // Ignore for now. |
| } |
| |
| public void setColorModel(ColorModel model) |
| { |
| colorModel = model; |
| } |
| |
| public void setHints(int flags) |
| { |
| // Ignore for now. |
| } |
| |
| public void setPixels(int x, int y, int w, int h, ColorModel model, |
| byte[] pixels, int offset, int scansize) |
| { |
| model = setupColorModel(model); |
| |
| if (bImage == null) |
| { |
| createImage(); |
| } |
| |
| Integer t = (Integer) imageProperties.get("gnu.awt.image.transparency"); |
| int transparency = t.intValue(); |
| |
| if(targetColorModel.equals(model)) |
| { |
| transparency = transferPixels(x, y, w, h, model, pixels, offset, |
| scansize, transparency); |
| } |
| else if (model instanceof IndexColorModel |
| && targetColorModel.equals(ColorModel.getRGBdefault())) |
| { |
| transparency = convertIndexColorModelToSRGB(x, y, w, h, |
| (IndexColorModel) model, |
| pixels, offset, scansize, |
| transparency); |
| } |
| else |
| { |
| transparency = convertPixels(x, y, w, h, model, pixels, offset, |
| scansize, transparency); |
| } |
| |
| imageProperties.put("gnu.awt.image.transparency", |
| Integer.valueOf(transparency)); |
| } |
| |
| public void setPixels(int x, int y, int w, int h, ColorModel model, |
| int[] pixels, int offset, int scansize) |
| { |
| model = setupColorModel(model); |
| if (bImage == null) |
| { |
| createImage(); |
| } |
| |
| Integer t = (Integer) imageProperties.get(IMAGE_TRANSPARENCY_PROPERTY); |
| int transparency= t.intValue(); |
| |
| if (targetColorModel.equals(model)) |
| { |
| transparency = transferPixels(x, y, w, h, model, pixels, offset, |
| scansize, transparency); |
| } |
| else if (model instanceof IndexColorModel |
| && targetColorModel.equals(ColorModel.getRGBdefault())) |
| { |
| transparency = convertIndexColorModelToSRGB(x, y, w, h, |
| (IndexColorModel) model, |
| pixels, offset, scansize, |
| transparency); |
| } |
| else |
| { |
| transparency = convertPixels(x, y, w, h, model, pixels, offset, |
| scansize, transparency); |
| } |
| |
| imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, |
| Integer.valueOf(transparency)); |
| |
| } |
| |
| /** |
| * Initialize the color model for this setPixels run: <br/> |
| * 1. if no color model was given use the hinted color model <br/> |
| * 2. if no color model was given and non was hinted use the default sRGB color model. <br/> |
| * Also:<br/> |
| * If no target color model was set use the color model of the given pixels. |
| * @param model |
| * @return |
| */ |
| private ColorModel setupColorModel(ColorModel model) |
| { |
| // If the given color model is null use the previously hinted color model. |
| if (model == null) |
| model = colorModel; |
| |
| // If no color model was given or hinted use default sRGB. |
| if (model == null) |
| model = ColorModel.getRGBdefault(); |
| |
| // If no specific color model was requested for the target use the current |
| // pixels model. |
| if (targetColorModel == null) |
| targetColorModel = model; |
| targetColorModel = ColorModel.getRGBdefault(); |
| return model; |
| } |
| |
| /** |
| * Creates the image instance into which the pixel data is converted. |
| */ |
| private void createImage() |
| { |
| if (imageProperties == null) |
| { |
| imageProperties = new Hashtable(); |
| } |
| |
| imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, |
| Integer.valueOf(Transparency.OPAQUE)); |
| imageProperties.put(IMAGE_PROPERTIES_PROPERTY, imageProperties); |
| |
| // For the sRGB case let the GraphicsEnvironment create an image for us. |
| if (ColorModel.getRGBdefault().equals(targetColorModel)) |
| { |
| bImage = GraphicsEnvironment.getLocalGraphicsEnvironment() |
| .getDefaultScreenDevice() |
| .getDefaultConfiguration() |
| .createCompatibleImage(width, height, Transparency.TRANSLUCENT); |
| } |
| else |
| { |
| WritableRaster raster = |
| targetColorModel.createCompatibleWritableRaster(width, height); |
| bImage = new BufferedImage(targetColorModel, raster, false, |
| imageProperties); |
| } |
| image.setRealImage(bImage); |
| return; |
| } |
| |
| /** |
| * Transfers pixels into a raster of the same color model. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int transferPixels(int x, int y, int w, int h, ColorModel model, |
| byte[] pixels, int offset, int scansize, |
| int transparency) |
| { |
| // If we have the same color model, then we can simply drop |
| // the pixel value into the target raster. |
| bImage.getRaster().setDataElements(x, y, w, h, pixels); |
| |
| for (int yy = 0; yy < h; yy++) |
| { |
| for (int xx = 0; xx < w; xx++) |
| { |
| int pixel = 0xFF & pixels[yy * scansize + xx + offset]; |
| int alpha = model.getAlpha(pixel); |
| transparency = updateTransparency(alpha, transparency); |
| } |
| } |
| return transparency; |
| } |
| |
| /** |
| * Transfers pixels into a raster of the same color model. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int transferPixels(int x, int y, int w, int h, ColorModel model, |
| int[] pixels, int offset, int scansize, |
| int transparency) |
| { |
| // If we have the same color model, then we can simply drop |
| // the pixel value into the target raster. |
| bImage.getRaster().setDataElements(x, y, w, h, pixels); |
| |
| for (int yy = 0; yy < h; yy++) |
| { |
| for (int xx = 0; xx < w; xx++) |
| { |
| int pixel = pixels[yy * scansize + xx + offset]; |
| int alpha = model.getAlpha(pixel); |
| transparency = updateTransparency(alpha, transparency); |
| } |
| } |
| return transparency; |
| } |
| |
| /** |
| * Converts pixel from one color model to another, and stores them in the |
| * target image. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int convertPixels(int x, int y, int w, int h, ColorModel model, |
| byte[] pixels, int offset, int scansize, |
| int transparency) |
| { |
| // If the color models are not the same, we must convert the |
| // pixel values from one model to the other. |
| Object dataEl = null; |
| // Convert pixels to the destination color model. |
| for (int yy = 0; yy < h; yy++) |
| { |
| for (int xx = 0; xx < w; xx++) |
| { |
| int pixel = 0xFF & pixels[yy * scansize + xx + offset]; |
| int rgb = model.getRGB(pixel); |
| int alpha = model.getAlpha(pixel); |
| transparency = updateTransparency(alpha, transparency); |
| dataEl = targetColorModel.getDataElements(rgb, dataEl); |
| bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); |
| } |
| } |
| return transparency; |
| } |
| |
| /** |
| * Converts pixel from one color model to another, and stores them in the |
| * target image. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int convertPixels(int x, int y, int w, int h, ColorModel model, |
| int[] pixels, int offset, int scansize, |
| int transparency) |
| { |
| // If the color models are not the same, we must convert the |
| // pixel values from one model to the other. |
| Object dataEl = null; |
| // Convert pixels to the destination color model. |
| for (int yy = 0; yy < h; yy++) |
| { |
| for (int xx = 0; xx < w; xx++) |
| { |
| int pixel = pixels[yy * scansize + xx + offset]; |
| int rgb = model.getRGB(pixel); |
| int alpha = model.getAlpha(pixel); |
| transparency = updateTransparency(alpha, transparency); |
| dataEl = targetColorModel.getDataElements(rgb, dataEl); |
| bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); |
| } |
| } |
| return transparency; |
| } |
| |
| /** |
| * Converts pixels from an index color model to the target image. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int convertIndexColorModelToSRGB(int x, int y, int w, int h, |
| IndexColorModel model, |
| byte[] pixels, int offset, |
| int scansize, int transparency) |
| { |
| |
| int mapSize = model.getMapSize(); |
| int[] colorMap = new int[mapSize]; |
| for(int i=0; i < mapSize; i++) |
| { |
| colorMap[i] = model.getRGB(i); |
| } |
| |
| WritableRaster raster = bImage.getRaster(); |
| SinglePixelPackedSampleModel sampleMode = |
| (SinglePixelPackedSampleModel) raster.getSampleModel(); |
| DataBuffer dataBuffer = (DataBuffer) raster.getDataBuffer(); |
| |
| int rasterOffset = sampleMode.getOffset(x,y)+dataBuffer.getOffset(); |
| int rasterScanline = sampleMode.getScanlineStride(); |
| |
| for (int yy = 0; yy < h; yy++) |
| { |
| int xoffset = offset; |
| for (int xx = 0; xx < w; xx++) |
| { |
| int argb = colorMap[(pixels[xoffset++] & 0xFF)]; |
| dataBuffer.setElem(rasterOffset+xx, argb); |
| int alpha = (argb >>> 24); |
| transparency = updateTransparency(alpha, transparency); |
| } |
| offset += scansize; |
| rasterOffset += rasterScanline; |
| } |
| |
| return transparency; |
| } |
| |
| /** |
| * Converts pixels from an index color model to the target image. |
| * |
| * @param x the X coordinate of the source pixel rectangle |
| * @param y the Y coordinate of the source pixel rectangle |
| * @param w the width of the source pixel rectangle |
| * @param h the height of the source pixel rectangle |
| * @param model the color model of the source pixels |
| * @param pixels the pixel data |
| * @param offset the offset in the pixel array |
| * @param scansize the scanline size |
| * @param transparency the assumed transparency |
| * |
| * @return the determined transparency |
| */ |
| private int convertIndexColorModelToSRGB(int x, int y, int w, int h, |
| IndexColorModel model, int[] pixels, |
| int offset, int scansize, |
| int transparency) |
| { |
| int mapSize = model.getMapSize(); |
| int[] colorMap = new int[mapSize]; |
| for(int i=0; i < mapSize; i++) |
| { |
| colorMap[i] = model.getRGB(i); |
| } |
| |
| WritableRaster raster = bImage.getRaster(); |
| SinglePixelPackedSampleModel sampleMode = |
| (SinglePixelPackedSampleModel) raster.getSampleModel(); |
| DataBuffer dataBuffer = (DataBuffer)raster.getDataBuffer(); |
| |
| int rasterOffset = sampleMode.getOffset(x, y) + dataBuffer.getOffset(); |
| int rasterScanline = sampleMode.getScanlineStride(); |
| |
| for (int yy = 0; yy < h; yy++) |
| { |
| int xoffset = offset; |
| for (int xx = 0; xx < w; xx++) |
| { |
| int argb = colorMap[pixels[xoffset++]]; |
| dataBuffer.setElem(rasterOffset + xx, argb); |
| int alpha = (argb >>> 24); |
| transparency = updateTransparency(alpha, transparency); |
| } |
| offset += scansize; |
| rasterOffset += rasterScanline; |
| } |
| |
| return transparency; |
| } |
| |
| /** |
| * Updates the transparency information according to the alpha pixel value. |
| * |
| * @param alpha the alpha pixel value |
| * @param transparency the old transparency |
| * |
| * @return the updated transparency |
| */ |
| private int updateTransparency(int alpha, int transparency) |
| { |
| if (alpha != 0xFF) |
| { |
| if (alpha == 0x00 && transparency <= Transparency.BITMASK) |
| { |
| transparency = Transparency.BITMASK; |
| } |
| else if (transparency < Transparency.TRANSLUCENT) |
| { |
| transparency = Transparency.TRANSLUCENT; |
| } |
| } |
| return transparency; |
| } |
| |
| public void imageComplete(int status) |
| { |
| image.notifyObservers(ImageObserver.ALLBITS, 0, 0, width, height); |
| } |
| |
| public void setTargetColorModel(ColorModel model) |
| { |
| targetColorModel = model; |
| } |
| |
| public Image getImage() |
| { |
| return image; |
| } |
| } |