KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > rendered > MorphologyOp


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image.rendered;
19
20 import java.awt.Rectangle JavaDoc;
21 import java.awt.RenderingHints JavaDoc;
22 import java.awt.color.ColorSpace JavaDoc;
23 import java.awt.geom.Point2D JavaDoc;
24 import java.awt.geom.Rectangle2D JavaDoc;
25 import java.awt.image.BufferedImage JavaDoc;
26 import java.awt.image.BufferedImageOp JavaDoc;
27 import java.awt.image.ColorModel JavaDoc;
28 import java.awt.image.DataBuffer JavaDoc;
29 import java.awt.image.DataBufferInt JavaDoc;
30 import java.awt.image.DirectColorModel JavaDoc;
31 import java.awt.image.Raster JavaDoc;
32 import java.awt.image.RasterOp JavaDoc;
33 import java.awt.image.SampleModel JavaDoc;
34 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
35 import java.awt.image.WritableRaster JavaDoc;
36
37 import org.apache.batik.ext.awt.image.GraphicsUtil;
38
39 /**
40  * This class provides an implementation for the SVG
41  * feMorphology filter, as defined in Chapter 15, section 20
42  * of the SVG specification.
43  *
44  * @author <a HREF="mailto:sheng.pei@sun.com">Sheng Pei</a>
45  * @version $Id: MorphologyOp.java,v 1.6 2004/08/18 07:14:08 vhardy Exp $
46  */

47 public class MorphologyOp implements BufferedImageOp JavaDoc, RasterOp JavaDoc {
48     /**
49      * The radius of the operation on X axis
50      */

51     private int radiusX;
52     /**
53      * The radius of the operation on Y axis
54      */

55     private int radiusY;
56     /*
57      * Determine whether to do the dilation or erosion operation.
58      * Will do dilation when it's true and erosion when it's false.
59      */

60     private boolean doDilation;
61
62     /*
63      * rangeX is 2*radiusX+1, which is the width of the Kernel
64      */

65     private final int rangeX;
66
67     /*
68      * rangeY is 2*radiusY+1, which is the height of the Kernel
69      */

70     private final int rangeY;
71
72     /*
73      * sRGB ColorSpace instance used for compatibility checking
74      */

75     private final ColorSpace JavaDoc sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
76
77     /*
78      * Linear RGB ColorSpace instance used for compatibility checking
79      */

80     private final ColorSpace JavaDoc lRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
81
82     /**
83      * @param radiusX defines the radius of filter operation on X-axis. Should not be negative.
84      * A value of zero will disable the effect of the operation on X-axis, as described
85      * in the SVG specification.
86      * @param radiusY defines the radius of filter operation on Y-axis. Should not be negative.
87      * A value of zero will disable the effect of the operation on Y-axis, as described
88      * in the SVG specification.
89      * @param doDilation defines whether to do dilation or erosion operation. Will do dilation
90      * when the value is true, erosion when false.
91      */

92     public MorphologyOp (int radiusX, int radiusY, boolean doDilation){
93         if (radiusX<=0 || radiusY<=0){
94             throw new IllegalArgumentException JavaDoc(new String JavaDoc("The radius of X-axis or Y-axis should not be Zero or Negatives."));
95         }
96         else {
97             this.radiusX = radiusX;
98             this.radiusY = radiusY;
99             this.doDilation = doDilation;
100             rangeX = 2*radiusX + 1;
101             rangeY = 2*radiusY + 1;
102         }
103     }
104
105     public Rectangle2D JavaDoc getBounds2D(Raster JavaDoc src){
106         checkCompatible(src.getSampleModel());
107         return new Rectangle JavaDoc(src.getMinX(), src.getMinY(), src.getWidth(), src.getHeight());
108     }
109
110     public Rectangle2D JavaDoc getBounds2D(BufferedImage JavaDoc src){
111         return new Rectangle JavaDoc(0, 0, src.getWidth(), src.getHeight());
112     }
113
114     public Point2D JavaDoc getPoint2D(Point2D JavaDoc srcPt, Point2D JavaDoc destPt){
115         // This operation does not affect pixel location
116
if(destPt==null)
117             destPt = new Point2D.Float JavaDoc();
118         destPt.setLocation(srcPt.getX(), srcPt.getY());
119         return destPt;
120     }
121
122     private void checkCompatible(ColorModel JavaDoc colorModel,
123                                  SampleModel JavaDoc sampleModel){
124         ColorSpace JavaDoc cs = colorModel.getColorSpace();
125
126         // Check that model is sRGB or linear RGB
127
if((!cs .equals (sRGB)) && (!cs .equals( lRGB)))
128             throw new IllegalArgumentException JavaDoc("Expected CS_sRGB or CS_LINEAR_RGB color model");
129
130         // Check ColorModel is of type DirectColorModel
131
if(!(colorModel instanceof DirectColorModel JavaDoc))
132             throw new IllegalArgumentException JavaDoc("colorModel should be an instance of DirectColorModel");
133
134         // Check transfer type
135
if(sampleModel.getDataType() != DataBuffer.TYPE_INT)
136             throw new IllegalArgumentException JavaDoc("colorModel's transferType should be DataBuffer.TYPE_INT");
137
138         // Check red, green, blue and alpha mask
139
DirectColorModel JavaDoc dcm = (DirectColorModel JavaDoc)colorModel;
140         if(dcm.getRedMask() != 0x00ff0000)
141             throw new IllegalArgumentException JavaDoc("red mask in source should be 0x00ff0000");
142         if(dcm.getGreenMask() != 0x0000ff00)
143             throw new IllegalArgumentException JavaDoc("green mask in source should be 0x0000ff00");
144         if(dcm.getBlueMask() != 0x000000ff)
145             throw new IllegalArgumentException JavaDoc("blue mask in source should be 0x000000ff");
146         if(dcm.getAlphaMask() != 0xff000000)
147             throw new IllegalArgumentException JavaDoc("alpha mask in source should be 0xff000000");
148     }
149
150     private boolean isCompatible(ColorModel JavaDoc colorModel,
151                  SampleModel JavaDoc sampleModel){
152         ColorSpace JavaDoc cs = colorModel.getColorSpace();
153         // Check that model is sRGB or linear RGB
154
if((cs != ColorSpace.getInstance(ColorSpace.CS_sRGB))
155            &&
156            (cs != ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)))
157             return false;
158
159         // Check ColorModel is of type DirectColorModel
160
if(!(colorModel instanceof DirectColorModel JavaDoc))
161             return false;
162
163         // Check transfer type
164
if(sampleModel.getDataType() != DataBuffer.TYPE_INT)
165             return false;
166
167         // Check red, green, blue and alpha mask
168
DirectColorModel JavaDoc dcm = (DirectColorModel JavaDoc)colorModel;
169         if(dcm.getRedMask() != 0x00ff0000)
170             return false;
171         if(dcm.getGreenMask() != 0x0000ff00)
172             return false;
173         if(dcm.getBlueMask() != 0x000000ff)
174             return false;
175         if(dcm.getAlphaMask() != 0xff000000)
176             return false;
177         return true;
178     }
179
180     private void checkCompatible(SampleModel JavaDoc model){
181         // Check model is ok: should be SinglePixelPackedSampleModel
182
if(!(model instanceof SinglePixelPackedSampleModel JavaDoc))
183             throw new IllegalArgumentException JavaDoc
184                 ("MorphologyOp only works with Rasters " +
185                  "using SinglePixelPackedSampleModels");
186         // Check number of bands
187
int nBands = model.getNumBands();
188         if(nBands!=4)
189             throw new IllegalArgumentException JavaDoc
190                 ("MorphologyOp only words with Rasters having 4 bands");
191         // Check that integer packed.
192
if(model.getDataType()!=DataBuffer.TYPE_INT)
193             throw new IllegalArgumentException JavaDoc
194                 ("MorphologyOp only works with Rasters using DataBufferInt");
195
196         // Check bit masks
197
int bitOffsets[]=((SinglePixelPackedSampleModel JavaDoc)model).getBitOffsets();
198         for(int i=0; i<bitOffsets.length; i++){
199             if(bitOffsets[i]%8 != 0)
200                 throw new IllegalArgumentException JavaDoc
201                     ("MorphologyOp only works with Rasters using 8 bits " +
202                      "per band : " + i + " : " + bitOffsets[i]);
203         }
204     }
205
206     public RenderingHints JavaDoc getRenderingHints(){
207         return null;
208     }
209
210     public WritableRaster JavaDoc createCompatibleDestRaster(Raster JavaDoc src){
211         checkCompatible(src.getSampleModel());
212         // Src Raster is OK: create a similar Raster for destination.
213
return src.createCompatibleWritableRaster();
214     }
215
216     public BufferedImage JavaDoc createCompatibleDestImage(BufferedImage JavaDoc src,
217                                                    ColorModel JavaDoc destCM){
218         BufferedImage JavaDoc dest = null;
219         if(destCM==null)
220             destCM = src.getColorModel();
221
222         WritableRaster JavaDoc wr;
223         wr = destCM.createCompatibleWritableRaster(src.getWidth(),
224                                                    src.getHeight());
225         checkCompatible(destCM, wr.getSampleModel());
226
227         dest = new BufferedImage JavaDoc(destCM, wr,
228                                  destCM.isAlphaPremultiplied(), null);
229         return dest;
230     }
231
232     /*
233      * This method compares the two input variables according
234      * to the doDilation boolean variable.
235      */

