/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.core.api.image.op; import java.awt.Rectangle; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.util.Map; import javax.media.jai.ImageLayout; import javax.media.jai.PackedImageData; import javax.media.jai.PixelAccessor; import javax.media.jai.PointOpImage; import javax.media.jai.UnpackedImageData; /** * The Class ThresholdToBinOpImage. * * @author Nicolas Roduit */ /** * SampleOpImage is an extension of PointOpImage that takes two integer parameters and one source and performs a * modified threshold operation on the given source. */ public class ThresholdToBinOpImage extends PointOpImage { private double min; private double max; private boolean inverse = false; /** * Lookup table for ORing bytes of output. */ private static byte[] byteTable = new byte[] { (byte) 0x80, (byte) 0x40, (byte) 0x20, (byte) 0x10, (byte) 0x08, (byte) 0x04, (byte) 0x02, (byte) 0x01, }; /** * Constructs an SampleOpImage. The image dimensions are copied from the source image. The tile grid layout, * SampleModel, and ColorModel may optionally be specified by an ImageLayout object. * * @param source * a RenderedImage. * @param layout * an ImageLayout optionally containing the tile grid layout, SampleModel, and ColorModel, or null. */ public ThresholdToBinOpImage(RenderedImage source, Map map, ImageLayout layout, double min, double max) { super(source, layout, map, true); this.min = min; this.max = max; // cas limite, si l'inverse est sélectionné et que les valeurs min et max sont égales, alors la sélection se // fait comme // si l'inverse n'était pas sélectionné, donc seuille une intensité unique. if (min > max) { inverse = true; } } @Override protected void computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect) { // Depending on the base dataType of the RasterAccessors, // either the byteLoop or intLoop method is called. The two // functions are virtually the same, except for the data type // of the underlying arrays. switch (sources[0].getSampleModel().getDataType()) { case DataBuffer.TYPE_BYTE: byteLoop(sources[0], dest, destRect); break; case DataBuffer.TYPE_SHORT: shortLoop(sources[0], dest, destRect); break; case DataBuffer.TYPE_USHORT: unsignedShortLoop(sources[0], dest, destRect); break; case DataBuffer.TYPE_INT: intLoop(sources[0], dest, destRect); break; case DataBuffer.TYPE_FLOAT: floatLoop(sources[0], dest, destRect); break; case DataBuffer.TYPE_DOUBLE: doubleLoop(sources[0], dest, destRect); break; default: String className = this.getClass().getName(); throw new RuntimeException(className + " does not implement computeRect" //$NON-NLS-1$ + " for int/short/float/double data"); //$NON-NLS-1$ } } private void byteLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_BYTE, false); int srcOffset = srcImD.bandOffsets[0]; byte[] srcData = ((byte[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { int pixel = srcData[s] & 0xFF; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } private void shortLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_SHORT, false); int srcOffset = srcImD.bandOffsets[0]; short[] srcData = ((short[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { int pixel = srcData[s]; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } private void unsignedShortLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_USHORT, false); int srcOffset = srcImD.bandOffsets[0]; short[] srcData = ((short[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { int pixel = srcData[s] & 0xffff; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } private void intLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_INT, false); int srcOffset = srcImD.bandOffsets[0]; int[] srcData = ((int[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { int pixel = srcData[s]; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } private void floatLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_FLOAT, false); int srcOffset = srcImD.bandOffsets[0]; float[] srcData = ((float[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { float pixel = srcData[s]; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } private void doubleLoop(Raster source, WritableRaster dest, Rectangle destRect) { Rectangle srcRect = mapDestRect(destRect, 0); // should be identical to destRect PixelAccessor pa = new PixelAccessor(dest.getSampleModel(), null); PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false); int offset = pid.offset; PixelAccessor srcPa = new PixelAccessor(source.getSampleModel(), null); UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_DOUBLE, false); int srcOffset = srcImD.bandOffsets[0]; double[] srcData = ((double[][]) srcImD.data)[0]; int pixelStride = srcImD.pixelStride; int ind0 = pid.bitOffset; for (int h = 0; h < destRect.height; h++) { for (int b = ind0, s = srcOffset; b < ind0 + destRect.width; b++, s += pixelStride) { double pixel = srcData[s]; if (inverse) { if (pixel > min || pixel < max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } else { if (pixel >= min && pixel <= max) { pid.data[offset + (b >> 3)] |= byteTable[b % 8]; } } } offset += pid.lineStride; srcOffset += srcImD.lineStride; } pa.setPackedPixels(pid); } }