summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/kitfox/svg/batik/GraphicsUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/kitfox/svg/batik/GraphicsUtil.java')
-rw-r--r--src/main/java/com/kitfox/svg/batik/GraphicsUtil.java382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/main/java/com/kitfox/svg/batik/GraphicsUtil.java b/src/main/java/com/kitfox/svg/batik/GraphicsUtil.java
new file mode 100644
index 0000000..b52148b
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/batik/GraphicsUtil.java
@@ -0,0 +1,382 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package com.kitfox.svg.batik;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+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 java.awt.image.renderable.RenderContext;
+import java.awt.image.renderable.RenderableImage;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ *
+ * @author kitfox
+ */
+public class GraphicsUtil
+{
+
+ /** Creates a new instance of GraphicsUtil */
+ public GraphicsUtil()
+ {
+ }
+
+ /**
+ * 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()== false)
+ // 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());
+
+ int [] pixel = null;
+ int bands = wr.getNumBands();
+ float norm;
+ if (newAlphaPreMult)
+ {
+ 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
+ {
+ 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<y1; y++)
+ for (int x=x0; x<x1; x++)
+ {
+ pixel = wr.getPixel(x,y,pixel);
+ a = pixel[bands-1];
+ if ((a >= 0) && (a < 255))
+ {
+ alpha = a*norm;
+ for (b=0; b<bands-1; b++)
+ pixel[b] = (int)(pixel[b]*alpha+0.5f);
+ wr.setPixel(x,y,pixel);
+ }
+ }
+ }
+ } else
+ {
+ if (is_BYTE_COMP_Data(wr.getSampleModel()))
+ divide_BYTE_COMP_Data(wr);
+ else if (is_INT_PACK_Data(wr.getSampleModel(), true))
+ divide_INT_PACK_Data(wr);
+ else
+ {
+ int x0, x1, y0, y1, a, b;
+ float ialpha;
+ x0 = wr.getMinX();
+ x1 = x0+wr.getWidth();
+ y0 = wr.getMinY();
+ y1 = y0+wr.getHeight();
+ for (int y=y0; y<y1; y++)
+ for (int x=x0; x<x1; x++)
+ {
+ pixel = wr.getPixel(x,y,pixel);
+ a = pixel[bands-1];
+ if ((a > 0) && (a < 255))
+ {
+ ialpha = 255/(float)a;
+ for (b=0; b<bands-1; b++)
+ pixel[b] = (int)(pixel[b]*ialpha+0.5f);
+ wr.setPixel(x,y,pixel);
+ }
+ }
+ }
+ }
+
+ return coerceColorModel(cm, newAlphaPreMult);
+ }
+
+
+ public static boolean is_INT_PACK_Data(SampleModel sm,
+ boolean requireAlpha)
+ {
+ // Check ColorModel is of type DirectColorModel
+ if(!(sm instanceof SinglePixelPackedSampleModel)) return false;
+
+ // Check transfer type
+ if(sm.getDataType() != DataBuffer.TYPE_INT) return false;
+
+ SinglePixelPackedSampleModel sppsm;
+ sppsm = (SinglePixelPackedSampleModel)sm;
+
+ int [] masks = sppsm.getBitMasks();
+ if (masks.length == 3)
+ {
+ if (requireAlpha) return false;
+ } else if (masks.length != 4)
+ return false;
+
+ if(masks[0] != 0x00ff0000) return false;
+ if(masks[1] != 0x0000ff00) return false;
+ if(masks[2] != 0x000000ff) return false;
+ if ((masks.length == 4) &&
+ (masks[3] != 0xff000000)) return false;
+
+ return true;
+ }
+
+ 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()));
+ int n=0;
+ // Access the pixel data array
+ final int pixels[] = db.getBankData()[0];
+ for (int y=0; y<wr.getHeight(); y++)
+ {
+ int sp = base + y*scanStride;
+ final int end = sp + width;
+ while (sp < end)
+ {
+ int pixel = pixels[sp];
+ int a = pixel>>>24;
+ if ((a>=0) && (a<255))
+ {
+ pixels[sp] = ((a << 24) |
+ ((((pixel&0xFF0000)*a)>>8)&0xFF0000) |
+ ((((pixel&0x00FF00)*a)>>8)&0x00FF00) |
+ ((((pixel&0x0000FF)*a)>>8)&0x0000FF));
+ }
+ sp++;
+ }
+ }
+ }
+
+ protected static void divide_INT_PACK_Data(WritableRaster wr)
+ {
+ // System.out.println("Divide Int");
+
+ 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()));
+ int pixel, a, aFP, n=0;
+ // Access the pixel data array
+ final int pixels[] = db.getBankData()[0];
+ for (int y=0; y<wr.getHeight(); y++)
+ {
+ int sp = base + y*scanStride;
+ final int end = sp + width;
+ while (sp < end)
+ {
+ pixel = pixels[sp];
+ a = pixel>>>24;
+ if (a<=0)
+ {
+ pixels[sp] = 0x00FFFFFF;
+ }
+ else if (a<255)
+ {
+ aFP = (0x00FF0000/a);
+ pixels[sp] =
+ ((a << 24) |
+ (((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) |
+ (((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) |
+ (((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16));
+ }
+ sp++;
+ }
+ }
+ }
+
+ public static boolean is_BYTE_COMP_Data(SampleModel sm)
+ {
+ // Check ColorModel is of type DirectColorModel
+ if(!(sm instanceof ComponentSampleModel)) return false;
+
+ // Check transfer type
+ if(sm.getDataType() != DataBuffer.TYPE_BYTE) return false;
+
+ return true;
+ }
+
+ 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 a=0;
+ int aOff = bandOff[bandOff.length-1];
+ int bands = bandOff.length-1;
+ int b, i;
+
+ // Access the pixel data array
+ final byte pixels[] = db.getBankData()[0];
+ for (int y=0; y<wr.getHeight(); y++)
+ {
+ int sp = base + y*scanStride;
+ final int end = sp + width*pixStride;
+ while (sp < end)
+ {
+ a = pixels[sp+aOff]&0xFF;
+ if (a!=0xFF)
+ for (b=0; b<bands; b++)
+ {
+ i = sp+bandOff[b];
+ pixels[i] = (byte)(((pixels[i]&0xFF)*a)>>8);
+ }
+ sp+=pixStride;
+ }
+ }
+ }
+
+ 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 a=0;
+ int aOff = bandOff[bandOff.length-1];
+ int bands = bandOff.length-1;
+ int b, i;
+ // Access the pixel data array
+ final byte pixels[] = db.getBankData()[0];
+ for (int y=0; y<wr.getHeight(); y++)
+ {
+ int sp = base + y*scanStride;
+ final int end = sp + width*pixStride;
+ while (sp < end)
+ {
+ a = pixels[sp+aOff]&0xFF;
+ if (a==0)
+ {
+ for (b=0; b<bands; b++)
+ pixels[sp+bandOff[b]] = (byte)0xFF;
+ } else if (a<255)
+ {
+ int aFP = (0x00FF0000/a);
+ for (b=0; b<bands; b++)
+ {
+ i = sp+bandOff[b];
+ pixels[i] = (byte)(((pixels[i]&0xFF)*aFP)>>>16);
+ }
+ }
+ sp+=pixStride;
+ }
+ }
+ }
+
+
+}