236     static final boolean isBetter (final int v1, final int v2, final boolean doDilation) {
237         if (v1 > v2)
238             return doDilation;
239         if (v1 < v2)
240             return !doDilation;
241         return true;
242     }
243
244     /*
245      * This method deals with the condition that the Kernel is wider than
246      * the Image
247      */

248     private void specialProcessRow(Raster JavaDoc src, WritableRaster JavaDoc dest){
249         final int w = src.getWidth();
250         final int h = src.getHeight();
251
252         // Access the integer buffer for each image.
253
DataBufferInt JavaDoc srcDB = (DataBufferInt JavaDoc)src.getDataBuffer();
254         DataBufferInt JavaDoc dstDB = (DataBufferInt JavaDoc)dest.getDataBuffer();
255
256         // Offset defines where in the stack the real data begin
257
SinglePixelPackedSampleModel JavaDoc sppsm;
258         sppsm = (SinglePixelPackedSampleModel JavaDoc)src.getSampleModel();
259
260         final int srcOff = srcDB.getOffset() +
261             sppsm.getOffset(src.getMinX() - src.getSampleModelTranslateX(),
262                             src.getMinY() - src.getSampleModelTranslateY());
263
264
265         sppsm = (SinglePixelPackedSampleModel JavaDoc)dest.getSampleModel();
266         final int dstOff = dstDB.getOffset() +
267             sppsm.getOffset(dest.getMinX() - dest.getSampleModelTranslateX(),
268                             dest.getMinY() - dest.getSampleModelTranslateY());
269
270         // Stride is the distance between two consecutive column elements,
271
// in the one-dimention dataBuffer
272
final int srcScanStride = ((SinglePixelPackedSampleModel JavaDoc)src.getSampleModel()).getScanlineStride();
273         final int dstScanStride = ((SinglePixelPackedSampleModel JavaDoc)dest.getSampleModel()).getScanlineStride();
274
275         // Access the pixel value array
276
final int srcPixels[] = srcDB.getBankData()[0];
277         final int destPixels[] = dstDB.getBankData()[0];
278
279         // The pointer of src and dest indicating where the pixel values are
280
int sp, dp;
281
282         // Declaration for the circular buffer's implementation
283
// These are the circular buffers' head pointer and
284
// the index pointers
285

286         // bufferHead points to the leftmost element in the circular buffer
287
int bufferHead;
288
289         int maxIndexA;
290         int maxIndexR;
291         int maxIndexG;
292         int maxIndexB;
293
294         // Temp variables
295
int pel, currentPixel, lastPixel;
296         int a,r,g,b;
297         int a1,r1,g1,b1;
298
299         // If image width is less than or equal to the radiusX,
300
// all the pixels share the same max/min value
301
if (w<=radiusX){
302             for (int i=0; i<h; i++){
303                 // pointing to the first pixels of each row
304
sp = srcOff + i*srcScanStride;
305                 dp = dstOff + i*dstScanStride;
306                 pel = srcPixels[sp++];
307                 a = pel>>>24;
308                 r = pel&0xff0000;
309                 g = pel&0xff00;
310                 b = pel&0xff;
311
312                 for (int k=1; k<w; k++){
313                     currentPixel = srcPixels[sp++];
314                     a1 = currentPixel>>>24;
315                     r1 = currentPixel&0xff0000;
316                     g1 = currentPixel&0xff00;
317                     b1 = currentPixel&0xff;
318                     
319                     if (isBetter(a1, a, doDilation)){
320                         a = a1;
321                     }
322                     if (isBetter(r1, r, doDilation)){
323                         r = r1;
324                     }
325                     if (isBetter(g1, g, doDilation)){
326                         g = g1;
327                     }
328                     if (isBetter(b1, b, doDilation)){
329                         b = b1;
330                     }
331                 }
332                 // all the element share the same max/min value
333
for (int k=0; k<w; k++){
334                     destPixels[dp++] = (a << 24) | r | g | b;
335                 }
336             }
337         }
338
339         // When radiusX < w <= 2*radiusX
340
else {
341
342             // The width of the circular buffer is w
343
final int [] bufferA = new int [w];
344             final int [] bufferR = new int [w];
345             final int [] bufferG = new int [w];
346             final int [] bufferB = new int [w];
347
348             for (int i=0; i<h; i++){
349                 // initialization of pointers, indice
350
// at the head of each row
351
sp = srcOff + i*srcScanStride;
352                 dp = dstOff + i*dstScanStride;
353
354                 bufferHead = 0;
355                 maxIndexA = 0;
356                 maxIndexR = 0;
357                 maxIndexG = 0;
358                 maxIndexB = 0;
359
360                 pel = srcPixels[sp++];
361                 a = pel>>>24;
362                 r = pel&0xff0000;
363                 g = pel&0xff00;
364                 b = pel&0xff;
365                 bufferA[0] = a;
366                 bufferR[0] = r;
367                 bufferG[0] = g;
368                 bufferB[0] = b;
369
370                 for (int k=1; k<=radiusX; k++){
371                     currentPixel = srcPixels[sp++];
372                     a1 = currentPixel>>>24;
373                     r1 = currentPixel&0xff0000;
374                     g1 = currentPixel&0xff00;
375                     b1 = currentPixel&0xff;
376                     bufferA[k] = a1;
377                     bufferR[k] = r1;
378                     bufferG[k] = g1;
379                     bufferB[k] = b1;
380
381                     if (isBetter(a1, a, doDilation)){
382                         a = a1;
383                         maxIndexA = k;
384                     }
385                     if (isBetter(r1, r, doDilation)){
386                         r = r1;
387                         maxIndexR = k;
388                     }
389                     if (isBetter(g1, g, doDilation)){
390                         g = g1;
391                         maxIndexG = k;
392                     }
393                     if (isBetter(b1, b, doDilation)){
394                         b = b1;
395                         maxIndexB = k;
396                     }
397                 }
398                 destPixels[dp++] = (a << 24) | r | g | b;
399
400                 //
401
// 1 <= j <= w-radiusX-1 : The left margin of each row.
402
//
403
for (int j=1; j<=w-radiusX-1; j++){
404                     lastPixel = srcPixels[sp++];
405
406                     // here is the Alpha channel
407

408                     // we retrieve the previous max/min value
409
a = bufferA[maxIndexA];
410                     a1 = lastPixel>>>24;
411                     bufferA[j+radiusX] = a1;
412                     if (isBetter(a1, a, doDilation)){
413                         a = a1;
414                         maxIndexA = j+radiusX;
415                     }
416
417                     // now we deal with the Red channel
418

419                     r = bufferR[maxIndexR];
420                     r1 = lastPixel&0xff0000;
421                     bufferR[j+radiusX] = r1;
422                     if (isBetter(r1, r, doDilation)){
423                         r = r1;
424                         maxIndexR = j+radiusX;
425                     }
426
427                     // now we deal with the Green channel
428

429                     g = bufferG[maxIndexG];
430                     g1 = lastPixel&0xff00;
431                     bufferG[j+radiusX] = g1;
432                     if (isBetter(g1, g, doDilation)){
433                         g = g1;
434                         maxIndexG = j+radiusX;
435                     }
436
437                     // now we deal with the Blue channel
438

439                     b = bufferB[maxIndexB];
440                     b1 = lastPixel&0xff;
441                     bufferB[j+radiusX] = b1;
442                     if (isBetter(b1, b, doDilation)){
443                         b = b1;
444                         maxIndexB = j+radiusX;
445                     }
446                     // now we have gone through the four channels and
447
// updated the index array. then we'll pack the
448
// new max/min value according to each channel's
449
// max/min vlue
450

451                     destPixels[dp++] = (a << 24) | r | g | b;
452                 }
453                 // Now is the inner body of the row:
454
// all elements in this segment share the same max/min value
455
for (int j = w-radiusX; j<= radiusX; j++){
456                     destPixels[dp] = destPixels[dp-1];
457                     dp++;
458                 }
459                 // Now the circular buffer is full
460
// Now is the right margin of the row when radiusX < w <= 2*radiusX
461
for (int j = radiusX+1; j<w; j++){
462
463                     if (maxIndexA == bufferHead){
464                         a = bufferA[bufferHead+1];
465                         maxIndexA = bufferHead+1;
466                         for (int m= bufferHead+2; m< w; m++){
467                             a1 = bufferA[m];
468                             if (isBetter(a1, a, doDilation)){
469                                 a = a1;
470                                 maxIndexA = m;
471                             }
472                         }
473                     }
474                     else {
475                         a = bufferA[maxIndexA];
476                     }
477                     if (maxIndexR == bufferHead){
478                         r = bufferR[bufferHead+1];
479                         maxIndexR = bufferHead+1;
480                         for (int m= bufferHead+2; m< w; m++){
481                             r1 = bufferR[m];
482                             if (isBetter(r1, r, doDilation)){
483                                 r = r1;
484                                 maxIndexR = m;
485                             }
486                         }
487                     }
488                     else {
489                         r = bufferR[maxIndexR];
490                     }
491
492                     if (maxIndexG == bufferHead){
493                         g = bufferG[bufferHead+1];
494                         maxIndexG = bufferHead+1;
495                         for (int m= bufferHead+2; m< w; m++){
496                             g1 = bufferG[m];
497                             if (isBetter(g1, g, doDilation)){
498                                 g = g1;
499                                 maxIndexG = m;
500                             }
501                         }
502                     }
503                     // we can reuse the previous max/min value
504
else {
505                         g = bufferG[maxIndexG];
506                     }
507
508                     if (maxIndexB == bufferHead){
509                         b = bufferB[bufferHead+1];
510                         maxIndexB = bufferHead+1;
511                         for (int m= bufferHead+2; m< w; m++){
512                             b1 = bufferB[m];
513                             if (isBetter(b1, b, doDilation)){
514                                 b = b1;
515                                 maxIndexB = m;
516                             }
517                         }
518                     }
519                     // we can reuse the previous max/min value
520
else {
521                         b = bufferB[maxIndexB];
522                     }
523
524                     // discard the leftmost element
525
bufferHead++;
526
527                     destPixels[dp++] = (a << 24) | r | g | b;
528                 }
529                 // return to the first pixel of the next row
530
}
531         }// When radiusX < w <=2*radiusX
532
}
533
534     /*
535      * This method deals with the condition when the Kernel is
536      * higher than the image.
537      */

