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

com.github.jaiimageio.impl.common.ImageUtil Maven / Gradle / Ivy

Go to download

Java Advanced Imaging Image I/O Tools API core, but without the classes involved with javax.media.jai dependencies, JPEG2000 or codecLibJIIO, meaning that this library can be distributed under the modified BSD license and should be GPL compatible.

The newest version!
/*
 * $RCSfile: ImageUtil.java,v $
 *
 * 
 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 * 
 * - Redistribution of source code must retain the above copyright 
 *   notice, this  list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of 
 * contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any 
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. 
 * 
 * You acknowledge that this software is not designed or intended for 
 * use in the design, construction, operation or maintenance of any 
 * nuclear facility. 
 *
 * $Revision: 1.7 $
 * $Date: 2007/08/28 18:45:06 $
 * $State: Exp $
 */
package com.github.jaiimageio.impl.common;

import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ServiceLoader;
//import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.spi.ImageReaderWriterSpi;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.ImageReadParam;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.IIOException;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;

public class ImageUtil {
    /* XXX testing only
    public static void main(String[] args) {
        ImageTypeSpecifier bilevel =
            ImageTypeSpecifier.createIndexed(new byte[] {(byte)0, (byte)255},
                                             new byte[] {(byte)0, (byte)255},
                                             new byte[] {(byte)0, (byte)255},
                                             null, 1,
                                             DataBuffer.TYPE_BYTE);
        ImageTypeSpecifier gray =
            ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false);
        ImageTypeSpecifier grayAlpha =
            ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false,
                                               false);
        ImageTypeSpecifier rgb =
            ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                                                 new int[] {0, 1, 2},
                                                 DataBuffer.TYPE_BYTE,
                                                 false,
                                                 false);
        ImageTypeSpecifier rgba =
            ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                                                 new int[] {0, 1, 2, 3},
                                                 DataBuffer.TYPE_BYTE,
                                                 true,
                                                 false);
        ImageTypeSpecifier packed =
            ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                                            0xff000000,
                                            0x00ff0000,
                                            0x0000ff00,
                                            0x000000ff,
                                            DataBuffer.TYPE_BYTE,
                                            false);

        SampleModel bandedSM =
            new java.awt.image.BandedSampleModel(DataBuffer.TYPE_BYTE,
                                                 1, 1, 15);

        System.out.println(createColorModel(bilevel.getSampleModel()));
        System.out.println(createColorModel(gray.getSampleModel()));
        System.out.println(createColorModel(grayAlpha.getSampleModel()));
        System.out.println(createColorModel(rgb.getSampleModel()));
        System.out.println(createColorModel(rgba.getSampleModel()));
        System.out.println(createColorModel(packed.getSampleModel()));
        System.out.println(createColorModel(bandedSM));
    }
    */

