package edu.mbl.jif.imaging.util; import java.io.*; import java.util.ArrayList; import javax.imageio.ImageIO; import javax.media.jai.*; import java.awt.*; import java.awt.color.ColorSpace; import java.awt.image.*; import java.awt.image.DataBufferFloat; import java.awt.image.renderable.ParameterBlock; import edu.mbl.jif.gui.dialog.DialogBox; import edu.mbl.jif.gui.imaging.FrameImageDisplayTabbed; import edu.mbl.jif.imaging.ImageObject; import edu.mbl.jif.imaging.tiff.MultipageTiffFile; import edu.mbl.jif.utils.FileUtil; public class ImageUtils { static byte[] avgImg = null; //////////////////////////////////////////////////////////////////////////// // Thumbnail / Scale // //----------------------------------------------------------- // makeThumbnail from a Planar Image // public static BufferedImage makeThumbnail (PlanarImage _image, float scale) { Interpolation interp = null; RenderingHints renderHints = null; ParameterBlock pb = new ParameterBlock(); pb.addSource(_image); pb.add(scale); pb.add(scale); pb.add(0.0F); pb.add(0.0F); if (interp == null) { interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST); } pb.add(interp); return JAI.create("scale", pb, renderHints).getAsBufferedImage(); } //--------------------------------------------------------------------- // makeThumbnail from a Buffered Image public static BufferedImage makeThumbnail (BufferedImage _image, float scale) { Interpolation interp = null; RenderingHints renderHints = null; ParameterBlock pb = new ParameterBlock(); pb.addSource(_image); pb.add(scale); pb.add(scale); pb.add(0.0F); pb.add(0.0F); if (interp == null) { interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST); } pb.add(interp); return JAI.create("scale", pb, renderHints).getAsBufferedImage(); } //////////////////////////////////////////////////////////////////////// // Image <--> Array // // //--------------------------------------------------------------------- // Creates a RenderedImage from byte[] array: byte[] --> RenderedImage // public static RenderedImage byteArrayToRenderedImage ( byte[] imgArray, int width, int height) { byte[] image_data; BufferedImage image = null; int size = width * height; image_data = new byte[size]; image_data = imgArray; DataBuffer db = new DataBufferByte(image_data, image_data.length); try { WritableRaster raster = Raster.createPackedRaster(db, width, height, 8, null); image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); image.setData(raster); } catch (Exception e) {} return (RenderedImage) image; // If you need a planar image // PlanarImage pi = PlanarImage.wrapRenderedImage(ri) } //--------------------------------------------------------------------- // Creates a RenderedImage from short[] array: short[] --> RenderedImage // public static RenderedImage shortArrayToRenderedImage (short[] imgArray, int width, int height) { byte[] image_data; BufferedImage image = null; int size = width * height; DataBuffer db = new DataBufferUShort(imgArray, imgArray.length); try { WritableRaster raster = Raster.createPackedRaster(db, width, height, 8, null); image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY); image.setData(raster); } catch (Exception e) { } return (RenderedImage) image; // If you need a planar image // PlanarImage pi = PlanarImage.wrapRenderedImage(ri) } //---------------------------------------------------------------- // createImage - create a BufferedImage fron short[] public static BufferedImage createImage (int imageWidth, int imageHeight, int dataType, Object data) { if (dataType == DataBuffer.TYPE_BYTE) { return createImage(imageWidth, imageHeight, (byte[]) data); } else if (dataType == DataBuffer.TYPE_USHORT) { return createImage(imageWidth, imageHeight, (short[]) data); } else { return null; } } // createImage - create a BufferedImage fron short[] public static BufferedImage createImage (int imageWidth, int imageHeight, short[] data) { ComponentColorModel ccm = new ComponentColorModel(ColorSpace.getInstance( ColorSpace.CS_GRAY), new int[] { 16}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); ComponentSampleModel csm = new ComponentSampleModel(DataBuffer.TYPE_USHORT, imageWidth, imageHeight, 1, imageWidth, new int[] { 0}); DataBuffer dataBuf = new DataBufferUShort((short[]) data, imageWidth); WritableRaster wr = Raster.createWritableRaster(csm, dataBuf, new Point(0, 0)); return new BufferedImage(ccm, wr, true, null); } // createImage - create a BufferedImage fron byte[] public static BufferedImage createImage (int imageWidth, int imageHeight, byte[] data) { ComponentColorModel ccm = new ComponentColorModel(ColorSpace.getInstance( ColorSpace.CS_GRAY), new int[] { 8}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); ComponentSampleModel csm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, imageWidth, imageHeight, 1, imageWidth, new int[] { 0}); DataBuffer dataBuf = new DataBufferByte((byte[]) data, imageWidth); WritableRaster wr = Raster.createWritableRaster(csm, dataBuf, new Point(0, 0)); return new BufferedImage(ccm, wr, true, null); } // //--------------------------------------------------------------------- public static BufferedImage byteArrayToBufferedImage ( byte[] imgArray, int width, int height) { int size = width * height; BufferedImage image = null; byte[] image_data = new byte[size]; image_data = imgArray; DataBuffer db = new DataBufferByte(image_data, image_data.length); try { image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); WritableRaster wr = image.getRaster(); wr.setDataElements(0, 0, width, height, image_data); } catch (Exception e) { } return image; // If you need a planar image // PlanarImage pi = PlanarImage.wrapRenderedImage(ri) } //--------------------------------------------------------------------- // Creates a RenderedImage from short[] array: short[] --> RenderedImage // public static BufferedImage shortArrayToBufferedImage (short[] imgArray, int width, int height) { byte[] image_data; BufferedImage image = null; int size = width * height; DataBuffer db = new DataBufferUShort(imgArray, imgArray.length); try { WritableRaster raster = Raster.createPackedRaster(db, width, height, 8, null); image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY); image.setData(raster); } catch (Exception e) { } return image; } //--------------------------------------------------------------------- // RenderedImageToByteArray - RenderedImage --> byte[] public static byte[] renderedImageToByteArray (RenderedImage image) { int imageSize = image.getWidth() * image.getHeight(); PixelGrabber pixGrab; RenderedImageAdapter ria = new RenderedImageAdapter(image); BufferedImage bi = ria.getAsBufferedImage(); byte[] pix = new byte[imageSize]; pix = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData(); return pix; } //--------------------------------------------------------------------- // Create a RenderedImage from a 2D array of Float values // float[][] --> RenderedImage public static RenderedImage createRenderedImage ( float[][] theData, int width, int height, int numBands) { int len = width * height; Point origin = new Point(0, 0); // create a float sample model SampleModel sampleModel = RasterFactory.createBandedSampleModel( DataBuffer. TYPE_FLOAT, width, height, numBands); // create a compatible ColorModel ColorModel colourModel = PlanarImage.createColorModel(sampleModel); // create a TiledImage using the float SampleModel TiledImage tiledImage = new TiledImage(origin, sampleModel, width, height); // create a DataBuffer from the float[][] array DataBufferFloat dataBuffer = new DataBufferFloat(theData, len); // create a Raster Raster raster = RasterFactory.createWritableRaster(sampleModel, dataBuffer, origin); // set the TiledImage data to that of the Raster tiledImage.setData(raster); RenderedImageAdapter img = new RenderedImageAdapter((RenderedImage) tiledImage); return img; } /////////////////////////////////////////////////////////////////////////// // Write on images... // //----------------------------------------------------------- // dataStripe - Write a string in a black bar along the bottom of the image // public static RenderedImage dataStripe (RenderedImage rImage, String data) { RenderedImageAdapter ria = new RenderedImageAdapter(rImage); BufferedImage bImage = ria.getAsBufferedImage(); return dataStripe(bImage, data); } public static BufferedImage dataStripe (BufferedImage bImage, String data) { Graphics bG = bImage.getGraphics(); int w = bImage.getWidth(); int h = bImage.getHeight(); // adjust font size to match stripe size // ########### bG.setFont(new Font("SansSerif", Font.PLAIN, 11)); bG.setColor(Color.black); //bG.fillRect(0, (int) ((h * 31) / 32), w, h - (int) ((h * 31) / 32)); bG.fillRect(0, h - 14, w, h); bG.setColor(Color.white); bG.drawString(data, 10, h - 3); bG.dispose(); return bImage; } //----------------------------------------------------------- // dataOnImage - Write a title plus an array of strings onto the image // public static RenderedImage dataOnImage ( RenderedImage rImage, String title, String[] data) { RenderedImageAdapter ria = new RenderedImageAdapter(rImage); BufferedImage bImage = ria.getAsBufferedImage(); return dataOnImage(bImage, title, data); } public static BufferedImage dataOnImage ( BufferedImage bImage, String title, String[] data) { Graphics bG = bImage.getGraphics(); int w = bImage.getWidth(); int h = bImage.getHeight(); int incr = (int) (h / (data.length + 2)); // draw the Title bG.setColor(Color.white); bG.drawString(title, (int) (w / 8), incr); // draw the strings for (int i = 0; i < data.length; i++) { bG.setColor(Color.white); bG.drawString(data[i], (int) (w / 8), incr * (i + 2)); } return bImage; } // //----------------------------------------------------------- // Write a string on the image // public static RenderedImage StrOnImage (RenderedImage rImage, String data) { RenderedImageAdapter ria = new RenderedImageAdapter(rImage); BufferedImage bImage = ria.getAsBufferedImage(); Graphics bG = bImage.getGraphics(); int w = bImage.getWidth(); int h = bImage.getHeight(); //int incr = (int) (h / (data.length + 2)); bG.setColor(Color.white); bG.drawString(data, (int) (w / 8), (int) (h / 8)); rImage = bImage; return rImage; } //////////////////////////////////////////////////////////////////////////// // Conversions // ////////////////////////////////////////////////////////////////////////// /// Convert between Color <--> Gray // /** produce a 3 band luminance image from a 3 band color image */ public static PlanarImage convertColorToGray (PlanarImage src, int brightness) { PlanarImage dst = null; double b = (double) brightness; double[][] matrix = { { .114D, 0.587D, 0.299D, b}, { .114D, 0.587D, 0.299D, b}, { .114D, 0.587D, 0.299D, b} }; if (src != null) { ParameterBlock pb = new ParameterBlock(); pb.addSource(src); pb.add(matrix); dst = JAI.create("bandcombine", pb, null); } return dst; } //------------------------------------------------------------------------ // Produce a 3 band image from a single band gray scale image public static PlanarImage convertGrayToColor (PlanarImage src, int brightness) { PlanarImage dst = null; double b = (double) brightness; double[][] matrix = { { 1.0D, b}, { 1.0D, b}, { 1.0D, b} }; if (src != null) { int nbands = src.getSampleModel().getNumBands(); // MUST check color model here if (nbands == 1) { ParameterBlock pb = new ParameterBlock(); pb.addSource(src); pb.add(matrix); dst = JAI.create("bandcombine", pb, null); } else { dst = src; } } return dst; } //------------------------------------------------------------------------ // public static BufferedImage convertToIndexColor(BufferedImage src) { // FloydSteinbergFilterOp fsfo = new FloydSteinbergFilterOp(); // return fsfo.filter(src, null); // } public static BufferedImage convertToIndexColor (BufferedImage src) { BufferedImage dst = new BufferedImage( src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED); ParameterBlock pb = new ParameterBlock(); pb.addSource(src); pb.add(ColorCube.BYTE_496); pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG); // Perform the error diffusion operation. try { RenderedImage imgR = JAI.create("errordiffusion", pb, null); dst = PlanarImage.wrapRenderedImage((PlanarImage) imgR) .getAsBufferedImage(); } catch (Exception ex) { ex.printStackTrace(); } return dst; } // //--------------------------------------------------------------------- final private byte clamp (int v) { if (v > 255) { return (byte) 255; } else if (v < 0) { return (byte) 0; } else { return (byte) v; } } ///////////////////////////////////////////////////////////////////////// // 4:1 Virtual Averager - halves the size of the image. // public static void average4to1 ( byte[] imageOut, byte[] imageIn, int _width, int _height) { int w2 = _width / 2; int h2 = _height / 2; int offset = 0; int x2 = 0; //byte[] avgImg = new byte[(_width / 2 * _height) / 2]; for (int y = 0; y < h2; y++) { offset = 2 * y * _width; for (int x = 0; x < w2; x++) { x2 = x * 2; imageOut[(y * w2) + x] = (byte) (( (int) (imageIn[offset + x2] & 0xFF) + (int) (imageIn[offset + x2 + 1] & 0xFF) + (int) (imageIn[offset + _width + x2] & 0xFF) + (int) (imageIn[offset + _width + x2 + 1] & 0xFF)) / 4); } } return; } public static byte[] average4to1 (byte[] image, int _width, int _height) { int w2 = _width / 2; int h2 = _height / 2; int offset = 0; int x2 = 0; //byte[] avgImg = new byte[(_width / 2 * _height) / 2]; for (int y = 0; y < h2; y++) { offset = 2 * y * _width; for (int x = 0; x < w2; x++) { x2 = x * 2; avgImg[(y * w2) + x] = (byte) (((int) (image[offset + x2] & 0xFF) + (int) (image[offset + x2 + 1] & 0xFF) + (int) (image[offset + _width + x2] & 0xFF) + (int) (image[offset + _width + x2 + 1] & 0xFF)) / 4); } } return avgImg; } //----------------------------------------------------------------------------- // This method returns an Image object from a buffered image public static Image toImage (BufferedImage bufferedImage) { return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource()); } //---------------------------------------------------------------------------- // Get a image from a file using ImageIO // public static Image getFromFile (String image_file_name) { Image image = null; try { image = ImageIO.read(new File(image_file_name)); } catch (Exception e) { System.out.println("Exception loading: " + image_file_name); e.printStackTrace(); } return image; } //--------------------------------------------------------------------------- // loadImageArrayList public static ArrayList loadImageArrayList (String tiffPathFile) { ArrayList imgs = new ArrayList(); try { imgs = MultipageTiffFile.loadImageArrayList(tiffPathFile); if (imgs == null) { DialogBox.boxError("Could not open image", "file: " + tiffPathFile); System.err.println("Could not loadImageArrayList from: " + tiffPathFile); } } catch (Exception e) { System.err.println("Error loading ImageArray from:\n " + tiffPathFile); e.printStackTrace(); imgs = null; } return imgs; } public static void loadIntoTabbedViewerFrame (String filename) { ArrayList imgs = new ArrayList(); imgs = ImageUtils.loadImageArrayList(filename); if (imgs != null) { ImageUtils.getImageDataType(imgs); int width = ((BufferedImage) imgs.get(0)).getWidth(); int height = ((BufferedImage) imgs.get(0)).getHeight(); int size = width * height; int numImages = imgs.size(); new FrameImageDisplayTabbed(imgs); } } //--------------------------------------------------------------------- public static int getImageDataType (ArrayList imgs) { return getImageDataType((BufferedImage) imgs.get(0)); } static boolean debug = false; public static int getImageDataType (BufferedImage img) { int dataType = img.getData().getDataBuffer().getDataType(); if (debug) { System.out.print("ImageLoaded: type= " + dataType + " ) "); switch (dataType) { case DataBuffer.TYPE_BYTE: System.out.print("BYTE"); break; case DataBuffer.TYPE_USHORT: System.out.print("USHORT"); break; case DataBuffer.TYPE_SHORT: System.out.print("SHORT"); break; case DataBuffer.TYPE_INT: System.out.print("INT"); break; case DataBuffer.TYPE_FLOAT: System.out.print("FLOAT"); break; case DataBuffer.TYPE_DOUBLE: System.out.print("DOUBLE"); break; default: System.out.print("unknown type?"); } System.out.println(); } return dataType; } ///////////////////////////////////////////////////////////////////////// // getImageObject - creates an ImageObject containing the first image // from a multipage Tiff file and the number of pages/slices in it. // public static ImageObject getImageObject (String path, String filename, float thumbScale) throws IOException { ImageObject _imgObj = null; try { _imgObj = getImageObject(path + filename, thumbScale); } catch (IOException ex) { throw ex; } return _imgObj; } public static ImageObject getImageObject (String _filename, float thumbScale) throws IOException { String f = filenameWithTifExt(_filename); MultipageTiffFile mf = new MultipageTiffFile(f); int numPages = mf.getNumImages(); BufferedImage bImage = mf.getImage(0); if (bImage == null) { mf.close(); mf = null; return null; } else { int sample = 4; if (bImage.getWidth() > 800) { sample = 5; } BufferedImage thumb = mf.getAsThumbnail(0, sample); ImageObject imageObj = new ImageObject(FileUtil.getJustFilenameNoExt(f), bImage, numPages, thumb, thumbScale); mf.close(); mf = null; return imageObj; } } public static String filenameWithTifExt (String filename) { return FileUtil.removeExtension(filename) + ".tif"; } } // end class Image Utils