package iiuf.jai; import java.awt.Color; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.MultiPixelPackedSampleModel; import java.awt.image.DataBufferByte; import java.awt.Rectangle; import java.util.Map; import javax.media.jai.BorderExtender; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import javax.media.jai.TileCache; import javax.media.jai.UntiledOpImage; /** (c) 1999, IIUF<p> RLSAOpImage is the implementation of the Run Length Smoothing Algorithm for the Java Advanced Imaging API. The operator only supports one particular image format. @author $Author: hassan $ @version $Revision: 1.1 $ */ public class RLSAOpImage extends UntiledOpImage { /** Horizontal RLSA */ public static int DIRECTION_H = 0; /** Vertical RLSA */ public static int DIRECTION_V = 1; /** Constructs an RLSAOpImage */ public RLSAOpImage(RenderedImage source, Map hints, ImageLayout layout, Integer direction, Integer threshold) { super(source, hints, layout); this.direction = direction.intValue(); this.threshold = threshold.intValue(); } /** Current direction */ protected int direction; /** Threshold value */ protected int threshold; /** Computes the output image */ public void computeImage(Raster[] sources, WritableRaster dest, Rectangle destRect) { if (direction == DIRECTION_H) { byteLoop_h(sources[0], dest); } else if (direction == DIRECTION_V) { byteLoop_v(sources[0], dest); } else { throw new RuntimeException(this.getClass().getName() + " invalid RLSA direction"); } } /** Needed for pixel accesses */ private static int bitAccess[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /** Gets the index of the white color (0 or 1). This may differ because of the PhotoMetricInterpretation flag in the TIFF format. */ private int getWhite() { if (getColorModel().getRGB(0) == Color.white.getRGB()) { return 0; } else { return 1; } } /** Does horizontal RLSA */ private void byteLoop_h(Raster src, WritableRaster dst) { int minX = getMinX(); int maxX = getMaxX(); int minY = getMinY(); int maxY = getMaxY(); DataBufferByte srcdb = (DataBufferByte) src.getDataBuffer(); DataBufferByte dstdb = (DataBufferByte) dst.getDataBuffer(); byte srcData[] = srcdb.getData(); byte dstData[] = dstdb.getData(); MultiPixelPackedSampleModel srcsm = (MultiPixelPackedSampleModel) src.getSampleModel(); MultiPixelPackedSampleModel dstsm = (MultiPixelPackedSampleModel) dst.getSampleModel(); int srcScanlineStride = srcsm.getScanlineStride(); int dstScanlineStride = dstsm.getScanlineStride(); int srcScanlineOffset = minY*srcScanlineStride; int dstScanlineOffset = 0; int[] line = new int[maxX]; int white = getWhite(); for (int y = minY; y < maxY; y++) { int srcPixelOffset = srcScanlineOffset; int dstPixelOffset = dstScanlineOffset; int lastx = minX-(threshold+2); // RLSA one line if (white == 0) { for (int x = minX; x < maxX; x++) { int xBit = x % 8; int xOffset = x / 8; if ((srcData[srcPixelOffset+xOffset] & bitAccess[xBit]) != 0) { line[x] = 1; if (x < lastx+threshold+2) { for (int i = lastx; i < x; i++) { line[i] = 1; } } lastx = x; } else { line[x] = 0; } } } else { for (int x = minX; x < maxX; x++) { int xBit = x % 8; int xOffset = x / 8; if ((srcData[srcPixelOffset+xOffset] & bitAccess[xBit]) == 0) { line[x] = 0; if (x < lastx+threshold+2) { for (int i = lastx; i < x; i++) { line[i] = 0; } } lastx = x; } else { line[x] = 1; } } } // Copy destination line to image for (int srcx = minX, dstx = 0; srcx < maxX; srcx++, dstx++) { int xBit = dstx % 8; int xOffset = dstx / 8; if (line[srcx] == 1) { dstData[dstPixelOffset+xOffset] |= bitAccess[xBit]; } else { dstData[dstPixelOffset+xOffset] &= ~bitAccess[xBit]; } } // Next line srcScanlineOffset += srcScanlineStride; dstScanlineOffset += dstScanlineStride; } } /** Does vertical RLSA */ private void byteLoop_v(Raster src, WritableRaster dst) { int minX = getMinX(); int maxX = getMaxX(); int minY = getMinY(); int maxY = getMaxY(); DataBufferByte srcdb = (DataBufferByte) src.getDataBuffer(); DataBufferByte dstdb = (DataBufferByte) dst.getDataBuffer(); byte srcData[] = srcdb.getData(); byte dstData[] = dstdb.getData(); MultiPixelPackedSampleModel srcsm = (MultiPixelPackedSampleModel) src.getSampleModel(); MultiPixelPackedSampleModel dstsm = (MultiPixelPackedSampleModel) dst.getSampleModel(); int srcScanlineStride = srcsm.getScanlineStride(); int dstScanlineStride = dstsm.getScanlineStride(); int srcScanlineOffset = minY*srcScanlineStride; int dstScanlineOffset = 0; int[] column = new int[maxY]; int white = getWhite(); for (int x = minX, dstx = 0; x < maxX; x++, dstx++) { int srcxOffset = x / 8; int srcxBit = x % 8; int dstxOffset = dstx / 8; int dstxBit = dstx % 8; int srcLineOffset = srcScanlineOffset; int dstLineOffset = dstScanlineOffset; int lasty = minY-(threshold+2); if (white == 0) { for (int y = minY; y < maxY; y++) { if ((srcData[srcLineOffset+srcxOffset] & bitAccess[srcxBit]) != 0) { column[y] = 1; if (y < lasty+threshold+2) { for (int i = lasty; i<y; i++) { column[i] = 1; } } lasty = y; } else { column[y] = 0; } srcLineOffset += srcScanlineStride; } } else { for (int y = minY; y < maxY; y++) { if ((srcData[srcLineOffset+srcxOffset] & bitAccess[srcxBit]) == 0) { column[y] = 0; if (y < lasty+threshold+2) { for (int i = lasty; i<y; i++) { column[i] = 0; } } lasty = y; } else { column[y] = 1; } srcLineOffset += srcScanlineStride; } } // Copy resulting column onto image for (int srcy = minY, lineOffset = 0; srcy < maxY; srcy++, lineOffset += dstScanlineStride) { if (column[srcy] == 1) { dstData[lineOffset+dstxOffset] |= bitAccess[dstxBit]; } else { dstData[lineOffset+dstxOffset] &= ~bitAccess[dstxBit]; } } } } }