All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.ij_plugins.imageio.ImagePlusFactory Maven / Gradle / Ivy

Go to download

ijp-ImageIO enable reading and writing images using Java ImageIO codecs. The core ImageIO formats: JPEG, PNG, BMP, WBMP, and GIF. IJP-ImageIO is also using JAI codes adding support for TIFF, JPEG200, PNM, and PCX. TIFF supports reading and writing using various compression schemes: LZW, JPEG, ZIP, and Deflate. For more detailed information see IJP-ImageIO home page: https://github.com/ij-plugins/ijp-imageio/wiki.

There is a newer version: 2.3.0
Show newest version
/*
 * Image/J Plugins
 * Copyright (C) 2002-2016 Jarek Sacha
 * Author's email: jpsacha at gmail.com
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Latest release available at http://sourceforge.net/projects/ij-plugins/
 */
package net.sf.ij_plugins.imageio;

import com.github.jaiimageio.impl.plugins.tiff.TIFFImageMetadata;
import com.github.jaiimageio.plugins.tiff.BaselineTIFFTagSet;
import com.github.jaiimageio.plugins.tiff.TIFFField;
import ij.ImagePlus;
import ij.measure.Calibration;
import ij.process.*;

import java.awt.image.*;

/**
 * Creates/converts Image/J's image objects from Java2D/JAI representation.
 *
 * @author Jarek Sacha
 */
public class ImagePlusFactory {


    private ImagePlusFactory() {
    }


    /**
     * Force Rendered image to set all the tails that it may have. In multi-tile
     * images not all tiles may be updated when a RenderedImage is created.
     *
     * @param ri image that may need tile update.
     * @return WritableRaster with all tiles updated.
     */
    public static WritableRaster forceTileUpdate(final RenderedImage ri) {
        Raster r = ri.getData();
        if (!(r instanceof WritableRaster)) {
            r = Raster.createWritableRaster(r.getSampleModel(), r.getDataBuffer(), null);
        }

        final WritableRaster wr = (WritableRaster) r;
        final int xTiles = ri.getNumXTiles();
        final int yTiles = ri.getNumYTiles();
        for (int ty = 0; ty < yTiles; ++ty) {
            for (int tx = 0; tx < xTiles; ++tx) {
                wr.setRect(ri.getTile(tx, ty));
            }
        }

        return wr;
    }


    /**
     * Create an ImageProcessor object from a DataBuffer.
     *
     * @param w      Image width.
     * @param h      Image height.
     * @param buffer Data buffer.
     * @param cm     Color model.
     * @return Image processor object.
     * @throws IJImageIOException If data buffer is in unknown format.
     */
    public static ImageProcessor createProcessor(final int w, final int h, final DataBuffer buffer,
                                                 final ColorModel cm) throws IJImageIOException {

        if (buffer.getOffset() != 0) {
            throw new IJImageIOException("Expecting BufferData with no offset.");
        }

        switch (buffer.getDataType()) {
            case DataBuffer.TYPE_BYTE:
                return new ByteProcessor(w, h, ((DataBufferByte) buffer).getData(), cm);
            case DataBuffer.TYPE_USHORT:
                return new ShortProcessor(w, h, ((DataBufferUShort) buffer).getData(), cm);
            case DataBuffer.TYPE_SHORT:
                final short[] pixels = ((DataBufferShort) buffer).getData();
                for (int i = 0; i < pixels.length; ++i) {
                    pixels[i] = (short) (pixels[i] + 32768);
                }
                return new ShortProcessor(w, h, pixels, cm);
            case DataBuffer.TYPE_INT:
                return new FloatProcessor(w, h, ((DataBufferInt) buffer).getData());
            case DataBuffer.TYPE_FLOAT: {
                final DataBufferFloat dbFloat = (DataBufferFloat) buffer;
                return new FloatProcessor(w, h, dbFloat.getData(), cm);
            }
            case DataBuffer.TYPE_DOUBLE:
                return new FloatProcessor(w, h, ((DataBufferDouble) buffer).getData());
            case DataBuffer.TYPE_UNDEFINED:
                // ENH: Should this be reported as data problem?
                throw new IJImageIOException("Pixel type is undefined.");
            default:
                throw new IJImageIOException("Unrecognized DataBuffer data type");
        }
    }


    /**
     * Convert BufferedImage to ImageProcessor.
     *
     * @param src image to be converted.
     * @return Instance of ImageProcessor, for instance, ColorProcessor.
     * @throws IJImageIOException when unable to determine how to convert the image.
     */
    public static ImageProcessor createProcessor(final BufferedImage src) throws IJImageIOException {

        // TODO verify that short pixels are converted correctly

        final Raster raster = src.getRaster();
        ColorModel colorModel = src.getColorModel();
        final DataBuffer dataBuffer = raster.getDataBuffer();

        final int numBanks = dataBuffer.getNumBanks();
        if (numBanks > 1 && colorModel == null) {
            throw new IJImageIOException("Don't know what to do with image with no " +
                    "color model and multiple banks.");
        }

        final SampleModel sm = raster.getSampleModel();
        if (numBanks > 1 || sm.getNumBands() > 1
                ) {
            // If image has multiple banks or multiple color components, assume that it
            // is a color image and relay on AWT for proper decoding.
            return new ColorProcessor(src);
        } else if (sm.getSampleSize(0) < 8) {
            // Temporary fix for less then 8 bit images
            return new ByteProcessor(src);
        } else {
            if (!(colorModel instanceof IndexColorModel)) {
                // Image/J (as of version 1.26r) can not properly deal with non color
                // images and ColorModel that is not an instance of IndexedColorModel.
                colorModel = null;
            }

            return createProcessor(raster.getWidth(), raster.getHeight(), raster.getDataBuffer(), colorModel);
        }
    }


