Java tutorial
/* * ========================================================================= * This file is part of NITRO * ========================================================================= * * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems * * NITRO 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 3 of the License, or * (at your option) any later version. * * This program 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 program; if not, If not, * see <http://www.gnu.org/licenses/>. */ package it.geosolutions.imageio.plugins.nitronitf; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.Window; import java.awt.image.BandedSampleModel; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferDouble; import java.awt.image.DataBufferFloat; import java.awt.image.DataBufferShort; import java.awt.image.DataBufferUShort; import java.awt.image.IndexColorModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.WindowConstants; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import sun.awt.image.SunWritableRaster; public class ImageIOUtils { private static final Log log = LogFactory.getLog(ImageIOUtils.class); private ImageIOUtils() { } /** * Returns an ImageReader given the input filename * * @param filename * @return * @throws IOException */ public static ImageReader getImageReader(String filename) throws IOException { return getImageReader(new File(filename)); } /** * Returns an ImageReader given the input file * * @param file * @return * @throws IOException */ public static ImageReader getImageReader(File file) throws IOException { String ext = FilenameUtils.getExtension(file.getName().toLowerCase()); ImageReader reader = null; Iterator<ImageReader> imageReaders = ImageIO.getImageReadersBySuffix(ext); if (imageReaders.hasNext()) { reader = imageReaders.next(); ImageInputStream stream = ImageIO.createImageInputStream(file); reader.setInput(stream); } return reader; } /** * Returns an ImageReader given the format, and sets the input source * * @param file * @return * @throws IOException */ public static ImageReader getImageReader(String format, Object input) throws IOException { ImageReader reader = null; Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByFormatName(format); if (imageReaders.hasNext()) { reader = imageReaders.next(); reader.setInput(input); } return reader; } /** * Returns an ImageWriter given the output filename * * @param filename * @return * @throws IOException */ public static ImageWriter getImageWriter(String filename) throws IOException { return getImageWriter(new File(filename)); } /** * Returns an ImageWriter given the input file * * @param file * @return * @throws IOException */ public static ImageWriter getImageWriter(File file) throws IOException { String ext = FilenameUtils.getExtension(file.getName().toLowerCase()); ImageWriter writer = null; Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersBySuffix(ext); if (imageWriters.hasNext()) { writer = imageWriters.next(); ImageOutputStream stream = ImageIO.createImageOutputStream(file); writer.setOutput(stream); } return writer; } public static String getPackageName(Class clazz) { // we can cheat and use the FilenameUtils to remove the class name return FilenameUtils.removeExtension(clazz.getCanonicalName()); } public static boolean canDisplay(BufferedImage image) { log.info("Data Type: " + image.getSampleModel().getDataType()); log.info("Pixel Size: " + image.getColorModel().getPixelSize()); if (image.getSampleModel().getDataType() == DataBuffer.TYPE_FLOAT && image.getColorModel().getPixelSize() == 64) return false; return !GraphicsEnvironment.isHeadless(); } /** * Returns a list of Files contained in the given String array of files or directories. If one of the array contents is a directory, it searches * it. Files ending in the extensions provided are returned in the list. * * @param filesOrDirs * @param extensions * @return */ public static List<File> getFiles(String[] filesOrDirs, String[] extensions) { List<File> files = new ArrayList<File>(); final String[] exts = extensions; for (int i = 0; i < filesOrDirs.length; i++) { String arg = filesOrDirs[i]; File file = new File(arg); if (file.isDirectory() && file.exists()) { files.addAll(Arrays.asList(file.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return ArrayUtils.contains(exts, FilenameUtils.getExtension(name.toLowerCase())); } }))); } else files.add(file); } return files; } public static JFrame showImage(BufferedImage image, String title) { return showImage(image, title, true); } public static JFrame showImage(BufferedImage image, String title, boolean fitToScreen) { JFrame frame = new JFrame(title != null ? title : ""); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); Image im = image; if (fitToScreen) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); int imageHeight = image.getHeight(); int imageWidth = image.getWidth(); if (imageHeight > screen.height || imageWidth > screen.width) { double hRatio = (imageHeight - screen.height) / screen.height; double wRatio = (imageWidth - screen.width) / screen.width; int w = -1; int h = -1; if (hRatio > wRatio) h = screen.height; else w = screen.width; im = image.getScaledInstance(w, h, Image.SCALE_DEFAULT); } } JLabel label = new JLabel(new ImageIcon(im)); frame.getContentPane().add(label, BorderLayout.CENTER); frame.pack(); centerWindow(frame); frame.setVisible(true); return frame; } public static void centerWindow(Window w) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); Dimension window = w.getSize(); if (window.width == 0) return; int left = screen.width / 2 - window.width / 2; int top = (screen.height - window.height) / 4; if (top < 0) top = 0; w.setLocation(left, top); } public static ColorModel createGrayscaleColorModel(boolean invert) { byte[] rLUT = new byte[256]; byte[] gLUT = new byte[256]; byte[] bLUT = new byte[256]; if (invert) for (int i = 0; i < 256; i++) { rLUT[255 - i] = (byte) i; gLUT[255 - i] = (byte) i; bLUT[255 - i] = (byte) i; } else { for (int i = 0; i < 256; i++) { rLUT[i] = (byte) i; gLUT[i] = (byte) i; bLUT[i] = (byte) i; } } return (new IndexColorModel(8, 256, rLUT, gLUT, bLUT)); } public static float[] findMinAndMax(float[] buffer, int pixelStride, int numBands) { float min = Float.MAX_VALUE; float max = -Float.MAX_VALUE; for (int i = 0; i < buffer.length; i += numBands) { for (int j = 0; j < pixelStride; ++j) { float value = buffer[i + j]; if (!Float.isInfinite(value)) { if (value < min) min = value; if (value > max) max = value; } } } return new float[] { min, max }; } public static double[] findMinAndMax(double[] buffer, int pixelStride, int numBands) { double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; for (int i = 0; i < buffer.length; i += numBands) { for (int j = 0; j < pixelStride; ++j) { double value = buffer[i + j]; if (!Double.isInfinite(value)) { if (value < min) min = value; if (value > max) max = value; } } } return new double[] { min, max }; } public static int[] findMinAndMax(short[] buffer, int pixelStride, int numBands) { int min = 65535; int max = 0; for (int i = 0; i < buffer.length; i += numBands) { for (int j = 0; j < pixelStride; ++j) { short value = buffer[i + j]; if (value < min) min = value; if (value > max) max = value; } } return new int[] { min, max }; } /** * Returns a generic banded WritableRaster * * @param numElems * @param numLines * @param bandOffsets * @param dataType * @return */ public static WritableRaster makeGenericBandedWritableRaster(int numElems, int numLines, int numBands, int dataType) { int[] bandOffsets = new int[numBands]; for (int i = 0; i < numBands; ++i) bandOffsets[i] = i; DataBuffer d = null; if (dataType == DataBuffer.TYPE_BYTE) d = new DataBufferByte(numElems * numLines * numBands); else if (dataType == DataBuffer.TYPE_FLOAT) d = new DataBufferFloat(numElems * numLines * numBands); else throw new IllegalArgumentException("Invalid datatype: " + dataType); BandedSampleModel bsm = new BandedSampleModel(dataType, numElems, numLines, bandOffsets.length, bandOffsets, bandOffsets); SunWritableRaster ras = new SunWritableRaster(bsm, d, new Point(0, 0)); return ras; } /** * Returns a generic pixel interleaved WritableRaster * * @param numElems * @param numLines * @param bandOffsets * @param dataType * @return */ public static WritableRaster makeGenericPixelInterleavedWritableRaster(int numElems, int numLines, int numBands, int dataType) { int[] bandOffsets = new int[numBands]; for (int i = 0; i < numBands; ++i) bandOffsets[i] = i; DataBuffer d = null; if (dataType == DataBuffer.TYPE_BYTE) d = new DataBufferByte(numElems * numLines * numBands); else if (dataType == DataBuffer.TYPE_SHORT) d = new DataBufferShort(numElems * numLines * numBands); else if (dataType == DataBuffer.TYPE_USHORT) d = new DataBufferUShort(numElems * numLines * numBands); else if (dataType == DataBuffer.TYPE_FLOAT) d = new DataBufferFloat(numElems * numLines * numBands); else if (dataType == DataBuffer.TYPE_DOUBLE) d = new DataBufferDouble(numElems * numLines * numBands); else throw new IllegalArgumentException("Invalid datatype: " + dataType); PixelInterleavedSampleModel pism = new PixelInterleavedSampleModel(dataType, numElems, numLines, bandOffsets.length, numElems * bandOffsets.length, bandOffsets); SunWritableRaster ras = new SunWritableRaster(pism, d, new Point(0, 0)); return ras; } /** * Converts the float data to byte data, and sets the values in the byteData buffer * * @param floatData * @param byteData */ public static void floatToByteBuffer(float[] floatData, byte[] byteData, int pixelStride, int numBands) { float[] minMax = ImageIOUtils.findMinAndMax(floatData, pixelStride, numBands); float scale = 255f / (minMax[1] - minMax[0]); for (int i = 0, j = 0; i < floatData.length; i += numBands, j++) { float val = floatData[i] - minMax[0]; if (val < 0.0f) val = 0.0f; int iVal = (int) (val * scale); if (iVal > 255) iVal = 255; byteData[j] = (byte) iVal; } } /** * Converts the float data to byte data, and sets the values in the byteData buffer * * @param doubleData * @param byteData */ public static void doubleToByteBuffer(double[] doubleData, byte[] byteData, int pixelStride, int numBands) { double[] minMax = ImageIOUtils.findMinAndMax(doubleData, pixelStride, numBands); double scale = 255F / (minMax[1] - minMax[0]); for (int i = 0, j = 0; i < doubleData.length; i += numBands, j++) { double val = doubleData[i] - minMax[0]; if (val < 0.0f) val = 0.0f; int iVal = (int) (val * scale); if (iVal > 255) iVal = 255; byteData[j] = (byte) iVal; } } /** * Converts the float data to byte data, and sets the values in the byteData buffer * * @param shortData * @param byteData */ public static void shortToByteBuffer(short[] shortData, byte[] byteData, int pixelStride, int numBands) { int[] minMax = ImageIOUtils.findMinAndMax(shortData, pixelStride, numBands); double scale = 1.0; if (minMax[1] != minMax[0]) scale = 256.0 / (minMax[1] - minMax[0]); for (int i = 0, j = 0; i < shortData.length; i += numBands, j++) { int value = (shortData[i] & 0xffff) - minMax[0]; if (value < 0) value = 0; value = (int) (value * scale); if (value > 255) value = 255; byteData[j] = (byte) value; } } /** * Utility method for creating a BufferedImage from a source raster Currently only Float->Byte and Byte->Byte are supported. Will throw an * {@link UnsupportedOperationException} if the conversion is not supported. * * @param raster * @param imageType * @return */ public static BufferedImage rasterToBufferedImage(Raster raster, ImageTypeSpecifier imageType) { if (imageType == null) { if (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) imageType = ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false); else throw new IllegalArgumentException("unable to dynamically determine the imageType"); } // create a new buffered image, for display BufferedImage bufImage = imageType.createBufferedImage(raster.getWidth(), raster.getHeight()); if (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_USHORT && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) { // convert short pixels to bytes short[] shortData = ((DataBufferUShort) raster.getDataBuffer()).getData(); byte[] byteData = ((DataBufferByte) bufImage.getWritableTile(0, 0).getDataBuffer()).getData(); ImageIOUtils.shortToByteBuffer(shortData, byteData, 1, raster.getNumBands()); } else if (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_FLOAT && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) { // convert float pixels to bytes float[] floatData = ((DataBufferFloat) raster.getDataBuffer()).getData(); byte[] byteData = ((DataBufferByte) bufImage.getWritableTile(0, 0).getDataBuffer()).getData(); ImageIOUtils.floatToByteBuffer(floatData, byteData, 1, raster.getNumBands()); } else if (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_DOUBLE && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) { // convert double pixels to bytes double[] doubleData = ((DataBufferDouble) raster.getDataBuffer()).getData(); byte[] byteData = ((DataBufferByte) bufImage.getWritableTile(0, 0).getDataBuffer()).getData(); ImageIOUtils.doubleToByteBuffer(doubleData, byteData, 1, raster.getNumBands()); } else if ((raster.getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) || (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_USHORT && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_USHORT) || (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_SHORT && bufImage.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_SHORT)) { bufImage.setData(raster); } else { throw new UnsupportedOperationException( "Unable to convert raster type to bufferedImage type: " + raster.getDataBuffer().getDataType() + " ==> " + bufImage.getRaster().getDataBuffer().getDataType()); } return bufImage; } /** * Turns a signed byte into an unsigned one. * * @param b The byte to read * @return An unsigned integer */ public static int makeUnsigned(byte b) { return b >= 0 ? (int) b : 255 + (int) b + 1; } public static void main(String[] args) { List<File> files = getFiles(new String[] { "c:/", "c:/dev/" }, new String[] { "jpg" }); for (File file : files) { log.info(file.getAbsolutePath()); } } }