// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © Andrew Kirillov, 2007-2008
// andrew.kirillov at gmail.com
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Lesser General Public
//    License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

package Catalano.Imaging.Filters;

import Catalano.Imaging.FastBitmap;
import Catalano.Imaging.IApplyInPlace;

/**
 * Horizontal run length smoothing algorithm.
 * 
 * The class implements horizontal run length smoothing algorithm, which
 * is described in: K.Y. Wong, R.G. Casey and F.M. Wahl, "Document analysis system,"
 * IBM J. Res. Devel., Vol. 26, NO. 6,111). 647-656, 1982.
 * 
 * Unlike the original description of this algorithm, this implementation must be applied
 * to inverted binary images containing document, i.e. white text on black background. So this
 * implementation fills horizontal black gaps between white pixels.
 * 
 * @author Diego Catalano
 */
public class HorizontalRunLengthSmoothing implements IApplyInPlace{
    
    private int maxGapSize = 10;
    private boolean processGapsWithImageBorders = false;

    /**
     * Get Maximum gap size to fill (in pixels).
     * 
     * The property specifies maximum horizontal gap between white pixels to fill.
     * If number of black pixels between some white pixels is bigger than this value, then those
     * black pixels are left as is; otherwise the gap is filled with white pixels.
     * 
     * @return Gap size.
     */
    public int getMaxGapSize() {
        return maxGapSize;
    }

    /**
     * Set Maximum gap size to fill (in pixels).
     * 
     * The property specifies maximum horizontal gap between white pixels to fill.
     * If number of black pixels between some white pixels is bigger than this value, then those
     * black pixels are left as is; otherwise the gap is filled with white pixels.
     * 
     * @param maxGapSize Gap size.
     */
    public void setMaxGapSize(int maxGapSize) {
        this.maxGapSize = Math.max( 1, Math.min( 1000, maxGapSize ));
    }

    /**
     * Verify Process gaps between objects and image borders or not.
     * 
     * The property sets if gaps between image borders and objects must be treated as
     * gaps between objects and also filled.
     * 
     * @return True if process
     */
    public boolean isProcessGapsWithImageBorders() {
        return processGapsWithImageBorders;
    }

    /**
     * Set Process gaps between objects and image borders or not.
     * 
     * The property sets if gaps between image borders and objects must be treated as
     * gaps between objects and also filled.
     * 
     * @param processGapsWithImageBorders True of false.
     */
    public void setProcessGapsWithImageBorders(boolean processGapsWithImageBorders) {
        this.processGapsWithImageBorders = processGapsWithImageBorders;
    }
    
    /**
     * Initialize a new instance of the HorizontalRunLengthSmoothing class.
     */
    public HorizontalRunLengthSmoothing() {}

    /**
     * Initialize a new instance of the HorizontalRunLengthSmoothing class.
     * @param maxGapSize Maximum gap size to fill.
     */
    public HorizontalRunLengthSmoothing(int maxGapSize) {
        setMaxGapSize(maxGapSize);
    }
    
    /**
     * Initialize a new instance of the HorizontalRunLengthSmoothing class.
     * @param maxGapSize Maximum gap size to fill.
     * @param processGapsWithImageBorders Process gaps between objects and image borders or not.
     */
    public HorizontalRunLengthSmoothing(int maxGapSize, boolean processGapsWithImageBorders) {
        setMaxGapSize(maxGapSize);
        setProcessGapsWithImageBorders(processGapsWithImageBorders);
    }

    @Override
    public void applyInPlace(FastBitmap fastBitmap) {
        
        if (fastBitmap.isGrayscale()){
            
            int width = fastBitmap.getWidth();
            int height = fastBitmap.getHeight();
            
            for (int i = 0; i < height; i++) {
                
                int position = 0;
                int lineStart = position;
                int lineEndPtr = width;
                
                // fill gaps between white pixels
                while(position < lineEndPtr){
                    
                    int gapStart = position;
                    
                    // look for non black pixel
                    while ( ( position < lineEndPtr ) && ( fastBitmap.getGray(i, position) == 0 ) ){
                        position++;
                    }
                    
                    // fill the gap between white areas
                    if ( position - gapStart <= maxGapSize ){
                        if ((processGapsWithImageBorders) || ((gapStart != lineStart) && (position != lineEndPtr))){
                            while ( gapStart < position ){
                                fastBitmap.setGray(i, gapStart, 255);
                                gapStart++;
                            }
                        }
                    }
                    
                    // skip all non black pixels
                    while ( ( position < lineEndPtr ) && ( fastBitmap.getGray(i, position) != 0 ) ){
                        position++;
                    }
                }
            }
        }
        else{
            throw new IllegalArgumentException("HorizontalRunLengthSmoothing only works in grayscale images.");
        }
    }
}
 

Ads help maintain this website.