538     private void specialProcessColumn(Raster JavaDoc src, WritableRaster JavaDoc dest){
539
540         final int w = src.getWidth();
541         final int h = src.getHeight();
542
543         // Access the integer buffer for each image.
544
DataBufferInt JavaDoc dstDB = (DataBufferInt JavaDoc)dest.getDataBuffer();
545
546         // Offset defines where in the stack the real data begin
547
final int dstOff = dstDB.getOffset();
548
549         // Stride is the distance between two consecutive column elements,
550
// in the one-dimention dataBuffer
551
final int dstScanStride = ((SinglePixelPackedSampleModel JavaDoc)dest.getSampleModel()).getScanlineStride();
552
553         // Access the pixel value array
554
final int destPixels[] = dstDB.getBankData()[0];
555
556         // The pointer of src and dest indicating where the pixel values are
557
int dp, cp;
558
559         // Declaration for the circular buffer's implementation
560
// These are the circular buffers' head pointer and
561
// the index pointers
562

563         // bufferHead points to the leftmost element in the circular buffer
564
int bufferHead;
565
566         int maxIndexA;
567         int maxIndexR;
568         int maxIndexG;
569         int maxIndexB;
570
571         // Temp variables
572
int pel, currentPixel, lastPixel;
573         int a,r,g,b;
574         int a1,r1,g1,b1;
575
576         // Here all the pixels share the same
577
// max/min value
578
if (h<=radiusY){
579             for (int j=0; j<w; j++){
580                 dp = dstOff + j;
581                 cp = dstOff + j;
582                 pel = destPixels[cp];
583                 cp += dstScanStride;
584                 a = pel>>>24;
585                 r = pel&0xff0000;
586                 g = pel&0xff00;
587                 b = pel&0xff;
588
589                 for (int k=1; k<h; k++){
590                     currentPixel = destPixels[cp];
591                     cp += dstScanStride;
592                     a1 = currentPixel>>>24;
593                     r1 = currentPixel&0xff0000;
594                     g1 = currentPixel&0xff00;
595                     b1 = currentPixel&0xff;
596
597                     if (isBetter(a1, a, doDilation)){
598                         a = a1;
599                     }
600                     if (isBetter(r1, r, doDilation)){
601                         r = r1;
602                     }
603                     if (isBetter(g1, g, doDilation)){
604                         g = g1;
605                     }
606                     if (isBetter(b1, b, doDilation)){
607                         b = b1;
608                     }
609                 }
610                 for (int k=0; k<h; k++){
611                     destPixels[dp] = (a << 24) | r | g | b;
612                     dp += dstScanStride;
613                 }
614                 // return to the first pixel of the next column
615
}
616         }
617
618         // When radiusY < h <= 2*radiusY
619
else {
620
621             // The height of the circular buffer is h
622
final int [] bufferA = new int [h];
623             final int [] bufferR = new int [h];
624             final int [] bufferG = new int [h];
625             final int [] bufferB = new int [h];
626
627             for (int j=0; j<w; j++){
628                 // initialization of pointers, indice
629
// at the head of each column
630
dp = dstOff + j;
631                 cp = dstOff + j;
632
633                 bufferHead = 0;
634                 maxIndexA = 0;
635                 maxIndexR = 0;
636                 maxIndexG = 0;
637                 maxIndexB = 0;
638
639                 pel = destPixels[cp];
640                 cp += dstScanStride;
641                 a = pel>>>24;
642                 r = pel&0xff0000;
643                 g = pel&0xff00;
644                 b = pel&0xff;
645                 bufferA[0] = a;
646                 bufferR[0] = r;
647                 bufferG[0] = g;
648                 bufferB[0] = b;
649
650                 for (int k=1; k<=radiusY; k++){
651                     currentPixel = destPixels[cp];
652                     cp += dstScanStride;
653                     a1 = currentPixel>>>24;
654                     r1 = currentPixel&0xff0000;
655                     g1 = currentPixel&0xff00;
656                     b1 = currentPixel&0xff;
657                     bufferA[k] = a1;
658                     bufferR[k] = r1;
659                     bufferG[k] = g1;
660                     bufferB[k] = b1;
661
662                     if (isBetter(a1, a, doDilation)){
663                         a = a1;
664                         maxIndexA = k;
665                     }
666                     if (isBetter(r1, r, doDilation)){
667                         r = r1;
668                         maxIndexR = k;
669                     }
670                     if (isBetter(g1, g, doDilation)){
671                         g = g1;
672                         maxIndexG = k;
673                     }
674                     if (isBetter(b1, b, doDilation)){
675                         b = b1;
676                         maxIndexB = k;
677                     }
678                 }
679                 // fill the first pixel of each column
680
destPixels[dp] = (a << 24) | r | g | b;
681                 dp += dstScanStride;
682
683                 //
684
// 1 <= i <= h-1-radiusY : The upper margin of each column.
685
//
686
for (int i=1; i<=h-radiusY-1; i++){
687                     lastPixel = destPixels[cp];
688                     cp += dstScanStride;
689
690                     // here is the Alpha channel
691

692                     a = bufferA[maxIndexA];
693                     a1 = lastPixel>>>24;
694                     bufferA[i+radiusY] = a1;
695                     if (isBetter(a1, a, doDilation)){
696                         a = a1;
697                         maxIndexA = i+radiusY;
698                     }
699
700                     // now we deal with the Red channel
701

702                     r = bufferR[maxIndexR];
703                     r1 = lastPixel&0xff0000;
704                     bufferR[i+radiusY] = r1;
705                     if (isBetter(r1, r, doDilation)){
706                         r = r1;
707                         maxIndexR = i+radiusY;
708                     }
709
710                     // now we deal with the Green channel
711

712                     g = bufferG[maxIndexG];
713                     g1 = lastPixel&0xff00;
714                     bufferG[i+radiusY] = g1;
715                     if (isBetter(g1, g, doDilation)){
716                         g = g1;
717                         maxIndexG = i+radiusY;
718                     }
719
720                     // now we deal with the Blue channel
721

722                     b = bufferB[maxIndexB];
723                     b1 = lastPixel&0xff;
724                     bufferB[i+radiusY] = b1;
725                     if (isBetter(b1, b, doDilation)){
726                         b = b1;
727                         maxIndexB = i+radiusY;
728                     }
729                     // now we have gone through the four channels and
730
// updated the index array. then we'll pack the
731
// new max/min value according to each channel's
732
// max/min vlue
733

734                     destPixels[dp] = (a << 24) | r | g | b;
735                     dp += dstScanStride;
736                 }
737                 // Now is the inner body of the column
738
// when radiusY < h <= 2*radiusY
739
for (int i = h-radiusY; i<= radiusY; i++){
740                     destPixels[dp] = destPixels[dp-dstScanStride];
741                     dp += dstScanStride;
742                 }
743                 // The circular buffer is full now
744

745                 for (int i = radiusY+1; i<h; i++){
746
747                     if (maxIndexA == bufferHead){
748                         a = bufferA[bufferHead+1];
749                         maxIndexA = bufferHead+1;
750                         for (int m= bufferHead+2; m< h; m++){
751                             a1 = bufferA[m];
752                             if (isBetter(a1, a, doDilation)){
753                                 a = a1;
754                                 maxIndexA = m;
755                             }
756                         }
757                     }
758                     else {
759                         a = bufferA[maxIndexA];
760                     }
761                     if (maxIndexR == bufferHead){
762                         r = bufferR[bufferHead+1];
763                         maxIndexR = bufferHead+1;
764                         for (int m= bufferHead+2; m< h; m++){
765                             r1 = bufferR[m];
766                             if (isBetter(r1, r, doDilation)){
767                                 r = r1;
768                                 maxIndexR = m;
769                             }
770                         }
771                     }
772                     else {
773                         r = bufferR[maxIndexR];
774                     }
775
776                     if (maxIndexG == bufferHead){
777                         g = bufferG[bufferHead+1];
778                         maxIndexG = bufferHead+1;
779                         for (int m= bufferHead+2; m< h; m++){
780                             g1 = bufferG[m];
781                             if (isBetter(g1, g, doDilation)){
782                                 g = g1;
783                                 maxIndexG = m;
784                             }
785                         }
786                     }
787                     // we can reuse the previous max/min value
788
else {
789                         g = bufferG[maxIndexG];
790                     }
791
792                     if (maxIndexB == bufferHead){
793                         b = bufferB[bufferHead+1];
794                         maxIndexB = bufferHead+1;
795                         for (int m= bufferHead+2; m< h; m++){
796                             b1 = bufferB[m];
797                             if (isBetter(b1, b, doDilation)){
798                                 b = b1;
799                                 maxIndexB = m;
800                             }
801                         }
802                     }
803                     // we can reuse the previous max/min value
804
else {
805                         b = bufferB[maxIndexB];
806                     }
807
808                     // discard the leftmost element
809
bufferHead++;
810
811                     destPixels[dp] = (a << 24) | r | g | b;
812                     dp += dstScanStride;
813                 }
814                 // return to the first pixel of the next column
815
}
816         } // when radiusY < h <= 2*radiusY
817
}
818
819     /**
820      * Filters src and writes result into dest. If dest if null, then
821      * a Raster is created. If dest and src refer to the same object,
822      * then the source is modified.
823      * <p>
824      * The filtering kernel(the operation range for each pixel) is a
825      * rectangle of width 2*radiusX+1 and height radiusY+1
826      * <p>
827      * @param src the Raster to be filtered
828      * @param dest stores the filtered image. If null, a destination will
829      * be created. src and dest can refer to the same Raster, in
830      * which situation the src will be modified.
831      */