    /**
     * Create instance of ImagePlus from a BufferedImage.
     *
     * @param title name of the output image.
     * @param bi    source buffered image
     * @return ImagePlus object created from WritableRaster r and
     * ColorModel cm
     * @throws IJImageIOException when enable to create ImagePlus.
     * @see #create(String, WritableRaster, ColorModel)
     */
    public static ImagePlus create(final String title, final BufferedImage bi) throws IJImageIOException {
        return create(title, bi.getRaster(), bi.getColorModel());
    }

    public static ImagePlus create(final String title, final IJImageIO.ImageAndMetadata mi) throws IJImageIOException {
        ImagePlus imp = create(title, mi.image.getRaster(), mi.image.getColorModel());

        if (mi.metadata instanceof TIFFImageMetadata) {
            TIFFImageMetadata tmd = (TIFFImageMetadata) mi.metadata;

            TIFFField xResField = tmd.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION);
            if (xResField != null) {
                long[] ls = xResField.getAsRational(0);
                Calibration cal = imp.getCalibration();
                cal.pixelWidth = ls[1] / (double) ls[0];
                imp.setCalibration(cal);
            }

            TIFFField yResField = tmd.getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
            if (yResField != null) {
                long[] ls = yResField.getAsRational(0);
                Calibration cal = imp.getCalibration();
                cal.pixelHeight = ls[1] / (double) ls[0];
                imp.setCalibration(cal);
            }

            {
                TIFFField field = tmd.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION);
                if (field != null && field.getCount() > 0) {
                    String description = field.getAsString(0);
                    DescriptionStringCoder.decode(description, imp);
                }
            }
        }

        return imp;
    }

    /**
     * Create instance of ImagePlus from WritableRaster r and ColorModel cm.
     *
     * @param title name of the output image.
     * @param r     Raster containing pixel data.
     * @param cm    Image color model (can be null).
     * @return ImagePlus object created from WritableRaster r and
     * ColorModel cm
     * @throws IJImageIOException when enable to create ImagePlus.
     */
    public static ImagePlus create(final String title, final WritableRaster r, ColorModel cm)
            throws IJImageIOException {

        final DataBuffer db = r.getDataBuffer();

        final int numBanks = db.getNumBanks();
        if (numBanks > 1 && cm == null) {
            throw new IJImageIOException("Don't know what to do with image with no " +
                    "color model and multiple banks.");
        }

        final SampleModel sm = r.getSampleModel();
        final ImagePlus result;
        if (numBanks > 1 || sm.getNumBands() > 1
                ) {
            // If image has multiple banks or multiple color components, assume that it
            // is a color image and relay on AWT for proper decoding.
            final BufferedImage bi = new BufferedImage(cm, r, false, null);
            result = new ImagePlus(title, new ColorProcessor(bi));
        } else if (sm.getSampleSize(0) < 8) {
            // Temporary fix for less then 8 bit images
            final BufferedImage bi = new BufferedImage(cm, r, false, null);
            switch (bi.getType()) {
                case BufferedImage.TYPE_BYTE_GRAY:
                    result = new ImagePlus(title, new ByteProcessor(bi));
                    break;
                case BufferedImage.TYPE_BYTE_BINARY:
                    final int width = bi.getWidth();
                    final int height = bi.getHeight();
                    final ByteProcessor bp = new ByteProcessor(width, height);
                    final Raster data = bi.getData();
                    final int[] p = new int[1];
                    for (int y = 0; y < height; y++) {
                        for (int x = 0; x < width; x++) {
                            data.getPixel(x, y, p);
                            bp.set(x, y, p[0]);
                        }
                    }
                    bp.setColorModel(cm);
                    result = new ImagePlus(title, bp);
                    break;
                default:
                    throw new IJImageIOException("Unable to process buffered image of type: " + bi.getType());
            }
        } else {
            if (!(cm instanceof IndexColorModel)) {
                // Image/J (as of version 1.26r) can not properly deal with non color
                // images and ColorModel that is not an instance of IndexedColorModel.
                cm = null;
            }

            final ImageProcessor ip = createProcessor(r.getWidth(), r.getHeight(),
                    r.getDataBuffer(), cm);
            final ImagePlus im = new ImagePlus(title, ip);

            // Add calibration function for 'short' pixels
            if (db.getDataType() == DataBuffer.TYPE_SHORT) {

                final Calibration cal = new Calibration(im);
                final double[] coeff = new double[2];
                coeff[0] = -32768.0;
                coeff[1] = 1.0;
                cal.setFunction(Calibration.STRAIGHT_LINE, coeff, "gray value");
                im.setCalibration(cal);
            } else if (cm == null) {
                final Calibration cal = im.getCalibration();
                im.setCalibration(null);
                final ImageStatistics stats = im.getStatistics();
                im.setCalibration(cal);
                ip.setMinAndMax(stats.min, stats.max);
                im.updateImage();
            }

            result = im;
        }

        return result;

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy