Source for gnu.java.awt.java2d.AlphaCompositeContext

   1: /* AlphaCompositeContext.java -- CompositeContext impl for AlphaComposite
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.java2d;
  40: 
  41: import java.awt.AWTError;
  42: import java.awt.AlphaComposite;
  43: import java.awt.CompositeContext;
  44: import java.awt.image.ColorModel;
  45: import java.awt.image.Raster;
  46: import java.awt.image.WritableRaster;
  47: 
  48: /**
  49:  * A CompositeContext implementation for {@link AlphaComposite}.
  50:  *
  51:  * @author Roman Kennke (kennke@aicas.com)
  52:  */
  53: public class AlphaCompositeContext
  54:   implements CompositeContext
  55: {
  56: 
  57:   /**
  58:    * The Composite object for which we perform compositing.
  59:    */
  60:   private AlphaComposite composite;
  61: 
  62:   /**
  63:    * The source color model.
  64:    */
  65:   private ColorModel srcColorModel;
  66: 
  67:   /**
  68:    * The destination color model.
  69:    */
  70:   private ColorModel dstColorModel;
  71: 
  72:   /**
  73:    * The blending factor for the source.
  74:    */
  75:   private float fs;
  76: 
  77:   /**
  78:    * The blending factor for the destination.
  79:    */
  80:   private float fd;
  81: 
  82:   /**
  83:    * Creates a new AlphaCompositeContext.
  84:    *
  85:    * @param aComp the AlphaComposite object
  86:    * @param srcCM the source color model
  87:    * @param dstCM the destination color model
  88:    */
  89:   public AlphaCompositeContext(AlphaComposite aComp, ColorModel srcCM,
  90:                                ColorModel dstCM)
  91:   {
  92:     composite = aComp;
  93:     srcColorModel = srcCM;
  94:     dstColorModel = dstCM;
  95: 
  96: 
  97:     // Determine the blending factors according to the rule in the
  98:     // AlphaComposite. For some rules the factors must be determined
  99:     // dynamically because they depend on the actual pixel value.
 100:     switch (composite.getRule())
 101:     {
 102:       case AlphaComposite.CLEAR:
 103:         fs = 0.F;
 104:         fd= 0.F;
 105:         break;
 106:       case AlphaComposite.DST:
 107:         fs = 0.F;
 108:         fd= 1.F;
 109:         break;
 110:       case AlphaComposite.DST_ATOP:
 111:         fs = 1.F; // Determined later as 1 - alpha_dst;
 112:         fd = 1.F; // Determined later as alpha_src;
 113:         break;
 114:       case AlphaComposite.DST_IN:
 115:         fs = 0.F;
 116:         fd = 0.F; // Determined later as alpha_src;
 117:         break;
 118:       case AlphaComposite.DST_OUT:
 119:         fs = 0.F;
 120:         fd = 0.F; // Determined later as 1 - alpha_src;
 121:         break;
 122:       case AlphaComposite.DST_OVER:
 123:         fs = 1.F; // Determined later as 1 - alpha_dst.
 124:         fd= 1.F;
 125:         break;
 126:       case AlphaComposite.SRC:
 127:         fs = 1.F;
 128:         fd= 0.F;
 129:         break;
 130:       case AlphaComposite.SRC_ATOP:
 131:         fs = 1.F; // Determined later as alpha_dst;
 132:         fd = 1.F; // Determined later as 1 - alpha_src;
 133:         break;
 134:       case AlphaComposite.SRC_IN:
 135:         fs = 0.F; // Determined later as alpha_dst;
 136:         fd = 0.F;
 137:         break;
 138:       case AlphaComposite.SRC_OUT:
 139:         fs = 0.F; // Determined later as 1 - alpha_dst;
 140:         fd = 0.F;
 141:         break;
 142:       case AlphaComposite.SRC_OVER:
 143:         fs = 1.F;
 144:         fd= 1.F; // Determined later as 1 - alpha_src.
 145:         break;
 146:       case AlphaComposite.XOR:
 147:         fs = 1.F; // Determined later as 1 - alpha_dst.
 148:         fd= 1.F; // Determined later as 1 - alpha_src.
 149:         break;
 150:       default:
 151:         throw new AWTError("Illegal AlphaComposite rule");
 152:     }
 153: 
 154:   }
 155: 
 156:   /**
 157:    * Releases all resources held by this composite object.
 158:    */
 159:   public void dispose()
 160:   {
 161:     // Nothing to do here yet.
 162:   }
 163: 
 164:   /**
 165:    * Performs compositing according to the rules specified in the
 166:    * AlphaComposite from the constructor.
 167:    */
 168:   public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
 169:   {
 170: 
 171:     // TODO: This implementation is very general and highly inefficient. There
 172:     // are two possible ways to optimize this:
 173:     // 1. Special cased implementations for common ColorModels and transfer
 174:     //    types.
 175:     // 2. Native implementation.
 176: 
 177:     int x0 = src.getMinX();
 178:     int y0 = src.getMinY();
 179:     int width = src.getWidth();
 180:     int height = src.getHeight();
 181:     int x1 = x0 + width;
 182:     int y1 = y0 + height;
 183: 
 184:     Object srcPixel = null;
 185:     Object dstPixel = null;
 186: 
 187:     // Prepare the array that holds the color and alpha components of the
 188:     // source pixels.
 189:     float[] srcComponents;
 190:     int srcComponentsLength = srcColorModel.getNumComponents();
 191:     if (! srcColorModel.hasAlpha())
 192:       srcComponentsLength += 1;
 193:     srcComponents = new float[srcComponentsLength];
 194: 
 195:     // Prepare the array that holds the color and alpha components of the
 196:     // destination pixels.
 197:     float[] dstComponents;
 198:     int dstComponentsLength = dstColorModel.getNumComponents();
 199:     if (! dstColorModel.hasAlpha())
 200:       dstComponentsLength += 1;
 201:     dstComponents = new float[dstComponentsLength];
 202: 
 203:     if (srcComponentsLength != dstComponentsLength)
 204:       throw new AWTError("The color models of the source and destination have"
 205:                          + "incompatible number of color components");
 206: 
 207:     int srcTransferType = srcColorModel.getTransferType();
 208:     int dstTransferType = dstColorModel.getTransferType();
 209: 
 210:     for (int y = y0; y < y1; y++)
 211:       {
 212:         for (int x = x0; x < x1; x++)
 213:           {
 214:             // Fetch source pixel.
 215:             srcPixel = src.getDataElements(x, y, (int[]) srcPixel);
 216:             // Fetch destination pixel.
 217:             dstPixel = dstIn.getDataElements(x, y, dstPixel);
 218:             // Get normalized components. This is the only type that is
 219:             // guaranteed to be supported by all ColorModels.
 220:             srcComponents =
 221:               srcColorModel.getNormalizedComponents(srcPixel, srcComponents, 0);
 222:             if (! srcColorModel.hasAlpha())
 223:               srcComponents[srcComponentsLength - 1] = 1.0F;
 224:             dstComponents =
 225:               dstColorModel.getNormalizedComponents(dstPixel, dstComponents, 0);
 226:             if (! dstColorModel.hasAlpha())
 227:               dstComponents[dstComponentsLength - 1] = 1.0F;
 228: 
 229:             // Prepare the input.
 230:             float compositeAlpha = composite.getAlpha();
 231:             srcComponents[srcComponentsLength - 1] *= compositeAlpha;
 232:             if (srcColorModel.isAlphaPremultiplied())
 233:               {
 234:                 for (int i = srcComponentsLength - 2; i >= 0; i--)
 235:                   srcComponents[i] *= compositeAlpha;
 236:               }
 237:             else
 238:               {
 239:                 for (int i = srcComponentsLength - 2; i >= 0; i--)
 240:                   srcComponents[i] *= srcComponents[srcComponentsLength - 1];
 241:               }
 242:             if (! dstColorModel.isAlphaPremultiplied())
 243:               {
 244:                 for (int i = dstComponentsLength - 2; i >= 0; i--)
 245:                   dstComponents[i] *= dstComponents[dstComponents.length - 1];
 246:               }
 247: 
 248:             // Determine the blending factors according to the rule in the
 249:             // AlphaComposite. For some rules the factors must be determined
 250:             // dynamically because they depend on the actual pixel value.
 251:             float srcAlpha = srcComponents[srcComponentsLength - 1];
 252:             float dstAlpha = dstComponents[dstComponentsLength - 1];
 253:             switch (composite.getRule())
 254:             {
 255:               case AlphaComposite.DST_ATOP:
 256:                 fs = 1.F - dstAlpha;
 257:                 fd = srcAlpha;
 258:                 break;
 259:               case AlphaComposite.DST_IN:
 260:                 fd = srcAlpha;
 261:                 break;
 262:               case AlphaComposite.DST_OUT:
 263:                 fd = 1.F - srcAlpha;
 264:                 break;
 265:               case AlphaComposite.DST_OVER:
 266:                 fs = 1.F - dstAlpha;
 267:                 break;
 268:               case AlphaComposite.SRC_ATOP:
 269:                 fs = srcAlpha;
 270:                 fd = 1.F - srcAlpha;
 271:                 break;
 272:               case AlphaComposite.SRC_IN:
 273:                 fs = dstAlpha;
 274:                 break;
 275:               case AlphaComposite.SRC_OUT:
 276:                 fs = 1.F - dstAlpha;
 277:                 break;
 278:               case AlphaComposite.SRC_OVER:
 279:                 fd= 1.F - srcAlpha;
 280:                 break;
 281:               case AlphaComposite.XOR:
 282:                 fs = 1.F - dstAlpha;
 283:                 fd= 1.F - srcAlpha;
 284:                 break;
 285:               default:
 286:                 // For the other cases the factors have already been determined
 287:                 // in the constructor.
 288:             }
 289: 
 290:             // Apply the blending equation to the pixels.
 291:             for (int i = 0; i < srcComponentsLength; i++)
 292:               {
 293:                 dstComponents[i] = srcComponents[i] * fs
 294:                                    + dstComponents[i] * fd;
 295:               }
 296: 
 297:             // Convert the result back when the destination is not
 298:             // alpha-premultiplied.
 299:             dstAlpha = dstComponents[dstComponentsLength - 1];
 300:             if (!dstColorModel.isAlphaPremultiplied() && dstAlpha != 0.F)
 301:               {
 302:                 for (int i = 0; i < dstComponentsLength - 1; i++)
 303:                   {
 304:                     dstComponents[i] = dstComponents[i] / dstAlpha;
 305:                   }
 306:               }
 307: 
 308:             // Store the result in the destination raster.
 309:             dstPixel = dstColorModel.getDataElements(dstComponents, 0,
 310:                                                      dstPixel);
 311:             dstOut.setDataElements(x, y, dstPixel);
 312:           } // End X loop.
 313:       } // End Y loop.
 314:   }
 315: 
 316: }