832     public WritableRaster JavaDoc filter(Raster JavaDoc src, WritableRaster JavaDoc dest){
833
834         //
835
//This method sorts the pixel values in the kernel window in two steps:
836
// 1. sort by row and store the result into an intermediate matrix
837
// 2. sort the intermediate matrix by column and output the max/min value
838
// into the destination matrix element
839

840         //check destation
841
if(dest!=null) checkCompatible(dest.getSampleModel());
842         else {
843             if(src==null)
844                 throw new IllegalArgumentException JavaDoc("src should not be null when dest is null");
845             else dest = createCompatibleDestRaster(src);
846         }
847
848         final int w = src.getWidth();
849         final int h = src.getHeight();
850
851         // Access the integer buffer for each image.
852
DataBufferInt JavaDoc srcDB = (DataBufferInt JavaDoc)src.getDataBuffer();
853         DataBufferInt JavaDoc dstDB = (DataBufferInt JavaDoc)dest.getDataBuffer();
854
855         // Offset defines where in the stack the real data begin
856
final int srcOff = srcDB.getOffset();
857         final int dstOff = dstDB.getOffset();
858
859         // Stride is the distance between two consecutive column elements,
860
// in the one-dimention dataBuffer
861
final int srcScanStride = ((SinglePixelPackedSampleModel JavaDoc)src.getSampleModel()).getScanlineStride();
862         final int dstScanStride = ((SinglePixelPackedSampleModel JavaDoc)dest.getSampleModel()).getScanlineStride();
863
864         // Access the pixel value array
865
final int srcPixels[] = srcDB.getBankData()[0];
866         final int destPixels[] = dstDB.getBankData()[0];
867
868         // The pointer of src and dest indicating where the pixel values are
869
int sp, dp, cp;
870
871         // Declaration for the circular buffer's implementation
872
// These are the circular buffers' head pointer and
873
// the index pointers
874

875         // bufferHead points to the leftmost element in the circular buffer
876
int bufferHead;
877
878         int maxIndexA;
879         int maxIndexR;
880         int maxIndexG;
881         int maxIndexB;
882
883         // Temp variables
884
int pel, currentPixel, lastPixel;
885         int a,r,g,b;
886         int a1,r1,g1,b1;
887
888         // In both round, we are using an optimization approach
889
// to reduce excessive computation to sort values around
890
// the current pixel. The idea is as follows:
891
// ----------------
892
// |*|V|V|$|N|V|V|&|
893
// ----------------
894
// For example, suppose we've finished pixel"$" and come
895
// to "N", the radius is 3. Then we must have got the max/min
896
// value and index array for "$". If the max/min is at
897
// "*"(using the index array to judge this),
898
// we need to recompute a max/min and the index array
899
// for "N"; if the max/min is not at "*", we can
900
// reuse the current max/min: we simply compare it with
901
// "&", and update the max/min and the index array.
902

903         //
904
// The first round: sort by row
905
//
906
if (w<=2*radiusX){
907             specialProcessRow(src, dest);
908         }
909
910         // when the size is large enough, we can
911
// use standard optimization method
912
else {
913
914             final int [] bufferA = new int [rangeX];
915             final int [] bufferR = new int [rangeX];
916             final int [] bufferG = new int [rangeX];
917             final int [] bufferB = new int [rangeX];
918
919             for (int i=0; i<h; i++){
920                 // initialization of pointers, indice
921
// at the head of each row
922
sp = srcOff + i*srcScanStride;
923                 dp = dstOff + i*dstScanStride;
924                 bufferHead = 0;
925                 maxIndexA = 0;
926                 maxIndexR = 0;
927                 maxIndexG = 0;
928                 maxIndexB = 0;
929
930                 //
931
// j=0 : Initialization, compute the max/min and
932
// index array for the use of other pixels.
933
//
934
pel = srcPixels[sp++];
935                 a = pel>>>24;
936                 r = pel&0xff0000;
937                 g = pel&0xff00;
938                 b = pel&0xff;
939                 bufferA[0] = a;
940                 bufferR[0] = r;
941                 bufferG[0] = g;
942                 bufferB[0] = b;
943
944                 for (int k=1; k<=radiusX; k++){
945                     currentPixel = srcPixels[sp++];
946                     a1 = currentPixel>>>24;
947                     r1 = currentPixel&0xff0000;
948                     g1 = currentPixel&0xff00;
949                     b1 = currentPixel&0xff;
950                     bufferA[k] = a1;
951                     bufferR[k] = r1;
952                     bufferG[k] = g1;
953                     bufferB[k] = b1;
954
955                     if (isBetter(a1, a, doDilation)){
956                         a = a1;
957                         maxIndexA = k;
958                     }
959                     if (isBetter(r1, r, doDilation)){
960                         r = r1;
961                         maxIndexR = k;
962                     }
963                     if (isBetter(g1, g, doDilation)){
964                         g = g1;
965                         maxIndexG = k;
966                     }
967                     if (isBetter(b1, b, doDilation)){
968                         b = b1;
969                         maxIndexB = k;
970                     }
971                 }
972                 destPixels[dp++] = (a << 24) | r | g | b;
973
974                 //
975
// 1 <= j <= radiusX : The left margin of each row.
976
//
977
for (int j=1; j<=radiusX; j++){
978                     lastPixel = srcPixels[sp++];
979
980                     // here is the Alpha channel
981

982                     // we retrieve the previous max/min value
983
a = bufferA[maxIndexA];
984                     a1 = lastPixel>>>24;
985                     bufferA[j+radiusX] = a1;
986                     if (isBetter(a1, a, doDilation)){
987                         a = a1;
988                         maxIndexA = j+radiusX;
989                     }
990
991                     // now we deal with the Red channel
992

993                     r = bufferR[maxIndexR];
994                     r1 = lastPixel&0xff0000;
995                     bufferR[j+radiusX] = r1;
996                     if (isBetter(r1, r, doDilation)){
997                         r = r1;
998                         maxIndexR = j+radiusX;
999                     }
1000
1001                    // now we deal with the Green channel
1002

1003                    g = bufferG[maxIndexG];
1004                    g1 = lastPixel&0xff00;
1005                    bufferG[j+radiusX] = g1;
1006                    if (isBetter(g1, g, doDilation)){
1007                        g = g1;
1008                        maxIndexG = j+radiusX;
1009                    }
1010
1011                    // now we deal with the Blue channel
1012

1013                    b = bufferB[maxIndexB];
1014                    b1 = lastPixel&0xff;
1015                    bufferB[j+radiusX] = b1;
1016                    if (isBetter(b1, b, doDilation)){
1017                        b = b1;
1018                        maxIndexB = j+radiusX;
1019                    }
1020                    // now we have gone through the four channels and
1021
// updated the index array. then we'll pack the
1022
// new max/min value according to each channel's
1023
// max/min vlue
1024

1025                    destPixels[dp++] = (a << 24) | r | g | b;
1026                }
1027
1028                //
1029
// radiusX <= j <= w-1-radiusX : Inner body of the row, between
1030
// left and right margins
1031
//
1032
for (int j=radiusX+1; j<=w-1-radiusX; j++){
1033                    lastPixel = srcPixels[sp++];
1034                    a1 = lastPixel>>>24;
1035                    r1 = lastPixel&0xff0000;
1036                    g1 = lastPixel&0xff00;
1037                    b1 = lastPixel&0xff;
1038                    bufferA[bufferHead] = a1;
1039                    bufferR[bufferHead] = r1;
1040                    bufferG[bufferHead] = g1;
1041                    bufferB[bufferHead] = b1;
1042
1043                    // Alpha channel:
1044
// we need to recompute a local max/min
1045
// and update the max/min index
1046
if (maxIndexA == bufferHead){
1047                        a = bufferA[0];
1048                        maxIndexA = 0;
1049                        for (int m= 1; m< rangeX; m++){
1050                            a1 = bufferA[m];
1051                            if (isBetter(a1, a, doDilation)){
1052                                a = a1;
1053                                maxIndexA = m;
1054                            }
1055                        }
1056                    }
1057                    // we can reuse the previous max/min value
1058
else {
1059                        a = bufferA[maxIndexA];
1060                        if (isBetter(a1, a, doDilation)){
1061                            a = a1;
1062                            maxIndexA = bufferHead;
1063                        }
1064                    }
1065
1066                    // Red channel
1067
// we need to recompute a local max/min
1068
// and update the index array
1069

1070                    if (maxIndexR == bufferHead){
1071                        r = bufferR[0];
1072                        maxIndexR = 0;
1073                        for (int m= 1; m< rangeX; m++){
1074                            r1 = bufferR[m];
1075                            if (isBetter(r1, r, doDilation)){
1076                                r = r1;
1077                                maxIndexR = m;
1078                            }
1079                        }
1080                    }
1081                    // we can reuse the previous max/min value
1082
else {
1083                        r = bufferR[maxIndexR];
1084                        if (isBetter(r1, r, doDilation)){
1085                            r = r1;
1086                            maxIndexR = bufferHead;
1087                        }
1088                    }
1089
1090                    // Green channel
1091
// we need to recompute a local max/min
1092
// and update the index array
1093

1094                    if (maxIndexG == bufferHead){
1095                        g = bufferG[0];
1096                        maxIndexG = 0;
1097                        for (int m= 1; m< rangeX; m++){
1098                            g1 = bufferG[m];
1099                            if (isBetter(g1, g, doDilation)){
1100                                g = g1;
1101                                maxIndexG = m;
1102                            }
1103                        }
1104                    }
1105                    // we can reuse the previous max/min value
1106
else {
1107                        g = bufferG[maxIndexG];
1108                        if (isBetter(g1, g, doDilation)){
1109                            g = g1;
1110                            maxIndexG = bufferHead;
1111                        }
1112                    }
1113
1114                    // Blue channel
1115
// we need to recompute a local max/min
1116
// and update the index array
1117

1118                    if (maxIndexB == bufferHead){
1119                        b = bufferB[0];
1120                        maxIndexB = 0;
1121                        for (int m= 1; m< rangeX; m++){
1122                            b1 = bufferB[m];
1123                            if (isBetter(b1, b, doDilation)){
1124                                b = b1;
1125                                maxIndexB = m;
1126                            }
1127                        }
1128                    }
1129                    // we can reuse the previous max/min value
1130
else {
1131                        b = bufferB[maxIndexB];
1132                        if (isBetter(b1, b, doDilation)){
1133                            b = b1;
1134                            maxIndexB = bufferHead;
1135                        }
1136                    }
1137                    destPixels[dp++] = (a << 24) | r | g | b;
1138                    bufferHead = (bufferHead+1)%rangeX;
1139                }
1140
1141                //
1142
// w-radiusX <= j < w : The right margin of the row
1143
//
1144

1145                // Head will be updated to indicate the current head
1146
// of the remaining buffer
1147
int head;
1148                // Tail is where the last element is
1149
final int tail = (bufferHead == 0)?rangeX-1:bufferHead -1;
1150                int count = rangeX-1;
1151
1152                for (int j=w-radiusX; j<w; j++){
1153                    head = (bufferHead+1)%rangeX;
1154                    // Dealing with Alpha Channel:
1155
if (maxIndexA == bufferHead){
1156                        a = bufferA[tail];
1157                        int hd = head;
1158                        for(int m=1; m<count; m++) {
1159                            a1 = bufferA[hd];
1160                            if (isBetter(a1, a, doDilation)){
1161                                a = a1;
1162                                maxIndexA = hd;
1163                            }
1164                            hd = (hd+1)%rangeX;
1165                        }
1166                    }
1167                    // Dealing with Red Channel:
1168
if (maxIndexR == bufferHead){
1169                        r = bufferR[tail];
1170                        int hd = head;
1171                        for(int m=1; m<count; m++) {
1172                            r1 = bufferR[hd];
1173                            if (isBetter(r1, r, doDilation)){
1174                                r = r1;
1175                                maxIndexR = hd;
1176                            }
1177                            hd = (hd+1)%rangeX;
1178                        }
1179                    }
1180                    // Dealing with Green Channel:
1181
if (maxIndexG == bufferHead){
1182                        g = bufferG[tail];
1183                        int hd = head;
1184                        for(int m=1; m<count; m++) {
1185                            g1 = bufferG[hd];
1186                            if (isBetter(g1, g, doDilation)){
1187                                g = g1;
1188                                maxIndexG = hd;
1189                            }
1190                            hd = (hd+1)%rangeX;
1191                        }
1192                    }
1193                    // Dealing with Blue Channel:
1194
if (maxIndexB == bufferHead){
1195                        b = bufferB[tail];
1196                        int hd = head;
1197                        for(int m=1; m<count; m++) {
1198                            b1 = bufferB[hd];
1199                            if (isBetter(b1, b, doDilation)){
1200                                b = b1;
1201                                maxIndexB = hd;
1202                            }
1203                            hd = (hd+1)%rangeX;
1204                        }
1205                    }
1206                    destPixels[dp++] = (a << 24) | r | g | b;
1207                    bufferHead = (bufferHead+1)%rangeX;
1208                    // we throw another element
1209
count--;
1210                }// end of the right margin of this row
1211

1212                // return to the beginning of the next row
1213
}
1214        }// end of the first round!
1215

1216        //
1217
// Second round: sort by column
1218
// the difference from the first round is that
1219
// now we are accessing the intermediate matrix
1220
//
1221

1222        // When the image size is smaller than the
1223
// Kernel size
1224
if (h<=2*radiusY){
1225            specialProcessColumn(src, dest);
1226        }
1227
1228        // when the size is large enough, we can
1229
// use standard optimization method
1230
else {
1231            final int [] bufferA = new int [rangeY];
1232            final int [] bufferR = new int [rangeY];
1233            final int [] bufferG = new int [rangeY];
1234            final int [] bufferB = new int [rangeY];
1235
1236            for (int j=0; j<w; j++){
1237                // initialization of pointers, indice
1238
// at the head of each column
1239
dp = dstOff + j;
1240                cp = dstOff + j;
1241                bufferHead = 0;
1242                maxIndexA = 0;
1243                maxIndexR = 0;
1244                maxIndexG = 0;
1245                maxIndexB = 0;
1246
1247                // i=0 : The first pixel
1248
pel = destPixels[cp];
1249                cp += dstScanStride;
1250                a = pel>>>24;
1251                r = pel&0xff0000;
1252                g = pel&0xff00;
1253                b = pel&0xff;
1254                bufferA[0] = a;
1255                bufferR[0] = r;
1256                bufferG[0] = g;
1257                bufferB[0] = b;
1258
1259                for (int k=1; k<=radiusY; k++){
1260                    currentPixel = destPixels[cp];
1261                    cp += dstScanStride;
1262                    a1 = currentPixel>>>24;
1263                    r1 = currentPixel&0xff0000;
1264                    g1 = currentPixel&0xff00;
1265                    b1 = currentPixel&0xff;
1266                    bufferA[k] = a1;
1267                    bufferR[k] = r1;
1268                    bufferG[k] = g1;
1269                    bufferB[k] = b1;
1270
1271                    if (isBetter(a1, a, doDilation)){
1272                        a = a1;
1273                        maxIndexA = k;
1274                    }
1275                    if (isBetter(r1, r, doDilation)){
1276                        r = r1;
1277                        maxIndexR = k;
1278                    }
1279                    if (isBetter(g1, g, doDilation)){
1280                        g = g1;
1281                        maxIndexG = k;
1282                    }
1283                    if (isBetter(b1, b, doDilation)){
1284                        b = b1;
1285                        maxIndexB = k;
1286                    }
1287                }
1288                destPixels[dp] = (a << 24) | r | g | b;
1289                // go to the next element in the column.
1290
dp += dstScanStride;
1291
1292                // 1 <= i <= radiusY : The upper margin of each row
1293
for (int i=1; i<=radiusY; i++){
1294                    int maxI = i+radiusY;
1295                    // we can reuse the previous max/min value
1296
lastPixel = destPixels[cp];
1297                    cp += dstScanStride;
1298
1299                    // here is the Alpha channel
1300
a = bufferA[maxIndexA];
1301                    a1 = lastPixel>>>24;
1302                    bufferA[maxI] = a1;
1303                    if (isBetter(a1, a, doDilation)){
1304                        a = a1;
1305                        maxIndexA = maxI;
1306                    }
1307
1308                    // now we deal with the Red channel
1309
r = bufferR[maxIndexR];
1310                    r1 = lastPixel&0xff0000;
1311                    bufferR[maxI] = r1;
1312                    if (isBetter(r1, r, doDilation)){
1313                        r = r1;
1314                        maxIndexR = maxI;
1315                    }
1316
1317                    // now we deal with the Green channel
1318
g = bufferG[maxIndexG];
1319                    g1 = lastPixel&0xff00;
1320                    bufferG[maxI] = g1;
1321                    if (isBetter(g1, g, doDilation)){
1322                        g = g1;
1323                        maxIndexG = maxI;
1324                    }
1325
1326                    // now we deal with the Blue channel
1327
b = bufferB[maxIndexB];
1328                    b1 = lastPixel&0xff;
1329                    bufferB[maxI] = b1;
1330                    if (isBetter(b1, b, doDilation)){
1331                        b = b1;
1332                        maxIndexB = maxI;
1333                    }
1334                    destPixels[dp] = (a << 24) | r | g | b;
1335                    dp += dstScanStride;
1336                }
1337
1338                //
1339
// radiusY +1 <= i <= h-1-radiusY:
1340
// inner body of the column between upper and lower margins
1341
//
1342

1343                for (int i=radiusY+1; i<=h-1-radiusY; i++){
1344
1345                    lastPixel = destPixels[cp];
1346                    cp += dstScanStride;
1347                    a1 = lastPixel>>>24;
1348                    r1 = lastPixel&0xff0000;
1349                    g1 = lastPixel&0xff00;
1350                    b1 = lastPixel&0xff;
1351                    bufferA[bufferHead] = a1;
1352                    bufferR[bufferHead] = r1;
1353                    bufferG[bufferHead] = g1;
1354                    bufferB[bufferHead] = b1;
1355
1356                    // here we check if the previous max/min value can be
1357
// reused safely and, if possible, reuse the previous
1358
// maximum value
1359

1360                    // Alpha channel:
1361

1362                    // Recompute the local max/min
1363
if (maxIndexA == bufferHead){
1364                        a = bufferA[0];
1365                        maxIndexA = 0;
1366                        for (int m= 1; m<= 2*radiusY; m++){
1367                            a1 = bufferA[m];
1368                            if (isBetter(a1, a, doDilation)){
1369                                a = a1;
1370                                maxIndexA = m;
1371                            }
1372                        }
1373                    }
1374                    // we can reuse the previous max/min value
1375
else {
1376                        a = bufferA[maxIndexA];
1377                        if (isBetter(a1, a, doDilation)){
1378                            a = a1;
1379                            maxIndexA = bufferHead;
1380                        }
1381                    }
1382
1383                    // Red channel:
1384

1385                    if (maxIndexR == bufferHead){
1386                        r = bufferR[0];
1387                        maxIndexR = 0;
1388                        for (int m= 1; m<= 2*radiusY; m++){
1389                            r1 = bufferR[m];
1390                            if (isBetter(r1, r, doDilation)){
1391                                r = r1;
1392                                maxIndexR = m;
1393                            }
1394                        }
1395                    }
1396                    // we can reuse the previous max/min value
1397
else {
1398                        r = bufferR[maxIndexR];
1399                        if (isBetter(r1, r, doDilation)){
1400                            r = r1;
1401                            maxIndexR = bufferHead;
1402                        }
1403                    }
1404
1405                    // Green channel
1406
if (maxIndexG == bufferHead){
1407                        g = bufferG[0];
1408                        maxIndexG = 0;
1409                        for (int m= 1; m<= 2*radiusY; m++){
1410                            g1 = bufferG[m];
1411                            if (isBetter(g1, g, doDilation)){
1412                                g = g1;
1413                                maxIndexG = m;
1414                            }
1415                        }
1416                    }
1417                    // we can reuse the previous max/min value
1418
else {
1419                        g = bufferG[maxIndexG];
1420                        if (isBetter(g1, g, doDilation)){
1421                            g = g1;
1422                            maxIndexG = bufferHead;
1423                        }
1424                    }
1425
1426                    // Blue channel:
1427
if (maxIndexB == bufferHead){
1428                        b = bufferB[0];
1429                        maxIndexB = 0;
1430                        for (int m= 1; m<= 2*radiusY; m++){
1431                            b1 = bufferB[m];
1432                            if (isBetter(b1, b, doDilation)){
1433                                b = b1;
1434                                maxIndexB = m;
1435                            }
1436                        }
1437                    }
1438                    // we can reuse the previous max/min value
1439
else {
1440                        b = bufferB[maxIndexB];
1441                        if (isBetter(b1, b, doDilation)){
1442                            b = b1;
1443                            maxIndexB = bufferHead;
1444                        }
1445                    }
1446                    destPixels[dp] = (a << 24) | r | g | b;
1447                    dp += dstScanStride;
1448                    bufferHead = (bufferHead+1)%rangeY;
1449                }
1450
1451                //
1452
// h-radiusY <= i <= h-1 : The lower margin of the column
1453
//
1454

1455                // head will be updated to indicate the current head
1456
// of the remaining buffer:
1457
int head;
1458                // tail is where the last element in the buffer is
1459
final int tail = (bufferHead == 0)?2*radiusY:bufferHead -1;
1460                int count = rangeY-1;
1461
1462                for (int i= h-radiusY; i<h-1; i++){
1463                    head = (bufferHead +1)%rangeY;
1464
1465                    if (maxIndexA == bufferHead){
1466                        a = bufferA[tail];
1467                        int hd = head;
1468                        for (int m=1; m<count; m++){
1469                            a1 = bufferA[hd];
1470                            if (isBetter(a1, a, doDilation)){
1471                                a = a1;
1472                                maxIndexA = hd;
1473                            }
1474                            hd = (hd+1)%rangeY;
1475                        }
1476                    }
1477                    if (maxIndexR == bufferHead){
1478                        r = bufferR[tail];
1479                        int hd = head;
1480                        for (int m=1; m<count; m++){
1481                            r1 = bufferR[hd];
1482                            if (isBetter(r1, r, doDilation)){
1483                                r = r1;
1484                                maxIndexR = hd;
1485                            }
1486                            hd = (hd+1)%rangeY;
1487                        }
1488                    }
1489                    if (maxIndexG == bufferHead){
1490                        g = bufferG[tail];
1491                        int hd = head;
1492                        for (int m=1; m<count; m++){
1493                            g1 = bufferG[hd];
1494                            if (isBetter(g1, g, doDilation)){
1495                                g = g1;
1496                                maxIndexG = hd;
1497                            }
1498                            hd = (hd+1)%rangeY;
1499                        }
1500                    }
1501                    if (maxIndexB == bufferHead){
1502                        b = bufferB[tail];
1503                        int hd = head;
1504                        for (int m=1; m<count; m++){
1505                            b1 = bufferB[hd];
1506                            if (isBetter(b1, b, doDilation)){
1507                                b = b1;
1508                                maxIndexB = hd;
1509                            }
1510                            hd = (hd+1)%rangeY;
1511                        }
1512                    }
1513                    destPixels[dp] = (a << 24) | r | g | b;
1514                    dp += dstScanStride;
1515                    bufferHead = (bufferHead+1)%rangeY;
1516                    // we throw out this useless element
1517
count--;
1518                }
1519                // return to the beginning of the next column
1520
}
1521        }// end of the second round!
1522

1523        return dest;
1524    }// end of the filter() method for Raster
1525

1526      /**
1527       * This implementation of filter does the morphology operation
1528       * on a premultiplied alpha image. This tends to muddy the
1529       * colors. so something that is supposed to be a mostly
1530       * transparent bright red may well become a muddy opaque red.
1531       * Where as I think it should become a bright opaque red. Which
1532       * is the result you would get if you were using unpremult data.
1533       */

1534    public BufferedImage JavaDoc filter(BufferedImage JavaDoc src, BufferedImage JavaDoc dest){
1535        if (src == null)
1536            throw new NullPointerException JavaDoc("Source image should not be null");
1537
1538        BufferedImage JavaDoc origSrc = src;
1539        BufferedImage JavaDoc finalDest = dest;
1540
1541        if (!isCompatible(src.getColorModel(), src.getSampleModel())) {
1542            src = new BufferedImage JavaDoc(src.getWidth(), src.getHeight(),
1543                                    BufferedImage.TYPE_INT_ARGB_PRE);
1544            GraphicsUtil.copyData(origSrc, src);
1545        }
1546        else if (!src.isAlphaPremultiplied()) {
1547            // Get a Premultipled CM.
1548
ColorModel JavaDoc srcCM, srcCMPre;
1549            srcCM = src.getColorModel();
1550            srcCMPre = GraphicsUtil.coerceColorModel(srcCM, true);
1551
1552            src = new BufferedImage JavaDoc(srcCMPre, src.getRaster(),
1553                                    true, null);
1554            
1555            GraphicsUtil.copyData(origSrc, src);
1556        }
1557
1558
1559        if (dest == null) {
1560            dest = createCompatibleDestImage(src, null);
1561            finalDest = dest;
1562        } else if (!isCompatible(dest.getColorModel(),
1563                                 dest.getSampleModel())) {
1564            dest = createCompatibleDestImage(src, null);
1565        } else if (!dest.isAlphaPremultiplied()) {
1566            // Get a Premultipled CM.
1567
ColorModel JavaDoc dstCM, dstCMPre;
1568            dstCM = dest.getColorModel();
1569            dstCMPre = GraphicsUtil.coerceColorModel(dstCM, true);
1570
1571            dest = new BufferedImage JavaDoc(dstCMPre, finalDest.getRaster(),
1572                                     true, null);
1573        }
1574
1575        filter(src.getRaster(), dest.getRaster());
1576
1577        // Check to see if we need to 'fix' our source (divide out alpha).
1578
if ((src.getRaster() == origSrc.getRaster()) &&
1579            (src.isAlphaPremultiplied() != origSrc.isAlphaPremultiplied())) {
1580            // Copy our source back the way it was...
1581
GraphicsUtil.copyData(src, origSrc);
1582        }
1583
1584        // Check to see if we need to store our result...
1585
if ((dest.getRaster() != finalDest.getRaster()) ||
1586            (dest.isAlphaPremultiplied() != finalDest.isAlphaPremultiplied())){
1587            // Coerce our source back the way it was requested...
1588
GraphicsUtil.copyData(dest, finalDest);
1589        }
1590
1591        return finalDest;
1592    }
1593      /*
1594       * This commented out implementation of filter does the
1595       * morphology operation on unpremultiplied alpha image data.
1596       * This tends to leave colors bright.
1597       */

