changeset 860:fe58284a8dd9 stream

implemented colop= ntsc_gray and map_gray_bgr. still occasional weirdness.
author robcast
date Tue, 08 Mar 2011 21:00:56 +0100
parents f75e9f541ec1
children 74062b7d9b22
files servlet/src/digilib/image/DocuImage.java servlet/src/digilib/image/ImageLoaderDocuImage.java servlet/src/digilib/servlet/Scaler.java
diffstat 3 files changed, 119 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/servlet/src/digilib/image/DocuImage.java	Tue Mar 08 13:15:53 2011 +0100
+++ b/servlet/src/digilib/image/DocuImage.java	Tue Mar 08 21:00:56 2011 +0100
@@ -205,14 +205,22 @@
 
 	/** Operations for colorOps.
 	 * 
+     * GRAYSCALE: cast color image to grayscale
+     * NTSC_GRAY: convert color image to grayscale using NTSC formula
+     * INVERT: invert colors (every channel separately)
+     * MAP_GRAY_BGR: false color image from grayscale (0: blue, 128: green, 255: red)
 	 *
 	 */
-	public enum ColorOp {GRAYSCALE, INVERT};
+	public enum ColorOp {GRAYSCALE, NTSC_GRAY, INVERT, MAP_GRAY_BGR};
 
 	/** Changes the colors of the current image.
 	 * 
-	 * Changes the colors of the current image. Operations are e.g.
-	 * reduction to grayscale or false-color palettes.
+	 * Changes the colors of the current image. Operations are instances of ColorOp:
+	 * 
+	 * GRAYSCALE: cast color image to grayscale
+     * NTSC_GRAY: convert color image to grayscale using NTSC formula
+	 * INVERT: invert colors (every channel separately)
+	 * MAP_GRAY_BGR: false color image from grayscale (0: blue, 128: green, 255: red)
 	 * 
 	 * @throws ImageOpException
 	 */
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java	Tue Mar 08 13:15:53 2011 +0100
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java	Tue Mar 08 21:00:56 2011 +0100
@@ -26,6 +26,7 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.AffineTransformOp;
+import java.awt.image.BandCombineOp;
 import java.awt.image.BufferedImage;
 import java.awt.image.ByteLookupTable;
 import java.awt.image.ColorConvertOp;
@@ -78,17 +79,39 @@
 	protected static LookupTable invertSingleByteTable;
     protected static LookupTable invertRgbaByteTable;
     protected static boolean needsInvertRgba = false;
-	/* RescaleOps for contrast/brightness operation */
+	/* RescaleOp for contrast/brightness operation */
     protected static boolean needsRescaleRgba = false;
+    /* lookup tables for false-color */
+    protected static LookupTable mapBgrByteTable;
     
 	static {
 		byte[] invertByte = new byte[256];
 		byte[] orderedByte = new byte[256];
 		byte[] nullByte = new byte[256];
+        byte[] mapR = new byte[256];
+        byte[] mapG = new byte[256];
+        byte[] mapB = new byte[256];
 		for (int i = 0; i < 256; ++i) {
+		    // counting down
 			invertByte[i] = (byte) (256 - i);
+			// counting up
 			orderedByte[i] = (byte) i;
+			// constant 0
 			nullByte[i] = 0;
+			// three overlapping slopes
+			if (i < 64) {
+			    mapR[i] = 0;
+			    mapG[i] = (byte) (4 * i);
+			    mapB[i] = (byte) 255;
+			} else if (i >= 64 && i < 192) {
+                mapR[i] = (byte) (2 * (i - 64));
+                mapG[i] = (byte) 255;
+                mapB[i] = (byte) (255 - 2 * (i - 64));
+			} else {
+                mapR[i] = (byte) 255;
+                mapG[i] = (byte) (4 * (i - 192));
+                mapB[i] = 0;
+			}
 		}
 		// should(!) work for all color models
 		invertSingleByteTable = new ByteLookupTable(0, invertByte);
@@ -105,6 +128,9 @@
 		} else {
 			invertRgbaByteTable = invertSingleByteTable;
 		}
+		// this hopefully works for all
+		mapBgrByteTable = new ByteLookupTable(0, new byte[][] {
+                mapR, mapG, mapB});
 	}
 	
 	/** the size of the current image */
