public WritableRaster filter()

in batik-awt-util/src/main/java/org/apache/batik/ext/awt/image/rendered/MorphologyOp.java [833:1525]


    public WritableRaster filter(Raster src, WritableRaster dest){

        //
        //This method sorts the pixel values in the kernel window in two steps:
        // 1. sort by row and store the result into an intermediate matrix
        // 2. sort the intermediate matrix by column and output the max/min value
        //    into the destination matrix element

        //check destation
        if(dest!=null) checkCompatible(dest.getSampleModel());
        else {
            if(src==null)
                throw new IllegalArgumentException("src should not be null when dest is null");
            else dest = createCompatibleDestRaster(src);
        }

        final int w = src.getWidth();
        final int h = src.getHeight();

        // Access the integer buffer for each image.
        DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
        DataBufferInt dstDB = (DataBufferInt)dest.getDataBuffer();

        // Offset defines where in the stack the real data begin
        final int srcOff = srcDB.getOffset();
        final int dstOff = dstDB.getOffset();

        // Stride is the distance between two consecutive column elements,
        // in the one-dimention dataBuffer
        final int srcScanStride = ((SinglePixelPackedSampleModel)src.getSampleModel()).getScanlineStride();
        final int dstScanStride = ((SinglePixelPackedSampleModel)dest.getSampleModel()).getScanlineStride();

        // Access the pixel value array
        final int[] srcPixels = srcDB.getBankData()[0];
        final int[] destPixels = dstDB.getBankData()[0];

        // The pointer of src and dest indicating where the pixel values are
        int sp, dp, cp;

        // Declaration for the circular buffer's implementation
        // These are the circular buffers' head pointer and
        // the index pointers

        // bufferHead points to the leftmost element in the circular buffer
        int bufferHead;

        int maxIndexA;
        int maxIndexR;
        int maxIndexG;
        int maxIndexB;

        // Temp variables
        int pel, currentPixel, lastPixel;
        int a,r,g,b;
        int a1,r1,g1,b1;

        // In both round, we are using an optimization approach
        // to reduce excessive computation to sort values around
        // the current pixel. The idea is as follows:
        //           ----------------
        //           |*|V|V|$|N|V|V|&|
        //           ----------------
        // For example, suppose we've finished pixel"$" and come
        // to "N", the radius is 3. Then we must have got the max/min
        // value and index array for "$". If the max/min is at
        // "*"(using the index array to judge this),
        // we need to recompute a max/min and the index array
        // for "N"; if the max/min is not at "*", we can
        // reuse the current max/min: we simply compare it with
        // "&", and update the max/min and the index array.

        //
        // The first round: sort by row
        //
        if (w<=2*radiusX){
            specialProcessRow(src, dest);
        }

        // when the size is large enough, we can
        // use standard optimization method
        else {

            final int [] bufferA = new int [rangeX];
            final int [] bufferR = new int [rangeX];
            final int [] bufferG = new int [rangeX];
            final int [] bufferB = new int [rangeX];

            for (int i=0; i<h; i++){
                // initialization of pointers, indice
                // at the head of each row
                sp = srcOff + i*srcScanStride;
                dp = dstOff + i*dstScanStride;
                bufferHead = 0;
                maxIndexA = 0;
                maxIndexR = 0;
                maxIndexG = 0;
                maxIndexB = 0;

                //
                // j=0 : Initialization, compute the max/min and
                //       index array for the use of other pixels.
                //
                pel = srcPixels[sp++];
                a = pel>>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;
                bufferA[0] = a;
                bufferR[0] = r;
                bufferG[0] = g;
                bufferB[0] = b;

                for (int k=1; k<=radiusX; k++){
                    currentPixel = srcPixels[sp++];
                    a1 = currentPixel>>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;
                    bufferA[k] = a1;
                    bufferR[k] = r1;
                    bufferG[k] = g1;
                    bufferB[k] = b1;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = k;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = k;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = k;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = k;
                    }
                }
                destPixels[dp++] = (a << 24) | r | g | b;

                //
                // 1 <= j <= radiusX : The left margin of each row.
                //
                for (int j=1; j<=radiusX; j++){
                    lastPixel = srcPixels[sp++];

                    // here is the Alpha channel

                    // we retrieve the previous max/min value
                    a = bufferA[maxIndexA];
                    a1 = lastPixel>>>24;
                    bufferA[j+radiusX] = a1;
                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = j+radiusX;
                    }

                    // now we deal with the Red channel

                    r = bufferR[maxIndexR];
                    r1 = lastPixel&0xff0000;
                    bufferR[j+radiusX] = r1;
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = j+radiusX;
                    }

                    // now we deal with the Green channel

                    g = bufferG[maxIndexG];
                    g1 = lastPixel&0xff00;
                    bufferG[j+radiusX] = g1;
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = j+radiusX;
                    }

                    // now we deal with the Blue channel

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

                    destPixels[dp++] = (a << 24) | r | g | b;
                }

                //
                // radiusX <= j <= w-1-radiusX : Inner body of the row, between
                //                               left and right margins
                //
                for (int j=radiusX+1; j<=w-1-radiusX; j++){
                    lastPixel = srcPixels[sp++];
                    a1 = lastPixel>>>24;
                    r1 = lastPixel&0xff0000;
                    g1 = lastPixel&0xff00;
                    b1 = lastPixel&0xff;
                    bufferA[bufferHead] = a1;
                    bufferR[bufferHead] = r1;
                    bufferG[bufferHead] = g1;
                    bufferB[bufferHead] = b1;

                    // Alpha channel:
                    // we need to recompute a local max/min
                    // and update the max/min index
                    if (maxIndexA == bufferHead){
                        a = bufferA[0];
                        maxIndexA = 0;
                        for (int m= 1; m< rangeX; m++){
                            a1 = bufferA[m];
                            if (isBetter(a1, a, doDilation)){
                                a = a1;
                                maxIndexA = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        a = bufferA[maxIndexA];
                        if (isBetter(a1, a, doDilation)){
                            a = a1;
                            maxIndexA = bufferHead;
                        }
                    }

                    // Red channel
                    // we need to recompute a local max/min
                    // and update the index array

                    if (maxIndexR == bufferHead){
                        r = bufferR[0];
                        maxIndexR = 0;
                        for (int m= 1; m< rangeX; m++){
                            r1 = bufferR[m];
                            if (isBetter(r1, r, doDilation)){
                                r = r1;
                                maxIndexR = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        r = bufferR[maxIndexR];
                        if (isBetter(r1, r, doDilation)){
                            r = r1;
                            maxIndexR = bufferHead;
                        }
                    }

                    // Green channel
                    // we need to recompute a local max/min
                    // and update the index array

                    if (maxIndexG == bufferHead){
                        g = bufferG[0];
                        maxIndexG = 0;
                        for (int m= 1; m< rangeX; m++){
                            g1 = bufferG[m];
                            if (isBetter(g1, g, doDilation)){
                                g = g1;
                                maxIndexG = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        g = bufferG[maxIndexG];
                        if (isBetter(g1, g, doDilation)){
                            g = g1;
                            maxIndexG = bufferHead;
                        }
                    }

                    // Blue channel
                    // we need to recompute a local max/min
                    // and update the index array

                    if (maxIndexB == bufferHead){
                        b = bufferB[0];
                        maxIndexB = 0;
                        for (int m= 1; m< rangeX; m++){
                            b1 = bufferB[m];
                            if (isBetter(b1, b, doDilation)){
                                b = b1;
                                maxIndexB = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        b = bufferB[maxIndexB];
                        if (isBetter(b1, b, doDilation)){
                            b = b1;
                            maxIndexB = bufferHead;
                        }
                    }
                    destPixels[dp++] = (a << 24) | r | g | b;
                    bufferHead = (bufferHead+1)%rangeX;
                }

                //
                // w-radiusX <= j < w : The right margin of the row
                //

                // Head will be updated to indicate the current head
                // of the remaining buffer
                int head;
                // Tail is where the last element is
                final int tail = (bufferHead == 0)?rangeX-1:bufferHead -1;
                int count = rangeX-1;

                for (int j=w-radiusX; j<w; j++){
                    head = (bufferHead+1)%rangeX;
                    // Dealing with Alpha Channel:
                    if (maxIndexA == bufferHead){
                        a = bufferA[tail];
                        int hd = head;
                        for(int m=1; m<count; m++) {
                            a1 = bufferA[hd];
                            if (isBetter(a1, a, doDilation)){
                                a = a1;
                                maxIndexA = hd;
                            }
                            hd = (hd+1)%rangeX;
                        }
                    }
                    // Dealing with Red Channel:
                    if (maxIndexR == bufferHead){
                        r = bufferR[tail];
                        int hd = head;
                        for(int m=1; m<count; m++) {
                            r1 = bufferR[hd];
                            if (isBetter(r1, r, doDilation)){
                                r = r1;
                                maxIndexR = hd;
                            }
                            hd = (hd+1)%rangeX;
                        }
                    }
                    // Dealing with Green Channel:
                    if (maxIndexG == bufferHead){
                        g = bufferG[tail];
                        int hd = head;
                        for(int m=1; m<count; m++) {
                            g1 = bufferG[hd];
                            if (isBetter(g1, g, doDilation)){
                                g = g1;
                                maxIndexG = hd;
                            }
                            hd = (hd+1)%rangeX;
                        }
                    }
                    // Dealing with Blue Channel:
                    if (maxIndexB == bufferHead){
                        b = bufferB[tail];
                        int hd = head;
                        for(int m=1; m<count; m++) {
                            b1 = bufferB[hd];
                            if (isBetter(b1, b, doDilation)){
                                b = b1;
                                maxIndexB = hd;
                            }
                            hd = (hd+1)%rangeX;
                        }
                    }
                    destPixels[dp++] = (a << 24) | r | g | b;
                    bufferHead = (bufferHead+1)%rangeX;
                    // we throw another element
                    count--;
                }// end of the right margin of this row

                // return to the beginning of the next row
            }
        }// end of the first round!

        //
        // Second round: sort by column
        // the difference from the first round is that
        // now we are accessing the intermediate matrix
        //

        // When the image size is smaller than the
        // Kernel size
        if (h<=2*radiusY){
            specialProcessColumn(src, dest);
        }

        // when the size is large enough, we can
        // use standard optimization method
        else {
            final int [] bufferA = new int [rangeY];
            final int [] bufferR = new int [rangeY];
            final int [] bufferG = new int [rangeY];
            final int [] bufferB = new int [rangeY];

            for (int j=0; j<w; j++){
                // initialization of pointers, indice
                // at the head of each column
                dp = dstOff + j;
                cp = dstOff + j;
                bufferHead = 0;
                maxIndexA = 0;
                maxIndexR = 0;
                maxIndexG = 0;
                maxIndexB = 0;

                // i=0 : The first pixel
                pel = destPixels[cp];
                cp += dstScanStride;
                a = pel>>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;
                bufferA[0] = a;
                bufferR[0] = r;
                bufferG[0] = g;
                bufferB[0] = b;

                for (int k=1; k<=radiusY; k++){
                    currentPixel = destPixels[cp];
                    cp += dstScanStride;
                    a1 = currentPixel>>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;
                    bufferA[k] = a1;
                    bufferR[k] = r1;
                    bufferG[k] = g1;
                    bufferB[k] = b1;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = k;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = k;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = k;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = k;
                    }
                }
                destPixels[dp] = (a << 24) | r | g | b;
                // go to the next element in the column.
                dp += dstScanStride;

                // 1 <= i <= radiusY : The upper margin of each row
                for (int i=1; i<=radiusY; i++){
                    int maxI = i+radiusY;
                    // we can reuse the previous max/min value
                    lastPixel = destPixels[cp];
                    cp += dstScanStride;

                    // here is the Alpha channel
                    a = bufferA[maxIndexA];
                    a1 = lastPixel>>>24;
                    bufferA[maxI] = a1;
                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = maxI;
                    }

                    // now we deal with the Red channel
                    r = bufferR[maxIndexR];
                    r1 = lastPixel&0xff0000;
                    bufferR[maxI] = r1;
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = maxI;
                    }

                    // now we deal with the Green channel
                    g = bufferG[maxIndexG];
                    g1 = lastPixel&0xff00;
                    bufferG[maxI] = g1;
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = maxI;
                    }

                    // now we deal with the Blue channel
                    b = bufferB[maxIndexB];
                    b1 = lastPixel&0xff;
                    bufferB[maxI] = b1;
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = maxI;
                    }
                    destPixels[dp] = (a << 24) | r | g | b;
                    dp += dstScanStride;
                }

                //
                // radiusY +1 <= i <= h-1-radiusY:
                //    inner body of the column between upper and lower margins
                //

                for (int i=radiusY+1; i<=h-1-radiusY; i++){

                    lastPixel = destPixels[cp];
                    cp += dstScanStride;
                    a1 = lastPixel>>>24;
                    r1 = lastPixel&0xff0000;
                    g1 = lastPixel&0xff00;
                    b1 = lastPixel&0xff;
                    bufferA[bufferHead] = a1;
                    bufferR[bufferHead] = r1;
                    bufferG[bufferHead] = g1;
                    bufferB[bufferHead] = b1;

                    // here we check if the previous max/min value can be
                    // reused safely and, if possible, reuse the previous
                    // maximum value

                    // Alpha channel:

                    // Recompute the local max/min
                    if (maxIndexA == bufferHead){
                        a = bufferA[0];
                        maxIndexA = 0;
                        for (int m= 1; m<= 2*radiusY; m++){
                            a1 = bufferA[m];
                            if (isBetter(a1, a, doDilation)){
                                a = a1;
                                maxIndexA = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        a = bufferA[maxIndexA];
                        if (isBetter(a1, a, doDilation)){
                            a = a1;
                            maxIndexA = bufferHead;
                        }
                    }

                    // Red channel:

                    if (maxIndexR == bufferHead){
                        r = bufferR[0];
                        maxIndexR = 0;
                        for (int m= 1; m<= 2*radiusY; m++){
                            r1 = bufferR[m];
                            if (isBetter(r1, r, doDilation)){
                                r = r1;
                                maxIndexR = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        r = bufferR[maxIndexR];
                        if (isBetter(r1, r, doDilation)){
                            r = r1;
                            maxIndexR = bufferHead;
                        }
                    }

                    // Green channel
                    if (maxIndexG == bufferHead){
                        g = bufferG[0];
                        maxIndexG = 0;
                        for (int m= 1; m<= 2*radiusY; m++){
                            g1 = bufferG[m];
                            if (isBetter(g1, g, doDilation)){
                                g = g1;
                                maxIndexG = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        g = bufferG[maxIndexG];
                        if (isBetter(g1, g, doDilation)){
                            g = g1;
                            maxIndexG = bufferHead;
                        }
                    }

                    // Blue channel:
                    if (maxIndexB == bufferHead){
                        b = bufferB[0];
                        maxIndexB = 0;
                        for (int m= 1; m<= 2*radiusY; m++){
                            b1 = bufferB[m];
                            if (isBetter(b1, b, doDilation)){
                                b = b1;
                                maxIndexB = m;
                            }
                        }
                    }
                    // we can reuse the previous max/min value
                    else {
                        b = bufferB[maxIndexB];
                        if (isBetter(b1, b, doDilation)){
                            b = b1;
                            maxIndexB = bufferHead;
                        }
                    }
                    destPixels[dp] = (a << 24) | r | g | b;
                    dp += dstScanStride;
                    bufferHead = (bufferHead+1)%rangeY;
                }

                //
                // h-radiusY <= i <= h-1 : The lower margin of the column
                //

                // head will be updated to indicate the current head
                // of the remaining buffer:
                int head;
                // tail is where the last element in the buffer is
                final int tail = (bufferHead == 0)?2*radiusY:bufferHead -1;
                int count = rangeY-1;

                for (int i= h-radiusY; i<h-1; i++){
                    head = (bufferHead +1)%rangeY;

                    if (maxIndexA == bufferHead){
                        a = bufferA[tail];
                        int hd = head;
                        for (int m=1; m<count; m++){
                            a1 = bufferA[hd];
                            if (isBetter(a1, a, doDilation)){
                                a = a1;
                                maxIndexA = hd;
                            }
                            hd = (hd+1)%rangeY;
                        }
                    }
                    if (maxIndexR == bufferHead){
                        r = bufferR[tail];
                        int hd = head;
                        for (int m=1; m<count; m++){
                            r1 = bufferR[hd];
                            if (isBetter(r1, r, doDilation)){
                                r = r1;
                                maxIndexR = hd;
                            }
                            hd = (hd+1)%rangeY;
                        }
                    }
                    if (maxIndexG == bufferHead){
                        g = bufferG[tail];
                        int hd = head;
                        for (int m=1; m<count; m++){
                            g1 = bufferG[hd];
                            if (isBetter(g1, g, doDilation)){
                                g = g1;
                                maxIndexG = hd;
                            }
                            hd = (hd+1)%rangeY;
                        }
                    }
                    if (maxIndexB == bufferHead){
                        b = bufferB[tail];
                        int hd = head;
                        for (int m=1; m<count; m++){
                            b1 = bufferB[hd];
                            if (isBetter(b1, b, doDilation)){
                                b = b1;
                                maxIndexB = hd;
                            }
                            hd = (hd+1)%rangeY;
                        }
                    }
                    destPixels[dp] = (a << 24) | r | g | b;
                    dp += dstScanStride;
                    bufferHead = (bufferHead+1)%rangeY;
                    // we throw out this useless element
                    count--;
                }
                // return to the beginning of the next column
            }
        }// end of the second round!

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