1598      /*
1599    public BufferedImage filter(BufferedImage src, BufferedImage dest){
1600        if (src == null && dest == null)
1601            throw new NullPointerException("Source image should not be null");
1602
1603        BufferedImage origSrc = src;
1604        BufferedImage finalDest = dest;
1605
1606        if (!isCompatible(src.getColorModel(), src.getSampleModel())) {
1607            src = new BufferedImage(src.getWidth(), src.getHeight(),
1608                                    BufferedImage.TYPE_INT_ARGB);
1609            GraphicsUtil.copyData(origSrc, src);
1610        }
1611        else if (src.isAlphaPremultiplied()) {
1612            ColorModel srcCM, srcCMUnpre;
1613            srcCM = src.getColorModel();
1614            srcCMUnpre = GraphicsUtil.coerceColorModel(srcCM, false);
1615            src = new BufferedImage(srcCMUnpre, src.getRaster(),
1616                                    false, null);
1617            
1618            GraphicsUtil.copyData(origSrc, src);
1619        }
1620
1621
1622        if (dest == null) {
1623            dest = new BufferedImage(src.getWidth(), src.getHeight(),
1624                                          BufferedImage.TYPE_INT_ARGB);
1625            finalDest = dest;
1626        } else if (!isCompatible(dest.getColorModel(),
1627                                 dest.getSampleModel())) {
1628            dest = new BufferedImage(src.getWidth(), src.getHeight(),
1629                                     BufferedImage.TYPE_INT_ARGB);
1630        } else if (dest.isAlphaPremultiplied()) {
1631            ColorModel dstCM, dstCMUnpre;
1632            dstCM = dest.getColorModel();
1633            dstCMUnpre = GraphicsUtil.coerceColorModel(dstCM, false);
1634            dest = new BufferedImage(dstCMUnpre, finalDest.getRaster(),
1635                                     false, null);
1636        }
1637
1638        // We now have two compatible images. We can safely filter the rasters
1639        filter(src.getRaster(), dest.getRaster());
1640
1641        // Check to see if we need to 'fix' our source (divide out alpha).
1642        if ((src.getRaster() == origSrc.getRaster()) &&
1643            (src.isAlphaPremultiplied() != origSrc.isAlphaPremultiplied())) {
1644            GraphicsUtil.copyData(src, origSrc);
1645        }
1646
1647        // Check to see if we need to store our result...
1648        if ((dest.getRaster() != finalDest.getRaster()) ||
1649            (dest.isAlphaPremultiplied() != finalDest.isAlphaPremultiplied())){
1650            // Coerce our source back the way it was...
1651            System.out.println("Dest: " + dest.isAlphaPremultiplied() +
1652                               " finalDest: " +
1653                               finalDest.isAlphaPremultiplied());
1654            
1655            GraphicsUtil.copyData(dest, finalDest);
1656        }
1657        return finalDest;
1658    }
1659      */

1660}
1661
1662
1663
1664
1665
Popular Tags