    /**
     * Creates a ColorModel that may be used with the
     * specified SampleModel.  If a suitable
     * ColorModel cannot be found, this method returns
     * null.
     *
     * 

Suitable ColorModels are guaranteed to exist * for all instances of ComponentSampleModel. * For 1- and 3- banded SampleModels, the returned * ColorModel will be opaque. For 2- and 4-banded * SampleModels, the output will use alpha transparency * which is not premultiplied. 1- and 2-banded data will use a * grayscale ColorSpace, and 3- and 4-banded data a sRGB * ColorSpace. Data with 5 or more bands will have a * BogusColorSpace.

* *

An instance of DirectColorModel will be created for * instances of SinglePixelPackedSampleModel with no more * than 4 bands.

* *

An instance of IndexColorModel will be created for * instances of MultiPixelPackedSampleModel. The colormap * will be a grayscale ramp with 1 << numberOfBits * entries ranging from zero to at most 255.

* * @return An instance of ColorModel that is suitable for * the supplied SampleModel, or null. * * @throws IllegalArgumentException If sampleModel is * null. */ public static final ColorModel createColorModel(SampleModel sampleModel) { // Check the parameter. if(sampleModel == null) { throw new IllegalArgumentException("sampleModel == null!"); } // Get the data type. int dataType = sampleModel.getDataType(); // Check the data type switch(dataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_INT: case DataBuffer.TYPE_FLOAT: case DataBuffer.TYPE_DOUBLE: break; default: // Return null for other types. return null; } // The return variable. ColorModel colorModel = null; // Get the sample size. int[] sampleSize = sampleModel.getSampleSize(); // Create a Component ColorModel. if(sampleModel instanceof ComponentSampleModel) { // Get the number of bands. int numBands = sampleModel.getNumBands(); // Determine the color space. ColorSpace colorSpace = null; if(numBands <= 2) { colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY); } else if(numBands <= 4) { colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); } else { colorSpace = new BogusColorSpace(numBands); } boolean hasAlpha = (numBands == 2) || (numBands == 4); boolean isAlphaPremultiplied = false; int transparency = hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE; colorModel = new ComponentColorModel(colorSpace, sampleSize, hasAlpha, isAlphaPremultiplied, transparency, dataType); } else if (sampleModel.getNumBands() <= 4 && sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sampleModel; int[] bitMasks = sppsm.getBitMasks(); int rmask = 0; int gmask = 0; int bmask = 0; int amask = 0; int numBands = bitMasks.length; if (numBands <= 2) { rmask = gmask = bmask = bitMasks[0]; if (numBands == 2) { amask = bitMasks[1]; } } else { rmask = bitMasks[0]; gmask = bitMasks[1]; bmask = bitMasks[2]; if (numBands == 4) { amask = bitMasks[3]; } } int bits = 0; for (int i = 0; i < sampleSize.length; i++) { bits += sampleSize[i]; } return new DirectColorModel(bits, rmask, gmask, bmask, amask); } else if(sampleModel instanceof MultiPixelPackedSampleModel) { // Load the colormap with a ramp. int bitsPerSample = sampleSize[0]; int numEntries = 1 << bitsPerSample; byte[] map = new byte[numEntries]; for (int i = 0; i < numEntries; i++) { map[i] = (byte)(i*255/(numEntries - 1)); } colorModel = new IndexColorModel(bitsPerSample, numEntries, map, map, map); } return colorModel; } /** * For the case of binary data (isBinary() returns * true), return the binary data as a packed byte array. * The data will be packed as eight bits per byte with no bit offset, * i.e., the first bit in each image line will be the left-most of the * first byte of the line. The line stride in bytes will be * (int)((getWidth()+7)/8). The length of the returned * array will be the line stride multiplied by getHeight() * * @return the binary data as a packed array of bytes with zero offset * of null if the data are not binary. * @throws IllegalArgumentException if isBinary() returns * false with the SampleModel of the * supplied Raster as argument. */ public static byte[] getPackedBinaryData(Raster raster, Rectangle rect) { SampleModel sm = raster.getSampleModel(); if(!isBinary(sm)) { throw new IllegalArgumentException(I18N.getString("ImageUtil0")); } int rectX = rect.x; int rectY = rect.y; int rectWidth = rect.width; int rectHeight = rect.height; DataBuffer dataBuffer = raster.getDataBuffer(); int dx = rectX - raster.getSampleModelTranslateX(); int dy = rectY - raster.getSampleModelTranslateY(); MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm; int lineStride = mpp.getScanlineStride(); int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy); int bitOffset = mpp.getBitOffset(dx); int numBytesPerRow = (rectWidth + 7)/8; if(dataBuffer instanceof DataBufferByte && eltOffset == 0 && bitOffset == 0 && numBytesPerRow == lineStride && ((DataBufferByte)dataBuffer).getData().length == numBytesPerRow*rectHeight) { return ((DataBufferByte)dataBuffer).getData(); } byte[] binaryDataArray = new byte[numBytesPerRow*rectHeight]; int b = 0; if(bitOffset == 0) { if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); int stride = numBytesPerRow; int offset = 0; for(int y = 0; y < rectHeight; y++) { System.arraycopy(data, eltOffset, binaryDataArray, offset, stride); offset += stride; eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int xRemaining = rectWidth; int i = eltOffset; while(xRemaining > 8) { short datum = data[i++]; binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF); binaryDataArray[b++] = (byte)(datum & 0xFF); xRemaining -= 16; } if(xRemaining > 0) { binaryDataArray[b++] = (byte)((data[i] >>> 8) & 0XFF); } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int xRemaining = rectWidth; int i = eltOffset; while(xRemaining > 24) { int datum = data[i++]; binaryDataArray[b++] = (byte)((datum >>> 24) & 0xFF); binaryDataArray[b++] = (byte)((datum >>> 16) & 0xFF); binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF); binaryDataArray[b++] = (byte)(datum & 0xFF); xRemaining -= 32; } int shift = 24; while(xRemaining > 0) { binaryDataArray[b++] = (byte)((data[i] >>> shift) & 0xFF); shift -= 8; xRemaining -= 8; } eltOffset += lineStride; } } } else { // bitOffset != 0 if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); if((bitOffset & 7) == 0) { int stride = numBytesPerRow; int offset = 0; for(int y = 0; y < rectHeight; y++) { System.arraycopy(data, eltOffset, binaryDataArray, offset, stride); offset += stride; eltOffset += lineStride; } } else { // bitOffset % 8 != 0 int leftShift = bitOffset & 7; int rightShift = 8 - leftShift; for(int y = 0; y < rectHeight; y++) { int i = eltOffset; int xRemaining = rectWidth; while(xRemaining > 0) { if(xRemaining > rightShift) { binaryDataArray[b++] = (byte)(((data[i++]&0xFF) << leftShift) | ((data[i]&0xFF) >>> rightShift)); } else { binaryDataArray[b++] = (byte)((data[i]&0xFF) << leftShift); } xRemaining -= 8; } eltOffset += lineStride; } } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int bOffset = bitOffset; for(int x = 0; x < rectWidth; x += 8, bOffset += 8) { int i = eltOffset + bOffset/16; int mod = bOffset % 16; int left = data[i] & 0xFFFF; if(mod <= 8) { binaryDataArray[b++] = (byte)(left >>> (8 - mod)); } else { int delta = mod - 8; int right = data[i+1] & 0xFFFF; binaryDataArray[b++] = (byte)((left << delta) | (right >>> (16 - delta))); } } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int bOffset = bitOffset; for(int x = 0; x < rectWidth; x += 8, bOffset += 8) { int i = eltOffset + bOffset/32; int mod = bOffset % 32; int left = data[i]; if(mod <= 24) { binaryDataArray[b++] = (byte)(left >>> (24 - mod)); } else { int delta = mod - 24; int right = data[i+1]; binaryDataArray[b++] = (byte)((left << delta) | (right >>> (32 - delta))); } } eltOffset += lineStride; } } } return binaryDataArray; } /** * Returns the binary data unpacked into an array of bytes. * The line stride will be the width of the Raster. * * @throws IllegalArgumentException if isBinary() returns * false with the SampleModel of the * supplied Raster as argument. */ public static byte[] getUnpackedBinaryData(Raster raster, Rectangle rect) { SampleModel sm = raster.getSampleModel(); if(!isBinary(sm)) { throw new IllegalArgumentException(I18N.getString("ImageUtil0")); } int rectX = rect.x; int rectY = rect.y; int rectWidth = rect.width; int rectHeight = rect.height; DataBuffer dataBuffer = raster.getDataBuffer(); int dx = rectX - raster.getSampleModelTranslateX(); int dy = rectY - raster.getSampleModelTranslateY(); MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm; int lineStride = mpp.getScanlineStride(); int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy); int bitOffset = mpp.getBitOffset(dx); byte[] bdata = new byte[rectWidth*rectHeight]; int maxY = rectY + rectHeight; int maxX = rectX + rectWidth; int k = 0; if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); for(int y = rectY; y < maxY; y++) { int bOffset = eltOffset*8 + bitOffset; for(int x = rectX; x < maxX; x++) { byte b = data[bOffset/8]; bdata[k++] = (byte)((b >>> (7 - bOffset & 7)) & 0x0000001); bOffset++; } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); for(int y = rectY; y < maxY; y++) { int bOffset = eltOffset*16 + bitOffset; for(int x = rectX; x < maxX; x++) { short s = data[bOffset/16]; bdata[k++] = (byte)((s >>> (15 - bOffset % 16)) & 0x0000001); bOffset++; } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); for(int y = rectY; y < maxY; y++) { int bOffset = eltOffset*32 + bitOffset; for(int x = rectX; x < maxX; x++) { int i = data[bOffset/32]; bdata[k++] = (byte)((i >>> (31 - bOffset % 32)) & 0x0000001); bOffset++; } eltOffset += lineStride; } } return bdata; } /** * Sets the supplied Raster's data from an array * of packed binary data of the form returned by * getPackedBinaryData(). * * @throws IllegalArgumentException if isBinary() returns * false with the SampleModel of the * supplied Raster as argument. */ public static void setPackedBinaryData(byte[] binaryDataArray, WritableRaster raster, Rectangle rect) { SampleModel sm = raster.getSampleModel(); if(!isBinary(sm)) { throw new IllegalArgumentException(I18N.getString("ImageUtil0")); } int rectX = rect.x; int rectY = rect.y; int rectWidth = rect.width; int rectHeight = rect.height; DataBuffer dataBuffer = raster.getDataBuffer(); int dx = rectX - raster.getSampleModelTranslateX(); int dy = rectY - raster.getSampleModelTranslateY(); MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm; int lineStride = mpp.getScanlineStride(); int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy); int bitOffset = mpp.getBitOffset(dx); int b = 0; if(bitOffset == 0) { if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); if(data == binaryDataArray) { // Optimal case: simply return. return; } int stride = (rectWidth + 7)/8; int offset = 0; for(int y = 0; y < rectHeight; y++) { System.arraycopy(binaryDataArray, offset, data, eltOffset, stride); offset += stride; eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int xRemaining = rectWidth; int i = eltOffset; while(xRemaining > 8) { data[i++] = (short)(((binaryDataArray[b++] & 0xFF) << 8) | (binaryDataArray[b++] & 0xFF)); xRemaining -= 16; } if(xRemaining > 0) { data[i++] = (short)((binaryDataArray[b++] & 0xFF) << 8); } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int xRemaining = rectWidth; int i = eltOffset; while(xRemaining > 24) { data[i++] = (int)(((binaryDataArray[b++] & 0xFF) << 24) | ((binaryDataArray[b++] & 0xFF) << 16) | ((binaryDataArray[b++] & 0xFF) << 8) | (binaryDataArray[b++] & 0xFF)); xRemaining -= 32; } int shift = 24; while(xRemaining > 0) { data[i] |= (int)((binaryDataArray[b++] & 0xFF) << shift); shift -= 8; xRemaining -= 8; } eltOffset += lineStride; } } } else { // bitOffset != 0 int stride = (rectWidth + 7)/8; int offset = 0; if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); if((bitOffset & 7) == 0) { for(int y = 0; y < rectHeight; y++) { System.arraycopy(binaryDataArray, offset, data, eltOffset, stride); offset += stride; eltOffset += lineStride; } } else { // bitOffset % 8 != 0 int rightShift = bitOffset & 7; int leftShift = 8 - rightShift; int leftShift8 = 8 + leftShift; int mask = (byte)(255< 0) { byte datum = binaryDataArray[b++]; if (xRemaining > leftShift8) { // when all the bits in this BYTE will be set // into the data buffer. data[i] = (byte)((data[i] & mask ) | ((datum&0xFF) >>> rightShift)); data[++i] = (byte)((datum & 0xFF) << leftShift); } else if (xRemaining > leftShift) { // All the "leftShift" high bits will be set // into the data buffer. But not all the // "rightShift" low bits will be set. data[i] = (byte)((data[i] & mask ) | ((datum&0xFF) >>> rightShift)); i++; data[i] = (byte)((data[i] & mask1) | ((datum & 0xFF) << leftShift)); } else { // Less than "leftShift" high bits will be set. int remainMask = (1 << leftShift - xRemaining) - 1; data[i] = (byte)((data[i] & (mask | remainMask)) | (datum&0xFF) >>> rightShift & ~remainMask); } xRemaining -= 8; } eltOffset += lineStride; } } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); int rightShift = bitOffset & 7; int leftShift = 8 - rightShift; int leftShift16 = 16 + leftShift; int mask = (short)(~(255 << leftShift)); int mask1 = (short)(65535 << leftShift); int mask2 = (short)~mask1; for(int y = 0; y < rectHeight; y++) { int bOffset = bitOffset; int xRemaining = rectWidth; for(int x = 0; x < rectWidth; x += 8, bOffset += 8, xRemaining -= 8) { int i = eltOffset + (bOffset >> 4); int mod = bOffset & 15; int datum = binaryDataArray[b++] & 0xFF; if(mod <= 8) { // This BYTE is set into one SHORT if (xRemaining < 8) { // Mask the bits to be set. datum &= 255 << 8 - xRemaining; } data[i] = (short)((data[i] & mask) | (datum << leftShift)); } else if (xRemaining > leftShift16) { // This BYTE will be set into two SHORTs data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF)); data[++i] = (short)((datum << leftShift)&0xFFFF); } else if (xRemaining > leftShift) { // This BYTE will be set into two SHORTs; // But not all the low bits will be set into SHORT data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF)); i++; data[i] = (short)((data[i] & mask2) | ((datum << leftShift)&0xFFFF)); } else { // Only some of the high bits will be set into // SHORTs int remainMask = (1 << leftShift - xRemaining) - 1; data[i] = (short)((data[i] & (mask1 | remainMask)) | ((datum >>> rightShift)&0xFFFF & ~remainMask)); } } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); int rightShift = bitOffset & 7; int leftShift = 8 - rightShift; int leftShift32 = 32 + leftShift; int mask = 0xFFFFFFFF << leftShift; int mask1 = ~mask; for(int y = 0; y < rectHeight; y++) { int bOffset = bitOffset; int xRemaining = rectWidth; for(int x = 0; x < rectWidth; x += 8, bOffset += 8, xRemaining -= 8) { int i = eltOffset + (bOffset >> 5); int mod = bOffset & 31; int datum = binaryDataArray[b++] & 0xFF; if(mod <= 24) { // This BYTE is set into one INT int shift = 24 - mod; if (xRemaining < 8) { // Mask the bits to be set. datum &= 255 << 8 - xRemaining; } data[i] = (data[i] & (~(255 << shift))) | (datum << shift); } else if (xRemaining > leftShift32) { // All the bits of this BYTE will be set into two INTs data[i] = (data[i] & mask) | (datum >>> rightShift); data[++i] = datum << leftShift; } else if (xRemaining > leftShift) { // This BYTE will be set into two INTs; // But not all the low bits will be set into INT data[i] = (data[i] & mask) | (datum >>> rightShift); i++; data[i] = (data[i] & mask1) | (datum << leftShift); } else { // Only some of the high bits will be set into INT int remainMask = (1 << leftShift - xRemaining) - 1; data[i] = (data[i] & (mask | remainMask)) | (datum >>> rightShift & ~remainMask); } } eltOffset += lineStride; } } } } /** * Copies data into the packed array of the Raster * from an array of unpacked data of the form returned by * getUnpackedBinaryData(). * *

If the data are binary, then the target bit will be set if * and only if the corresponding byte is non-zero. * * @throws IllegalArgumentException if isBinary() returns * false with the SampleModel of the * supplied Raster as argument. */ public static void setUnpackedBinaryData(byte[] bdata, WritableRaster raster, Rectangle rect) { SampleModel sm = raster.getSampleModel(); if(!isBinary(sm)) { throw new IllegalArgumentException(I18N.getString("ImageUtil0")); } int rectX = rect.x; int rectY = rect.y; int rectWidth = rect.width; int rectHeight = rect.height; DataBuffer dataBuffer = raster.getDataBuffer(); int dx = rectX - raster.getSampleModelTranslateX(); int dy = rectY - raster.getSampleModelTranslateY(); MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm; int lineStride = mpp.getScanlineStride(); int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy); int bitOffset = mpp.getBitOffset(dx); int k = 0; if(dataBuffer instanceof DataBufferByte) { byte[] data = ((DataBufferByte)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int bOffset = eltOffset*8 + bitOffset; for(int x = 0; x < rectWidth; x++) { if(bdata[k++] != (byte)0) { data[bOffset/8] |= (byte)(0x00000001 << (7 - bOffset & 7)); } bOffset++; } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { short[] data = dataBuffer instanceof DataBufferShort ? ((DataBufferShort)dataBuffer).getData() : ((DataBufferUShort)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int bOffset = eltOffset*16 + bitOffset; for(int x = 0; x < rectWidth; x++) { if(bdata[k++] != (byte)0) { data[bOffset/16] |= (short)(0x00000001 << (15 - bOffset % 16)); } bOffset++; } eltOffset += lineStride; } } else if(dataBuffer instanceof DataBufferInt) { int[] data = ((DataBufferInt)dataBuffer).getData(); for(int y = 0; y < rectHeight; y++) { int bOffset = eltOffset*32 + bitOffset; for(int x = 0; x < rectWidth; x++) { if(bdata[k++] != (byte)0) { data[bOffset/32] |= (int)(0x00000001 << (31 - bOffset % 32)); } bOffset++; } eltOffset += lineStride; } } } public static boolean isBinary(SampleModel sm) { return sm instanceof MultiPixelPackedSampleModel && ((MultiPixelPackedSampleModel)sm).getPixelBitStride() == 1 && sm.getNumBands() == 1; } public static ColorModel createColorModel(ColorSpace colorSpace, SampleModel sampleModel) { ColorModel colorModel = null; if(sampleModel == null) { throw new IllegalArgumentException(I18N.getString("ImageUtil1")); } int numBands = sampleModel.getNumBands(); if (numBands < 1 || numBands > 4) { return null; } int dataType = sampleModel.getDataType(); if (sampleModel instanceof ComponentSampleModel) { if (dataType < DataBuffer.TYPE_BYTE || //dataType == DataBuffer.TYPE_SHORT || dataType > DataBuffer.TYPE_DOUBLE) { return null; } if (colorSpace == null) colorSpace = numBands <= 2 ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : ColorSpace.getInstance(ColorSpace.CS_sRGB); boolean useAlpha = (numBands == 2) || (numBands == 4); int transparency = useAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE; boolean premultiplied = false; int dataTypeSize = DataBuffer.getDataTypeSize(dataType); int[] bits = new int[numBands]; for (int i = 0; i < numBands; i++) { bits[i] = dataTypeSize; } colorModel = new ComponentColorModel(colorSpace, bits, useAlpha, premultiplied, transparency, dataType); } else if (sampleModel instanceof SinglePixelPackedSampleModel) { SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sampleModel; int[] bitMasks = sppsm.getBitMasks(); int rmask = 0; int gmask = 0; int bmask = 0; int amask = 0; numBands = bitMasks.length; if (numBands <= 2) { rmask = gmask = bmask = bitMasks[0]; if (numBands == 2) { amask = bitMasks[1]; } } else { rmask = bitMasks[0]; gmask = bitMasks[1]; bmask = bitMasks[2]; if (numBands == 4) { amask = bitMasks[3]; } } int[] sampleSize = sppsm.getSampleSize(); int bits = 0; for (int i = 0; i < sampleSize.length; i++) { bits += sampleSize[i]; } if (colorSpace == null) colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); colorModel = new DirectColorModel(colorSpace, bits, rmask, gmask, bmask, amask, false, sampleModel.getDataType()); } else if (sampleModel instanceof MultiPixelPackedSampleModel) { int bits = ((MultiPixelPackedSampleModel)sampleModel).getPixelBitStride(); int size = 1 << bits; byte[] comp = new byte[size]; for (int i = 0; i < size; i++) comp[i] = (byte)(255 * i / (size - 1)); colorModel = new IndexColorModel(bits, size, comp, comp, comp); } return colorModel; } public static int getElementSize(SampleModel sm) { int elementSize = DataBuffer.getDataTypeSize(sm.getDataType()); if (sm instanceof MultiPixelPackedSampleModel) { MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel)sm; return mppsm.getSampleSize(0) * mppsm.getNumBands(); } else if (sm instanceof ComponentSampleModel) { return sm.getNumBands() * elementSize; } else if (sm instanceof SinglePixelPackedSampleModel) { return elementSize; } return elementSize * sm.getNumBands(); } public static long getTileSize(SampleModel sm) { int elementSize = DataBuffer.getDataTypeSize(sm.getDataType()); if (sm instanceof MultiPixelPackedSampleModel) { MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel)sm; return (mppsm.getScanlineStride() * mppsm.getHeight() + (mppsm.getDataBitOffset() + elementSize -1) / elementSize) * ((elementSize + 7) / 8); } else if (sm instanceof ComponentSampleModel) { ComponentSampleModel csm = (ComponentSampleModel)sm; int[] bandOffsets = csm.getBandOffsets(); int maxBandOff = bandOffsets[0]; for (int i=1; i= 0) size += maxBandOff + 1; if (pixelStride > 0) size += pixelStride * (sm.getWidth() - 1); if (scanlineStride > 0) size += scanlineStride * (sm.getHeight() - 1); int[] bankIndices = csm.getBankIndices(); maxBandOff = bankIndices[0]; for (int i=1; i 0) size += pixelStride * (sm.getWidth() - 1); if (scanlineStride > 0) size += scanlineStride * (sm.getHeight() - 1); return size * ((elementSize + 7) / 8); } else return getTileSize(sm); } /** * Tests whether the color indices represent a gray-scale image with * the indicated number of bits over the color component range [0,255]. * The grayscale mapping may be inverted, i.e., 0 -> 255 and * mapSize -> 0. * * @param icm The gray-to-color mapping. * @return Whether the IndexColorModel maps index * i to ((255*i)/icm.getMapSize()-1). * @throws IllegalArgumentException if icm is * null. */ public static boolean isGrayscaleMapping(IndexColorModel icm) { if(icm == null) { throw new IllegalArgumentException("icm == null!"); } // Get colormap size and contents. int mapSize = icm.getMapSize(); byte[] r = new byte[mapSize]; byte[] g = new byte[mapSize]; byte[] b = new byte[mapSize]; icm.getReds(r); icm.getGreens(g); icm.getBlues(b); boolean isGrayToColor = true; // Check ascending ramp. for (int i = 0; i < mapSize; i++) { byte temp = (byte)(i*255/(mapSize - 1)); if (r[i] != temp || g[i] != temp || b[i] != temp) { isGrayToColor = false; break; } } if(!isGrayToColor) { isGrayToColor = true; // Check descending ramp. for (int i = 0, j = mapSize - 1; i < mapSize; i++, j--) { byte temp = (byte)(j*255/(mapSize - 1)); if (r[i] != temp || g[i] != temp || b[i] != temp) { isGrayToColor = false; break; } } } return isGrayToColor; } /** * Tests whether the color indices represent a gray-scale image. * * @param r The red channel color indices. * @param g The green channel color indices. * @param b The blue channel color indices. * @return If all the indices have 256 entries, and are identical mappings, * return true; otherwise, return false. */ public static boolean isIndicesForGrayscale(byte[] r, byte[] g, byte[] b) { if (r.length != g.length || r.length != b.length) return false; int size = r.length; if (size != 256) return false; for (int i = 0; i < size; i++) { byte temp = (byte) i; if (r[i] != temp || g[i] != temp || b[i] != temp) return false; } return true; } /** Converts the provided object to String */ public static String convertObjectToString(Object obj) { if (obj == null) return ""; String s = ""; if (obj instanceof byte[]) { byte[] bArray = (byte[])obj; for (int i = 0; i < bArray.length; i++) s += bArray[i] + " "; return s; } if (obj instanceof int[]) { int[] iArray = (int[])obj; for (int i = 0; i < iArray.length; i++) s += iArray[i] + " " ; return s; } if (obj instanceof short[]) { short[] sArray = (short[])obj; for (int i = 0; i < sArray.length; i++) s += sArray[i] + " " ; return s; } return obj.toString(); } /** Checks that the provided ImageWriter can encode * the provided ImageTypeSpecifier or not. If not, an * IIOException will be thrown. * @param writer The provided ImageWriter. * @param type The image to be tested. * @throws IIOException If the writer cannot encoded the provided image. */ public static final void canEncodeImage(ImageWriter writer, ImageTypeSpecifier type) throws IIOException { ImageWriterSpi spi = writer.getOriginatingProvider(); if(type != null && spi != null && !spi.canEncodeImage(type)) { throw new IIOException(I18N.getString("ImageUtil2")+" "+ writer.getClass().getName()); } } /** Checks that the provided ImageWriter can encode * the provided ColorModel and SampleModel. * If not, an IIOException will be thrown. * @param writer The provided ImageWriter. * @param colorModel The provided ColorModel. * @param sampleModel The provided SampleModel. * @throws IIOException If the writer cannot encoded the provided image. */ public static final void canEncodeImage(ImageWriter writer, ColorModel colorModel, SampleModel sampleModel) throws IIOException { ImageTypeSpecifier type = null; if (colorModel != null && sampleModel != null) type = new ImageTypeSpecifier(colorModel, sampleModel); canEncodeImage(writer, type); } /** * Returns whether the image has contiguous data across rows. */ public static final boolean imageIsContiguous(RenderedImage image) { SampleModel sm; if(image instanceof BufferedImage) { WritableRaster ras = ((BufferedImage)image).getRaster(); sm = ras.getSampleModel(); } else { sm = image.getSampleModel(); } if (sm instanceof ComponentSampleModel) { // Ensure image rows samples are stored contiguously // in a single bank. ComponentSampleModel csm = (ComponentSampleModel)sm; if (csm.getPixelStride() != csm.getNumBands()) { return false; } int[] bandOffsets = csm.getBandOffsets(); for (int i = 0; i < bandOffsets.length; i++) { if (bandOffsets[i] != i) { return false; } } int[] bankIndices = csm.getBankIndices(); for (int i = 0; i < bandOffsets.length; i++) { if (bankIndices[i] != 0) { return false; } } return true; } // Otherwise true if and only if it's a bilevel image with // a MultiPixelPackedSampleModel, 1 bit per pixel, and 1 bit // pixel stride. return ImageUtil.isBinary(sm); } /** * Gets the destination image type. */ // NOTE: Code shamelessly copied from ImageReader.getDestination(). public static final ImageTypeSpecifier getDestinationType(ImageReadParam param, Iterator imageTypes) throws IIOException { if (imageTypes == null || !imageTypes.hasNext()) { throw new IllegalArgumentException("imageTypes null or empty!"); } ImageTypeSpecifier imageType = null; // If param is non-null, use it if (param != null) { imageType = param.getDestinationType(); } // No info from param, use fallback image type if (imageType == null) { Object o = imageTypes.next(); if (!(o instanceof ImageTypeSpecifier)) { throw new IllegalArgumentException ("Non-ImageTypeSpecifier retrieved from imageTypes!"); } imageType = (ImageTypeSpecifier)o; } else { boolean foundIt = false; while (imageTypes.hasNext()) { ImageTypeSpecifier type = (ImageTypeSpecifier)imageTypes.next(); if (type.equals(imageType)) { foundIt = true; break; } } if (!foundIt) { throw new IIOException ("Destination type from ImageReadParam does not match!"); } } return imageType; } /** * Returns true if the given ColorSpace object * is an instance of ICC_ColorSpace but is not one of the * standard ColorSpaces returned by * ColorSpace.getInstance(). * * @param cs The ColorSpace to test. */ public static boolean isNonStandardICCColorSpace(ColorSpace cs) { boolean retval = false; try { // Check the standard ColorSpaces in decreasing order of // likelihood except check CS_PYCC last as in some JREs // PYCC.pf used not to be installed. retval = (cs instanceof ICC_ColorSpace) && !(cs.isCS_sRGB() || cs.equals(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) || cs.equals(ColorSpace.getInstance(ColorSpace.CS_GRAY)) || cs.equals(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ)) || cs.equals(ColorSpace.getInstance(ColorSpace.CS_PYCC))); } catch(IllegalArgumentException e) { // PYCC.pf not installed: ignore it - 'retval' is still 'false'. } return retval; } // Method to return JDK core ImageReaderSPI/ImageWriterSPI for a // given formatName. public static List getJDKImageReaderWriterSPI(ServiceRegistry registry, String formatName, boolean isReader) { IIORegistry iioRegistry = (IIORegistry)registry; Class spiClass; String descPart; if (isReader) { spiClass = ImageReaderSpi.class; descPart = " image reader"; } else { spiClass = ImageWriterSpi.class; descPart = " image writer"; } Iterator iter = ServiceLoader.load(spiClass).iterator(); // useOrdering String formatNames[]; ImageReaderWriterSpi provider; String desc = "standard " + formatName + descPart; String jiioPath = "com.github.jaiimageio.impl"; Locale locale = Locale.getDefault(); ArrayList list = new ArrayList(); while (iter.hasNext()) { provider = (ImageReaderWriterSpi)iter.next(); // Look for JDK core ImageWriterSpi's if (provider.getVendorName().startsWith("Sun Microsystems") && desc.equalsIgnoreCase(provider.getDescription(locale)) && // not JAI Image I/O plugins !provider.getPluginClassName().startsWith(jiioPath)) { // Get the formatNames supported by this Spi formatNames = provider.getFormatNames(); for (int i=0; i= deregisterJvmVersion && list.size() != 0) { // De-register JIIO's plug-in registry.deregisterServiceProvider(spi, category); } else { for (int i=0; i= priorityJvmVersion) { // Set JIIO plug-in to lower priority registry.setOrdering(category, list.get(i), spi); } else { // Set JIIO plug-in to higher priority registry.setOrdering(category, spi, list.get(i)); } } } } } static int getJvmVersion(String jvmSpecificationVersion) { if (jvmSpecificationVersion.startsWith("1.")) { // Skip the "1." part to get to the part of the version number that // actually changes from version to version // The assumption here is that "java.specification.version" // up to Java 1.8 is of the format "x.y" jvmSpecificationVersion = jvmSpecificationVersion.substring(2); return Integer.parseInt(jvmSpecificationVersion); } else { // http://www.oracle.com/technetwork/java/javase/9-relnote-issues-3704069.html#JDK-8085822 return Integer.parseInt(jvmSpecificationVersion); } } public static int readMultiByteInteger(ImageInputStream iis) throws IOException { int value = iis.readByte(); int result = value & 0x7f; while((value & 0x80) == 0x80) { result <<= 7; value = iis.readByte(); result |= (value & 0x7f); } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy