All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlgraphics.image.GraphicsUtil Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: GraphicsUtil.java 750418 2009-03-05 11:03:54Z vhennebert $ */

package org.apache.xmlgraphics.image;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;

import org.apache.xmlgraphics.image.rendered.Any2LsRGBRed;
import org.apache.xmlgraphics.image.rendered.Any2sRGBRed;
import org.apache.xmlgraphics.image.rendered.BufferedImageCachableRed;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.xmlgraphics.image.rendered.RenderedImageCachableRed;

/**
 * Set of utility methods for Graphics.
 * These generally bypass broken methods in Java2D or provide tweaked
 * implementations.
 *
 * @author Thomas DeWeese
 * @version $Id: GraphicsUtil.java 750418 2009-03-05 11:03:54Z vhennebert $
 */
public class GraphicsUtil {

    public static AffineTransform IDENTITY = new AffineTransform();

    /**
     * Standard prebuilt Linear_sRGB color model with no alpha */
    public static final ColorModel Linear_sRGB =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_LINEAR_RGB), 24,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0x0, false,
                             DataBuffer.TYPE_INT);
    /**
     * Standard prebuilt Linear_sRGB color model with premultiplied alpha.
     */
    public static final ColorModel Linear_sRGB_Pre =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_LINEAR_RGB), 32,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0xFF000000, true,
                             DataBuffer.TYPE_INT);
    /**
     * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
     */
    public static final ColorModel Linear_sRGB_Unpre =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_LINEAR_RGB), 32,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0xFF000000, false,
                             DataBuffer.TYPE_INT);

    /**
     * Standard prebuilt sRGB color model with no alpha.
     */
    public static final ColorModel sRGB =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_sRGB), 24,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0x0, false,
                             DataBuffer.TYPE_INT);
    /**
     * Standard prebuilt sRGB color model with premultiplied alpha.
     */
    public static final ColorModel sRGB_Pre =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_sRGB), 32,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0xFF000000, true,
                             DataBuffer.TYPE_INT);
    /**
     * Standard prebuilt sRGB color model with unpremultiplied alpha.
     */
    public static final ColorModel sRGB_Unpre =
        new DirectColorModel(ColorSpace.getInstance
                             (ColorSpace.CS_sRGB), 32,
                             0x00FF0000, 0x0000FF00,
                             0x000000FF, 0xFF000000, false,
                             DataBuffer.TYPE_INT);

    /**
     * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
     * based on premult flag.
     * @param premult True if the ColorModel should have premultiplied alpha.
     * @return        a ColorMdoel with Linear sRGB colorSpace and
     *                the alpha channel set in accordance with
     *                premult
     */
    public static ColorModel makeLinear_sRGBCM(boolean premult) {
         return premult ? Linear_sRGB_Pre : Linear_sRGB_Unpre;
    }

    /**
     * Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
     * @param width   The desired width of the BufferedImage
     * @param height  The desired height of the BufferedImage
     * @param premult The desired state of alpha premultiplied
     * @return        The requested BufferedImage.
     */
    public static BufferedImage makeLinearBufferedImage(int width,
                                                        int height,
                                                        boolean premult) {
        ColorModel cm = makeLinear_sRGBCM(premult);
        WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
        return new BufferedImage(cm, wr, premult, null);
    }

    /**
     * This method will return a CacheableRed that has it's data in
     * the linear sRGB colorspace. If src is already in
     * linear sRGB then this method does nothing and returns src.
     * Otherwise it creates a transform that will convert
     * src's output to linear sRGB and returns that CacheableRed.
     *
     * @param src The image to convert to linear sRGB.
     * @return    An equivilant image to src who's data is in
     *            linear sRGB.
     */
    public static CachableRed convertToLsRGB(CachableRed src) {
        ColorModel cm = src.getColorModel();
        ColorSpace cs = cm.getColorSpace();
        if (cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
            return src;

        return new Any2LsRGBRed(src);
    }

    /**
     * This method will return a CacheableRed that has it's data in
     * the sRGB colorspace. If src is already in
     * sRGB then this method does nothing and returns src.
     * Otherwise it creates a transform that will convert
     * src's output to sRGB and returns that CacheableRed.
     *
     * @param src The image to convert to sRGB.
     * @return    An equivilant image to src who's data is in sRGB.
     */
    public static CachableRed convertTosRGB(CachableRed src) {
        ColorModel cm = src.getColorModel();
        ColorSpace cs = cm.getColorSpace();
        if (cs == ColorSpace.getInstance(ColorSpace.CS_sRGB))
            return src;

        return new Any2sRGBRed(src);
    }

    /**
     * Convertes any RenderedImage to a CacheableRed.  

* If ri is already a CacheableRed it casts it down and * returns it.

* * In cases where ri is not already a CacheableRed it * wraps ri with a helper class. The wrapped * CacheableRed "Pretends" that it has no sources since it has no * way of inteligently handling the dependency/dirty region calls * if it exposed the source. * @param ri The RenderedImage to convert. * @return a CacheableRed that contains the same data as ri. */ public static CachableRed wrap(RenderedImage ri) { if (ri instanceof CachableRed) return (CachableRed) ri; if (ri instanceof BufferedImage) return new BufferedImageCachableRed((BufferedImage)ri); return new RenderedImageCachableRed(ri); } /** * An internal optimized version of copyData designed to work on * Integer packed data with a SinglePixelPackedSampleModel. Only * the region of overlap between src and dst is copied. * * Calls to this should be preflighted with is_INT_PACK_Data * on both src and dest (requireAlpha can be false). * * @param src The source of the data * @param dst The destination for the data. */ public static void copyData_INT_PACK(Raster src, WritableRaster dst) { // System.out.println("Fast copyData"); int x0 = dst.getMinX(); if (x0 < src.getMinX()) x0 = src.getMinX(); int y0 = dst.getMinY(); if (y0 < src.getMinY()) y0 = src.getMinY(); int x1 = dst.getMinX()+dst.getWidth()-1; if (x1 > src.getMinX()+src.getWidth()-1) x1 = src.getMinX()+src.getWidth()-1; int y1 = dst.getMinY()+dst.getHeight()-1; if (y1 > src.getMinY()+src.getHeight()-1) y1 = src.getMinY()+src.getHeight()-1; int width = x1-x0+1; int height = y1-y0+1; SinglePixelPackedSampleModel srcSPPSM; srcSPPSM = (SinglePixelPackedSampleModel)src.getSampleModel(); final int srcScanStride = srcSPPSM.getScanlineStride(); DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer(); final int [] srcPixels = srcDB.getBankData()[0]; final int srcBase = (srcDB.getOffset() + srcSPPSM.getOffset(x0-src.getSampleModelTranslateX(), y0-src.getSampleModelTranslateY())); SinglePixelPackedSampleModel dstSPPSM; dstSPPSM = (SinglePixelPackedSampleModel)dst.getSampleModel(); final int dstScanStride = dstSPPSM.getScanlineStride(); DataBufferInt dstDB = (DataBufferInt)dst.getDataBuffer(); final int [] dstPixels = dstDB.getBankData()[0]; final int dstBase = (dstDB.getOffset() + dstSPPSM.getOffset(x0-dst.getSampleModelTranslateX(), y0-dst.getSampleModelTranslateY())); if ((srcScanStride == dstScanStride) && (srcScanStride == width)) { // System.out.println("VERY Fast copyData"); System.arraycopy(srcPixels, srcBase, dstPixels, dstBase, width*height); } else if (width > 128) { int srcSP = srcBase; int dstSP = dstBase; for (int y=0; y src.getMinX()+src.getWidth()-1) x1 = src.getMinX()+src.getWidth()-1; int y1 = dst.getMinY()+dst.getHeight()-1; if (y1 > src.getMinY()+src.getHeight()-1) y1 = src.getMinY()+src.getHeight()-1; int width = x1-x0+1; int [] data = null; for (int y = y0; y <= y1 ; y++) { data = src.getPixels(x0,y,width,1,data); dst.setPixels (x0,y,width,1,data); } } /** * Copies data from one raster to another. Only the region of * overlap between src and dst is copied. Src and * Dst must have compatible SampleModels. * * @param src The source of the data * @param dst The destination for the data. */ public static void copyData(Raster src, WritableRaster dst) { if (is_INT_PACK_Data(src.getSampleModel(), false) && is_INT_PACK_Data(dst.getSampleModel(), false)) { copyData_INT_PACK(src, dst); return; } copyData_FALLBACK(src, dst); } /** * Creates a new raster that has a copy of the data in * ras. This is highly optimized for speed. There is * no provision for changing any aspect of the SampleModel. * * This method should be used when you need to change the contents * of a Raster that you do not "own" (ie the result of a * getData call). * @param ras The Raster to copy. * @return A writable copy of ras */ public static WritableRaster copyRaster(Raster ras) { return copyRaster(ras, ras.getMinX(), ras.getMinY()); } /** * Creates a new raster that has a copy of the data in * ras. This is highly optimized for speed. There is * no provision for changing any aspect of the SampleModel. * However you can specify a new location for the returned raster. * * This method should be used when you need to change the contents * of a Raster that you do not "own" (ie the result of a * getData call). * * @param ras The Raster to copy. * * @param minX The x location for the upper left corner of the * returned WritableRaster. * * @param minY The y location for the upper left corner of the * returned WritableRaster. * * @return A writable copy of ras */ public static WritableRaster copyRaster(Raster ras, int minX, int minY) { WritableRaster ret = Raster.createWritableRaster (ras.getSampleModel(), new Point(0,0)); ret = ret.createWritableChild (ras.getMinX()-ras.getSampleModelTranslateX(), ras.getMinY()-ras.getSampleModelTranslateY(), ras.getWidth(), ras.getHeight(), minX, minY, null); // Use System.arraycopy to copy the data between the two... DataBuffer srcDB = ras.getDataBuffer(); DataBuffer retDB = ret.getDataBuffer(); if (srcDB.getDataType() != retDB.getDataType()) { throw new IllegalArgumentException ("New DataBuffer doesn't match original"); } int len = srcDB.getSize(); int banks = srcDB.getNumBanks(); int [] offsets = srcDB.getOffsets(); for (int b=0; b< banks; b++) { switch (srcDB.getDataType()) { case DataBuffer.TYPE_BYTE: { DataBufferByte srcDBT = (DataBufferByte)srcDB; DataBufferByte retDBT = (DataBufferByte)retDB; System.arraycopy(srcDBT.getData(b), offsets[b], retDBT.getData(b), offsets[b], len); break; } case DataBuffer.TYPE_INT: { DataBufferInt srcDBT = (DataBufferInt)srcDB; DataBufferInt retDBT = (DataBufferInt)retDB; System.arraycopy(srcDBT.getData(b), offsets[b], retDBT.getData(b), offsets[b], len); break; } case DataBuffer.TYPE_SHORT: { DataBufferShort srcDBT = (DataBufferShort)srcDB; DataBufferShort retDBT = (DataBufferShort)retDB; System.arraycopy(srcDBT.getData(b), offsets[b], retDBT.getData(b), offsets[b], len); break; } case DataBuffer.TYPE_USHORT: { DataBufferUShort srcDBT = (DataBufferUShort)srcDB; DataBufferUShort retDBT = (DataBufferUShort)retDB; System.arraycopy(srcDBT.getData(b), offsets[b], retDBT.getData(b), offsets[b], len); break; } } } return ret; } /** * Coerces ras to be writable. The returned Raster continues to * reference the DataBuffer from ras, so modifications to the returned * WritableRaster will be seen in ras.

* * This method should only be used if you need a WritableRaster due to * an interface (such as to construct a BufferedImage), but have no * intention of modifying the contents of the returned Raster. If * you have any doubt about other users of the data in ras, * use copyRaster (above). * @param ras The raster to make writable. * @return A Writable version of ras (shares DataBuffer with * ras). */ public static WritableRaster makeRasterWritable(Raster ras) { return makeRasterWritable(ras, ras.getMinX(), ras.getMinY()); } /** * Coerces ras to be writable. The returned Raster continues to * reference the DataBuffer from ras, so modifications to the returned * WritableRaster will be seen in ras.

* * You can specify a new location for the returned WritableRaster, this * is especially useful for constructing BufferedImages which require * the Raster to be at (0,0). * * This method should only be used if you need a WritableRaster due to * an interface (such as to construct a BufferedImage), but have no * intention of modifying the contents of the returned Raster. If * you have any doubt about other users of the data in ras, * use copyRaster (above). * * @param ras The raster to make writable. * * @param minX The x location for the upper left corner of the * returned WritableRaster. * * @param minY The y location for the upper left corner of the * returned WritableRaster. * * @return A Writable version of ras with it's upper left * hand coordinate set to minX, minY (shares it's DataBuffer * with ras). */ public static WritableRaster makeRasterWritable(Raster ras, int minX, int minY) { WritableRaster ret = Raster.createWritableRaster (ras.getSampleModel(), ras.getDataBuffer(), new Point(0,0)); ret = ret.createWritableChild (ras.getMinX()-ras.getSampleModelTranslateX(), ras.getMinY()-ras.getSampleModelTranslateY(), ras.getWidth(), ras.getHeight(), minX, minY, null); return ret; } /** * Create a new ColorModel with it's alpha premultiplied state matching * newAlphaPreMult. * @param cm The ColorModel to change the alpha premult state of. * @param newAlphaPreMult The new state of alpha premult. * @return A new colorModel that has isAlphaPremultiplied() * equal to newAlphaPreMult. */ public static ColorModel coerceColorModel(ColorModel cm, boolean newAlphaPreMult) { if (cm.isAlphaPremultiplied() == newAlphaPreMult) return cm; // Easiest way to build proper colormodel for new Alpha state... // Eventually this should switch on known ColorModel types and // only fall back on this hack when the CM type is unknown. WritableRaster wr = cm.createCompatibleWritableRaster(1,1); return cm.coerceData(wr, newAlphaPreMult); } /** * Coerces data within a bufferedImage to match newAlphaPreMult, * Note that this can not change the colormodel of bi so you * * @param wr The raster to change the state of. * @param cm The colormodel currently associated with data in wr. * @param newAlphaPreMult The desired state of alpha Premult for raster. * @return A new colormodel that matches newAlphaPreMult. */ public static ColorModel coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) { // System.out.println("CoerceData: " + cm.isAlphaPremultiplied() + // " Out: " + newAlphaPreMult); if (!cm.hasAlpha()) // Nothing to do no alpha channel return cm; if (cm.isAlphaPremultiplied() == newAlphaPreMult) // nothing to do alpha state matches... return cm; // System.out.println("CoerceData: " + wr.getSampleModel()); if (newAlphaPreMult) { multiplyAlpha(wr); } else { divideAlpha(wr); } return coerceColorModel(cm, newAlphaPreMult); } public static void multiplyAlpha(WritableRaster wr) { if (is_BYTE_COMP_Data(wr.getSampleModel())) mult_BYTE_COMP_Data(wr); else if (is_INT_PACK_Data(wr.getSampleModel(), true)) mult_INT_PACK_Data(wr); else { int [] pixel = null; int bands = wr.getNumBands(); float norm = 1f/255f; int x0, x1, y0, y1, a, b; float alpha; x0 = wr.getMinX(); x1 = x0+wr.getWidth(); y0 = wr.getMinY(); y1 = y0+wr.getHeight(); for (int y=y0; y= 0) && (a < 255)) { alpha = a*norm; for (b=0; b 0) && (a < 255)) { ialpha = 255/(float)a; for (b=0; b= 0) { // Fill alpha channel with 255's oPix[out] = 255; out -= bands; } int b, in; for (int y=y0; y<=y1; y++) { pixel = srcR.getPixels(x0,y,w,1,pixel); in = w*(bands-1)-1; out = (w*bands)-2; // The 2 skips alpha channel on last pix switch (bands) { case 4: while(in >= 0) { oPix[out--] = pixel[in--]; oPix[out--] = pixel[in--]; oPix[out--] = pixel[in--]; out--; } break; default: while(in >= 0) { for (b=0; b= 0) { a = pixel[in]; if (a == 255) in -= 4; else { in--; alpha = fpNorm*a; pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--; pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--; pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--; } } break; default: while(in >= 0) { a = pixel[in]; if (a == 255) in -= bands; else { in--; alpha = fpNorm*a; for (b=0; b>>24; in--; } } } } dstR.setPixels(x0+dx, y+dy, w, 1, pixel); } } else if (dstAlpha && !dst.isAlphaPremultiplied()) { // Src and dest have Alpha but we need to divide it out for dst. // System.out.println("Div Case"); int a, b, ialpha, in, fpNorm = 0x00FF0000, pt5 = 1<<15; for (int y=y0; y<=y1; y++) { pixel = srcR.getPixels(x0,y,w,1,pixel); in=(bands*w)-1; switch(bands) { case 4: while(in >= 0) { a = pixel[in]; if ((a <= 0) || (a >= 255)) in -= 4; else { in--; ialpha = fpNorm/a; pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--; pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--; pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--; } } break; default: while(in >= 0) { a = pixel[in]; if ((a <= 0) || (a >= 255)) in -= bands; else { in--; ialpha = fpNorm/a; for (b=0; b>>16; in--; } } } } dstR.setPixels(x0+dx, y+dy, w, 1, pixel); } } else if (src.isAlphaPremultiplied()) { int [] oPix = new int[bands*w]; // Src has alpha dest does not so unpremult and store... // System.out.println("Remove Alpha, Div Case"); int a, b, ialpha, in, out, fpNorm = 0x00FF0000, pt5 = 1<<15; for (int y=y0; y<=y1; y++) { pixel = srcR.getPixels(x0,y,w,1,pixel); in = (bands+1)*w -1; out = (bands*w)-1; while(in >= 0) { a = pixel[in]; in--; if (a > 0) { if (a < 255) { ialpha = fpNorm/a; for (b=0; b>>16; } else for (b=0; b>>24; if (a<=0) { pixels[sp] = 0x00FFFFFF; } else if (a<255) { int aFP = (0x00FF0000/a); pixels[sp] = ((a << 24) | (((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) | (((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) | (((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16)); } sp++; } } } protected static void mult_INT_PACK_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); SinglePixelPackedSampleModel sppsm; sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = sppsm.getScanlineStride(); DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); final int base = (db.getOffset() + sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); // Access the pixel data array final int[] pixels = db.getBankData()[0]; for (int y=0; y>>24; if ((a>=0) && (a<255)) { // this does NOT include a == 255 (0xff) ! pixels[sp] = ((a << 24) | ((((pixel&0xFF0000)*a)>>8)&0xFF0000) | ((((pixel&0x00FF00)*a)>>8)&0x00FF00) | ((((pixel&0x0000FF)*a)>>8)&0x0000FF)); } sp++; } } } protected static void divide_BYTE_COMP_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); ComponentSampleModel csm; csm = (ComponentSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = csm.getScanlineStride(); final int pixStride = csm.getPixelStride(); final int [] bandOff = csm.getBandOffsets(); DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); final int base = (db.getOffset() + csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); int aOff = bandOff[bandOff.length-1]; int bands = bandOff.length-1; // Access the pixel data array final byte[] pixels = db.getBankData()[0]; for (int y=0; y>>16); } } sp+=pixStride; } } } protected static void mult_BYTE_COMP_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); ComponentSampleModel csm; csm = (ComponentSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = csm.getScanlineStride(); final int pixStride = csm.getPixelStride(); final int [] bandOff = csm.getBandOffsets(); DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); final int base = (db.getOffset() + csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); int aOff = bandOff[bandOff.length-1]; int bands = bandOff.length-1; // Access the pixel data array final byte[] pixels = db.getBankData()[0]; for (int y=0; y>8); } sp+=pixStride; } } } /* This is skanky debugging code that might be useful in the future: if (count == 33) { String label = "sub [" + x + ", " + y + "]: "; org.ImageDisplay.showImage (label, subBI); org.ImageDisplay.printImage (label, subBI, new Rectangle(75-iR.x, 90-iR.y, 32, 32)); } // if ((count++ % 50) == 10) // org.ImageDisplay.showImage("foo: ", subBI); Graphics2D realG2D = g2d; while (realG2D instanceof sun.java2d.ProxyGraphics2D) { realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate(); } if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) { count++; if (count == 34) { RenderedImage ri; ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg; // g2d.setComposite(SVGComposite.OVER); // org.ImageDisplay.showImage("Bar: " + count, cr); org.ImageDisplay.printImage("Bar: " + count, cr, new Rectangle(75, 90, 32, 32)); org.ImageDisplay.showImage ("Foo: " + count, ri); org.ImageDisplay.printImage("Foo: " + count, ri, new Rectangle(75, 90, 32, 32)); System.out.println("BI: " + ri); System.out.println("BISM: " + ri.getSampleModel()); System.out.println("BICM: " + ri.getColorModel()); System.out.println("BICM class: " + ri.getColorModel().getClass()); System.out.println("BICS: " + ri.getColorModel().getColorSpace()); System.out.println ("sRGB CS: " + ColorSpace.getInstance(ColorSpace.CS_sRGB)); System.out.println("G2D info"); System.out.println("\tComposite: " + g2d.getComposite()); System.out.println("\tTransform" + g2d.getTransform()); java.awt.RenderingHints rh = g2d.getRenderingHints(); java.util.Set keys = rh.keySet(); java.util.Iterator iter = keys.iterator(); while (iter.hasNext()) { Object o = iter.next(); System.out.println("\t" + o.toString() + " -> " + rh.get(o).toString()); } ri = cr; System.out.println("RI: " + ri); System.out.println("RISM: " + ri.getSampleModel()); System.out.println("RICM: " + ri.getColorModel()); System.out.println("RICM class: " + ri.getColorModel().getClass()); System.out.println("RICS: " + ri.getColorModel().getColorSpace()); } } */ /** * Extracts an alpha raster from a RenderedImage. The method tries to avoid copying data * unnecessarily by checking if the RenderedImage is a BufferedImage which offers suitable * direct methods. * @param image the image * @return the alpha raster */ public static Raster getAlphaRaster(RenderedImage image) { ColorModel cm = image.getColorModel(); if (!cm.hasAlpha() || cm.getTransparency() != ColorModel.TRANSLUCENT) { throw new IllegalStateException("Image doesn't have an alpha channel"); } Raster alpha; if (image instanceof BufferedImage) { //Optimization possible with BufferedImage (No copying) alpha = ((BufferedImage)image).getAlphaRaster(); } else { WritableRaster wraster = GraphicsUtil.makeRasterWritable(image.getData()); alpha = image.getColorModel().getAlphaRaster(wraster); } return alpha; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy