1 18 package org.apache.batik.ext.awt.image.renderable; 19 20 import java.awt.Point ; 21 import java.awt.Rectangle ; 22 import java.awt.RenderingHints ; 23 import java.awt.Shape ; 24 import java.awt.color.ColorSpace ; 25 import java.awt.geom.AffineTransform ; 26 import java.awt.geom.Rectangle2D ; 27 import java.awt.image.BufferedImage ; 28 import java.awt.image.BufferedImageOp ; 29 import java.awt.image.ColorModel ; 30 import java.awt.image.ConvolveOp ; 31 import java.awt.image.DataBuffer ; 32 import java.awt.image.DataBufferInt ; 33 import java.awt.image.DirectColorModel ; 34 import java.awt.image.Kernel ; 35 import java.awt.image.Raster ; 36 import java.awt.image.RenderedImage ; 37 import java.awt.image.SinglePixelPackedSampleModel ; 38 import java.awt.image.WritableRaster ; 39 import java.awt.image.renderable.RenderContext ; 40 41 import org.apache.batik.ext.awt.image.GraphicsUtil; 42 import org.apache.batik.ext.awt.image.PadMode; 43 import org.apache.batik.ext.awt.image.rendered.AffineRed; 44 import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed; 45 import org.apache.batik.ext.awt.image.rendered.CachableRed; 46 import org.apache.batik.ext.awt.image.rendered.PadRed; 47 48 58 public class ConvolveMatrixRable8Bit 59 extends AbstractColorInterpolationRable 60 implements ConvolveMatrixRable { 61 62 Kernel kernel; 63 Point target; 64 float bias; 65 boolean kernelHasNegValues; 66 PadMode edgeMode; 67 float [] kernelUnitLength = new float[2]; 68 69 boolean preserveAlpha = false; 70 71 public ConvolveMatrixRable8Bit(Filter source) { 72 super(source); 73 } 74 75 public Filter getSource() { 76 return (Filter)getSources().get(0); 77 } 78 79 public void setSource(Filter src) { 80 init(src); 81 } 82 83 84 87 public Kernel getKernel() { 88 return kernel; 89 } 90 91 95 public void setKernel(Kernel k) { 96 touch(); 97 this.kernel = k; 98 kernelHasNegValues = false; 99 float [] kv = k.getKernelData(null); 100 for (int i=0; i<kv.length; i++) 101 if (kv[i] < 0) { 102 kernelHasNegValues = true; 103 break; 104 } 105 } 106 107 public Point getTarget() { 108 return (Point )target.clone(); 109 } 110 111 public void setTarget(Point pt) { 112 touch(); 113 this.target = (Point )pt.clone(); 114 } 115 116 119 public double getBias() { 120 return bias; 121 } 122 123 126 public void setBias(double bias) { 127 touch(); 128 this.bias = (float)bias; 129 } 130 131 134 public PadMode getEdgeMode() { 135 return edgeMode; 136 } 137 138 141 public void setEdgeMode(PadMode edgeMode) { 142 touch(); 143 this.edgeMode = edgeMode; 144 } 145 146 149 public double [] getKernelUnitLength() { 150 if (kernelUnitLength == null) 151 return null; 152 153 double [] ret = new double[2]; 154 ret[0] = kernelUnitLength[0]; 155 ret[1] = kernelUnitLength[1]; 156 return ret; 157 } 158 159 163 public void setKernelUnitLength(double [] kernelUnitLength) { 164 touch(); 165 if (kernelUnitLength == null) { 166 this.kernelUnitLength = null; 167 return; 168 } 169 170 if (this.kernelUnitLength == null) 171 this.kernelUnitLength = new float[2]; 172 173 this.kernelUnitLength[0] = (float)kernelUnitLength[0]; 174 this.kernelUnitLength[1] = (float)kernelUnitLength[1]; 175 } 176 177 180 public boolean getPreserveAlpha() { 181 return preserveAlpha; 182 } 183 184 189 public void setPreserveAlpha(boolean preserveAlpha) { 190 touch(); 191 this.preserveAlpha = preserveAlpha; 192 } 193 194 195 public void fixAlpha(BufferedImage bi) { 196 if ((!bi.getColorModel().hasAlpha()) || 197 (!bi.isAlphaPremultiplied())) 198 return; 200 if (GraphicsUtil.is_INT_PACK_Data(bi.getSampleModel(), true)) 201 fixAlpha_INT_PACK(bi.getRaster()); 202 else 203 fixAlpha_FALLBACK(bi.getRaster()); 204 } 205 206 public void fixAlpha_INT_PACK(WritableRaster wr) { 207 SinglePixelPackedSampleModel sppsm; 208 sppsm = (SinglePixelPackedSampleModel )wr.getSampleModel(); 209 210 final int width = wr.getWidth(); 211 212 final int scanStride = sppsm.getScanlineStride(); 213 DataBufferInt db = (DataBufferInt )wr.getDataBuffer(); 214 final int base 215 = (db.getOffset() + 216 sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), 217 wr.getMinY()-wr.getSampleModelTranslateY())); 218 int pixel, a, v; 219 final int pixels[] = db.getBankData()[0]; 221 for (int y=0; y<wr.getHeight(); y++) { 222 int sp = base + y*scanStride; 223 final int end = sp + width; 224 while (sp < end) { 225 pixel = pixels[sp]; 226 a = pixel>>>24; 227 v = (pixel>>16)&0xFF; 228 if (a < v) a = v; 229 v = (pixel>> 8)&0xFF; 230 if (a < v) a = v; 231 v = (pixel )&0xFF; 232 if (a < v) a = v; 233 pixels[sp] = (pixel&0x00FFFFFF) | (a << 24); 234 sp++; 235 } 236 } 237 } 238 239 public void fixAlpha_FALLBACK(WritableRaster wr) { 240 int x0=wr.getMinX(); 241 int w =wr.getWidth(); 242 int y0=wr.getMinY(); 243 int y1=y0 + wr.getHeight()-1; 244 int bands = wr.getNumBands(); 245 int a, x, y, b, i; 246 int [] pixel = null; 247 for (y=y0; y<=y1; y++) { 248 pixel = wr.getPixels(x0, y, w, 1, pixel); 249 i=0; 250 for (x=0; x<w; x++) { 251 a=pixel[i]; 252 for (b=1; b<bands; b++) 253 if (pixel[i+b] > a) a = pixel[i+b]; 254 pixel[i+bands-1] = a; 255 i+=bands; 256 } 257 wr.setPixels(x0, y, w, 1, pixel); 258 } 259 } 260 261 public RenderedImage createRendering(RenderContext rc) { 262 RenderingHints rh = rc.getRenderingHints(); 264 if (rh == null) rh = new RenderingHints (null); 265 266 AffineTransform at = rc.getTransform(); 268 269 270 double sx = at.getScaleX(); 274 double sy = at.getScaleY(); 275 276 double shx = at.getShearX(); 277 double shy = at.getShearY(); 278 279 double tx = at.getTranslateX(); 280 double ty = at.getTranslateY(); 281 282 double scaleX = Math.sqrt(sx*sx + shy*shy); 287 double scaleY = Math.sqrt(sy*sy + shx*shx); 288 289 if (kernelUnitLength != null) { 292 if (kernelUnitLength[0] > 0.0) 293 scaleX = 1/kernelUnitLength[0]; 294 295 if (kernelUnitLength[1] > 0.0) 296 scaleY = 1/kernelUnitLength[1]; 297 } 298 299 Shape aoi = rc.getAreaOfInterest(); 300 if(aoi == null) 301 aoi = getBounds2D(); 302 303 Rectangle2D r = aoi.getBounds2D(); 304 305 int kw = kernel.getWidth(); 306 int kh = kernel.getHeight(); 307 int kx = target.x; 308 int ky = target.y; 309 310 { 312 double rx0 = r.getX() -(kx/scaleX); 313 double ry0 = r.getY() -(ky/scaleY); 314 double rx1 = rx0 + r.getWidth() + (kw-1)/scaleX; 315 double ry1 = ry0 + r.getHeight() + (kh-1)/scaleY; 316 r = new Rectangle2D.Double (Math.floor(rx0), 317 Math.floor(ry0), 318 Math.ceil (rx1-Math.floor(rx0)), 319 Math.ceil (ry1-Math.floor(ry0))); 320 } 321 AffineTransform srcAt 326 = AffineTransform.getScaleInstance(scaleX, scaleY); 327 328 333 AffineTransform resAt = new AffineTransform (sx/scaleX, shy/scaleX, 336 shx/scaleY, sy/scaleY, 337 tx, ty); 338 339 RenderedImage ri; 340 ri = getSource().createRendering(new RenderContext (srcAt, r, rh)); 341 if (ri == null) 342 return null; 343 344 348 CachableRed cr = convertSourceCS(ri); 349 350 Shape devShape = srcAt.createTransformedShape(aoi); 351 Rectangle2D devRect = devShape.getBounds2D(); 352 r = devRect; 353 r = new Rectangle2D.Double (Math.floor(r.getX()-kx), 354 Math.floor(r.getY()-ky), 355 Math.ceil (r.getX()+r.getWidth())- 356 Math.floor(r.getX())+(kw-1), 357 Math.ceil (r.getY()+r.getHeight())- 358 Math.floor(r.getY())+(kh-1)); 359 360 if (!r.getBounds().equals(cr.getBounds())) { 361 if (edgeMode == PadMode.WRAP) 362 throw new IllegalArgumentException 363 ("edgeMode=\"wrap\" is not supported by ConvolveMatrix."); 364 cr = new PadRed(cr, r.getBounds(), edgeMode, rh); 365 } 366 367 371 if (bias != 0.0) 372 throw new IllegalArgumentException 373 ("Only bias equal to zero is supported in ConvolveMatrix."); 374 375 BufferedImageOp op = new ConvolveOp (kernel, 376 ConvolveOp.EDGE_NO_OP, 377 rh); 378 379 ColorModel cm = cr.getColorModel(); 380 381 Raster rr = cr.getData(); 385 WritableRaster wr = GraphicsUtil.makeRasterWritable(rr, 0, 0); 386 387 int phaseShiftX = target.x - kernel.getXOrigin(); 390 int phaseShiftY = target.y - kernel.getYOrigin(); 391 int destX = (int)(r.getX() + phaseShiftX); 392 int destY = (int)(r.getY() + phaseShiftY); 393 394 BufferedImage destBI; 395 if (!preserveAlpha) { 396 cm = GraphicsUtil.coerceData(wr, cm, true); 399 400 BufferedImage srcBI; 401 srcBI = new BufferedImage (cm, wr, cm.isAlphaPremultiplied(), null); 402 403 destBI = op.filter(srcBI, null); 405 406 if (kernelHasNegValues) { 407 fixAlpha(destBI); 413 } 414 415 } else { 416 BufferedImage srcBI; 417 srcBI = new BufferedImage (cm, wr, cm.isAlphaPremultiplied(), null); 418 419 cm = new DirectColorModel (ColorSpace.getInstance 421 (ColorSpace.CS_LINEAR_RGB), 24, 422 0x00FF0000, 0x0000FF00, 423 0x000000FF, 0x0, false, 424 DataBuffer.TYPE_INT); 425 426 427 428 BufferedImage tmpSrcBI = new BufferedImage 430 (cm, cm.createCompatibleWritableRaster(wr.getWidth(), 431 wr.getHeight()), 432 cm.isAlphaPremultiplied(), null); 433 434 GraphicsUtil.copyData(srcBI, tmpSrcBI); 437 438 441 ColorModel dstCM = GraphicsUtil.Linear_sRGB_Unpre; 443 destBI = new BufferedImage 445 (dstCM, dstCM.createCompatibleWritableRaster(wr.getWidth(), 446 wr.getHeight()), 447 dstCM.isAlphaPremultiplied(), null); 448 449 452 WritableRaster dstWR = 454 Raster.createWritableRaster 455 (cm.createCompatibleSampleModel(wr.getWidth(), wr.getHeight()), 456 destBI.getRaster().getDataBuffer(), 457 new Point (0,0)); 458 459 BufferedImage tmpDstBI = new BufferedImage 461 (cm, dstWR, cm.isAlphaPremultiplied(), null); 462 463 tmpDstBI = op.filter(tmpSrcBI, tmpDstBI); 465 466 469 Rectangle srcRect = wr.getBounds(); 472 Rectangle dstRect = new Rectangle (srcRect.x-phaseShiftX, 473 srcRect.y-phaseShiftY, 474 srcRect.width, srcRect.height); 475 GraphicsUtil.copyBand(wr, srcRect, wr.getNumBands()-1, 476 destBI.getRaster(), dstRect, 477 destBI.getRaster().getNumBands()-1); 478 } 479 480 cr = new BufferedImageCachableRed(destBI, destX, destY); 482 483 490 cr = new PadRed(cr, devRect.getBounds(), PadMode.ZERO_PAD, rh); 492 493 if (!resAt.isIdentity()) 495 cr = new AffineRed(cr, resAt, null); 496 497 return cr; 499 } 500 501 } 502 | Popular Tags |