@@ -496,40 +522,86 @@
 		return fb;
 	}
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * digilib.image.DocuImageImpl#colorOp(digilib.image.DocuImage.ColorOps)
-	 */
-	public void colorOp(ColorOp op) throws ImageOpException {
-		if (op == ColorOp.GRAYSCALE) {
-			// convert image to grayscale
-			logger.debug("Color op: grayscaling");
-			ColorConvertOp colop = new ColorConvertOp(
-					ColorSpace.getInstance(ColorSpace.CS_GRAY), renderHint);
-			// let filter create new image
-			img = colop.filter(img, null);
-		} else if (op == ColorOp.INVERT) {
-			// invert colors i.e. invert every channel
-			logger.debug("Color op: inverting");
-			// TODO: is this enough for all image types?
-			LookupTable invtbl = null;
-			ColorModel cm = img.getColorModel();
-			if (needsInvertRgba && cm.hasAlpha()) {
-				/* should work with one array for all channels, but
-				 * JDK 1.6 in Linux (at least) is broken :-(
-				 */
-				invtbl = invertRgbaByteTable;
-			} else {
-				invtbl = invertSingleByteTable;
-			}
-			LookupOp colop = new LookupOp(invtbl, renderHint);
-			logger.debug("colop: image="+img+" colormodel="+cm);
-			colop.filter(img, img);
-		}
-
-	}
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * digilib.image.DocuImageImpl#colorOp(digilib.image.DocuImage.ColorOps)
+     */
+    public void colorOp(ColorOp colop) throws ImageOpException {
+        if (colop == ColorOp.GRAYSCALE) {
+            /*
+             * convert image to grayscale
+             */
+            logger.debug("Color op: grayscaling");
+            ColorModel cm = img.getColorModel();
+            if (cm.getNumColorComponents() == 1) {
+                // grayscale already
+                return;
+            }
+            ColorConvertOp op = new ColorConvertOp(
+                    ColorSpace.getInstance(ColorSpace.CS_GRAY), renderHint);
+            // let filter create new image
+            img = op.filter(img, null);
+        } else if (colop == ColorOp.NTSC_GRAY) {
+            /*
+             * convert image to grayscale NTSC-style: luminance = 0.2989*red +
+             * 0.5870*green + 0.1140*blue
+             */
+            logger.debug("Color op: NTSC gray");
+            ColorModel cm = img.getColorModel();
+            if (cm.getNumColorComponents() == 1) {
+                // grayscale already
+                return;
+            }
+            float[][] combineFn = new float[1][4];
+            combineFn[0] = rgbOrdered(new float[] { 0.299f, 0.114f, 0.587f, 0f });
+            BandCombineOp op = new BandCombineOp(combineFn, renderHint);
+            // unfortunately BandCombineOp only works on Rasters so we create a
+            // new image and use its Raster
+            BufferedImage dest = new BufferedImage(img.getWidth(),
+                    img.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
+            op.filter(img.getRaster(), dest.getRaster());
+            img = dest;
+        } else if (colop == ColorOp.INVERT) {
+            /*
+             * invert colors i.e. invert every channel
+             */
+            logger.debug("Color op: inverting");
+            // TODO: is this enough for all image types?
+            LookupTable invtbl = null;
+            ColorModel cm = img.getColorModel();
+            if (needsInvertRgba && cm.hasAlpha()) {
+                /*
+                 * should work with one array for all channels, but JDK 1.6 in
+                 * Linux (at least) is broken :-(
+                 */
+                invtbl = invertRgbaByteTable;
+            } else {
+                invtbl = invertSingleByteTable;
+            }
+            LookupOp op = new LookupOp(invtbl, renderHint);
+            logger.debug("colop: image=" + img + " colormodel=" + cm);
+            op.filter(img, img);
+        } else if (colop == ColorOp.MAP_GRAY_BGR) {
+            /*
+             * false color image from grayscale (0: blue, 128: green, 255: red)
+             */
+            logger.debug("Color op: map_gray_bgr");
+            // convert to grayscale
+            ColorConvertOp grayOp = new ColorConvertOp(
+                    ColorSpace.getInstance(ColorSpace.CS_GRAY), renderHint);
+            // create new 3-byte image
+            BufferedImage dest = new BufferedImage(img.getWidth(),
+                    img.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
+            img = grayOp.filter(img, dest);
+            logger.debug("map_gray: image=" + img);
+            // convert to false color
+            LookupOp mapOp = new LookupOp(mapBgrByteTable, renderHint);
+            mapOp.filter(img, img);
+            logger.debug("mapped image=" + img);
+        }
+    }
 
 	public void rotate(double angle) throws ImageOpException {
 		// setup rotation
--- a/servlet/src/digilib/servlet/Scaler.java	Tue Mar 08 13:15:53 2011 +0100
+++ b/servlet/src/digilib/servlet/Scaler.java	Tue Mar 08 21:00:56 2011 +0100
@@ -31,7 +31,7 @@
     private static final long serialVersionUID = 5289386646192471549L;
 
     /** digilib servlet version (for all components) */
-    public static final String version = "1.9.1a20";
+    public static final String version = "1.9.1a21";
 
     /** servlet error codes */
     public static enum Error {UNKNOWN, AUTH, FILE, IMAGE};