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

com.github.jaiimageio.impl.plugins.raw.RawImageWriter Maven / Gradle / Ivy

/*
 * $RCSfile: RawImageWriter.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.1 $
 * $Date: 2005/02/11 05:01:42 $
 * $State: Exp $
 */
package com.github.jaiimageio.impl.plugins.raw;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BandedSampleModel;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferDouble;
import java.awt.image.DataBufferFloat;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
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 javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;

import com.github.jaiimageio.impl.common.ImageUtil;

/**
 * The Java Image IO plugin writer for encoding a binary RenderedImage into
 * a Raw format.
 *
 * 

The encoding process may clip, subsample or select bands using the * parameters specified in the ImageWriteParam. * * Thus, when read this raw image the proper image data type * should be provided. * * @see com.github.jaiimageio.plugins.RawImageWriteParam */ //

If the destination data is packed packed, the data is written in the // order defined by the sample model. That the data is packed is defined as // (1) if the sample model is SingleSamplePackedSampleModel or // BandedSampleModel; or (2) the pixel stride or sanline stride // equals to the band number; or (3) the pixel stride equals to the band // number multiply the tile height; or (4) the scanline stride equals to the // band number multiply the tile width; or (5) the data for a band is stored // in a separate data bank. // //

Otherwise, the data is reordered in a packed pixel interleaved format, // and then written into the stream. In this case the data order may be change. // For example, the original image data is in the order of //

 //        RRRRRRRRRRRRRRRRRRRR
 //        GGGGGGGGGGGGGGGGGGGG
 //        BBBBBBBBBBBBBBBBBBBB
 //        RRRRRRRRRRRRRRRRRRRR
 //        GGGGGGGGGGGGGGGGGGGG
 //        BBBBBBBBBBBBBBBBBBBB
 // 
// // , and only the G and B bands are written in the stream. So the data in the // stream will be in the order of //
 //       GBGBGBGBGBGBGB
 // 
. public class RawImageWriter extends ImageWriter { /** The output stream to write into */ private ImageOutputStream stream = null; /** The image index in this stream. */ private int imageIndex; /** The tile width for encoding */ private int tileWidth; /** The tile height for encoding */ private int tileHeight; /** The tile grid offset for encoding */ private int tileXOffset, tileYOffset; /** The source -> destination transformation */ private int scaleX, scaleY, xOffset, yOffset; /** The source bands to be encoded. */ private int[] sourceBands = null; /** The number of components in the image */ private int numBands; /** The source raster if write raster. */ private RenderedImage input; /** The input source raster. */ private Raster inputRaster; private Rectangle destinationRegion = null; private SampleModel sampleModel; /** Coordinate transform or sub selection is needed before encoding. */ private boolean noTransform = true; private boolean noSubband = true; /** Indicates a raster rather than a RenderedImage * to be encoded. */ private boolean writeRaster = false; /** Whether can write optimally. */ private boolean optimal = false; /** The strides for pixel, band, and scanline. */ private int pxlStride, lineStride, bandStride; /** Constructs RawImageWriter based on the provided * ImageWriterSpi. */ public RawImageWriter(ImageWriterSpi originator) { super(originator); } public void setOutput(Object output) { super.setOutput(output); // validates output if (output != null) { if (!(output instanceof ImageOutputStream)) throw new IllegalArgumentException(I18N.getString("RawImageWriter0")); this.stream = (ImageOutputStream)output; } else this.stream = null; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { return null; } public IIOMetadata convertImageMetadata(IIOMetadata metadata, ImageTypeSpecifier type, ImageWriteParam param) { return null; } public boolean canWriteRasters() { return true; } public ImageWriteParam getDefaultWriteParam() { return new RawImageWriteParam(getLocale()); } public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException { clearAbortRequest(); processImageStarted(imageIndex++); if (param == null) param = getDefaultWriteParam(); writeRaster = image.hasRaster(); Rectangle sourceRegion = param.getSourceRegion(); ColorModel colorModel = null; Rectangle originalRegion = null; if (writeRaster) { inputRaster = image.getRaster(); sampleModel = inputRaster.getSampleModel(); originalRegion = inputRaster.getBounds(); } else { input = image.getRenderedImage(); sampleModel = input.getSampleModel(); originalRegion = new Rectangle(input.getMinX(), input.getMinY(), input.getWidth(), input.getHeight()); colorModel = input.getColorModel(); } if (sourceRegion == null) sourceRegion = (Rectangle)originalRegion.clone(); else sourceRegion = sourceRegion.intersection(originalRegion); if (sourceRegion.isEmpty()) throw new RuntimeException(I18N.getString("RawImageWriter1")); scaleX = param.getSourceXSubsampling(); scaleY = param.getSourceYSubsampling(); xOffset = param.getSubsamplingXOffset(); yOffset = param.getSubsamplingYOffset(); sourceRegion.translate(xOffset, yOffset); sourceRegion.width -= xOffset; sourceRegion.height -= yOffset; xOffset = sourceRegion.x % scaleX; yOffset = sourceRegion.y % scaleY; int minX = sourceRegion.x / scaleX; int minY = sourceRegion.y / scaleY; int w = (sourceRegion.width + scaleX - 1) / scaleX; int h = (sourceRegion.height + scaleY - 1) / scaleY; destinationRegion = new Rectangle(minX, minY, w, h); noTransform = destinationRegion.equals(originalRegion); tileHeight = sampleModel.getHeight(); tileWidth = sampleModel.getWidth(); if (noTransform) { if (writeRaster) { tileXOffset = inputRaster.getMinX(); tileYOffset = inputRaster.getMinY(); } else { tileXOffset = input.getTileGridXOffset(); tileYOffset = input.getTileGridYOffset(); } } else { tileXOffset = destinationRegion.x; tileYOffset = destinationRegion.y; } sourceBands = param.getSourceBands(); boolean noSubband = true; numBands = sampleModel.getNumBands(); if (sourceBands != null) { sampleModel = sampleModel.createSubsetSampleModel(sourceBands); colorModel = null; noSubband = false; numBands = sampleModel.getNumBands(); } else { sourceBands = new int[numBands]; for (int i = 0; i < numBands; i++) sourceBands[i] = i; } if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel csm = (ComponentSampleModel)sampleModel; int[] bandOffsets = csm.getBandOffsets(); bandStride = bandOffsets[0]; for (int i = 1; i < bandOffsets.length; i++) if (bandStride > bandOffsets[i]) bandStride = bandOffsets[i]; int[] bankIndices = csm.getBankIndices(); int numBank = bankIndices[0]; for (int i = 1; i < bankIndices.length; i++) if (numBank > bankIndices[i]) numBank = bankIndices[i]; pxlStride = csm.getPixelStride(); lineStride = csm.getScanlineStride(); optimal = bandStride == 0 || (pxlStride < lineStride && pxlStride == numBands) || (lineStride < pxlStride && lineStride == numBands) || (pxlStride < lineStride && lineStride == numBands * csm.getWidth()) || (lineStride < pxlStride && pxlStride == numBands * csm.getHeight()) || csm instanceof BandedSampleModel; } else if (sampleModel instanceof SinglePixelPackedSampleModel || sampleModel instanceof MultiPixelPackedSampleModel) { optimal = true; } int numXTiles = getMaxTileX() - getMinTileX() + 1; int totalTiles = numXTiles * (getMaxTileY() - getMinTileY() + 1); for (int y = getMinTileY(); y <= getMaxTileY(); y++) { for (int x = getMinTileX(); x <= getMaxTileX(); x++) { writeRaster(getTile(x, y)); float percentage = (x + y * numXTiles + 1.0F) / totalTiles; processImageProgress(percentage * 100.0F); } } stream.flush(); if (abortRequested()) processWriteAborted(); else processImageComplete(); } //XXX: just for test public int getWidth() { return destinationRegion.width; } public int getHeight() { return destinationRegion.height; } private void writeRaster(Raster raster) throws IOException { int numBank = 0; int bandStride = 0; int[] bankIndices = null; int[] bandOffsets = null; int bandSize = 0; int numBand = sampleModel.getNumBands(); int type = sampleModel.getDataType(); if (sampleModel instanceof ComponentSampleModel) { ComponentSampleModel csm = (ComponentSampleModel)sampleModel; bandOffsets = csm.getBandOffsets(); for (int i = 0; i < numBand; i++) if (bandStride < bandOffsets[i]) bandStride = bandOffsets[i]; bankIndices = csm.getBankIndices(); for (int i = 0; i < numBand; i++) if (numBank < bankIndices[i]) numBank = bankIndices[i]; bandSize = (int)ImageUtil.getBandSize(sampleModel) ; } byte[] bdata = null; short[] sdata = null; int[] idata = null; float[] fdata = null; double[] ddata = null; if (raster.getParent() != null && !sampleModel.equals(raster.getParent().getSampleModel())) { WritableRaster ras = Raster.createWritableRaster(sampleModel, new Point(raster.getMinX(), raster.getMinY())); ras.setRect(raster); raster = ras; } DataBuffer data = raster.getDataBuffer(); if (optimal) { if (numBank > 0) { //multiple data bank for (int i = 0; i < numBands; i++) { int bank = bankIndices[sourceBands[i]]; switch (type) { case DataBuffer.TYPE_BYTE: bdata = ((DataBufferByte)data).getData(bank); stream.write(bdata, 0, bdata.length); break; case DataBuffer.TYPE_SHORT: sdata = ((DataBufferShort)data).getData(bank); stream.writeShorts(sdata, 0, sdata.length); break; case DataBuffer.TYPE_USHORT: sdata = ((DataBufferUShort)data).getData(bank); stream.writeShorts(sdata, 0, sdata.length); break; case DataBuffer.TYPE_INT: idata = ((DataBufferInt)data).getData(bank); stream.writeInts(idata, 0, idata.length); break; case DataBuffer.TYPE_FLOAT: fdata = ((DataBufferFloat)data).getData(bank); stream.writeFloats(fdata, 0, fdata.length); break; case DataBuffer.TYPE_DOUBLE: ddata = ((DataBufferDouble)data).getData(bank); stream.writeDoubles(ddata, 0, ddata.length); break; } } } else { // Single data bank switch (type) { case DataBuffer.TYPE_BYTE: bdata = ((DataBufferByte)data).getData(); break; case DataBuffer.TYPE_SHORT: sdata = ((DataBufferShort)data).getData(); break; case DataBuffer.TYPE_USHORT: sdata = ((DataBufferUShort)data).getData(); break; case DataBuffer.TYPE_INT: idata = ((DataBufferInt)data).getData(); break; case DataBuffer.TYPE_FLOAT: fdata = ((DataBufferFloat)data).getData(); break; case DataBuffer.TYPE_DOUBLE: ddata = ((DataBufferDouble)data).getData(); break; } if (!noSubband && bandStride >= raster.getWidth() * raster.getHeight() * (numBands-1)) { for (int i = 0; i < numBands; i++) { int offset = bandOffsets[sourceBands[i]]; switch (type) { case DataBuffer.TYPE_BYTE: stream.write(bdata, offset, bandSize); break; case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: stream.writeShorts(sdata, offset, bandSize); break; case DataBuffer.TYPE_INT: stream.writeInts(idata, offset, bandSize); break; case DataBuffer.TYPE_FLOAT: stream.writeFloats(fdata, offset, bandSize); break; case DataBuffer.TYPE_DOUBLE: stream.writeDoubles(ddata, offset, bandSize); break; } } } else { switch (type) { case DataBuffer.TYPE_BYTE: stream.write(bdata, 0, bdata.length); break; case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: stream.writeShorts(sdata, 0, sdata.length); break; case DataBuffer.TYPE_INT: stream.writeInts(idata, 0, idata.length); break; case DataBuffer.TYPE_FLOAT: stream.writeFloats(fdata, 0, fdata.length); break; case DataBuffer.TYPE_DOUBLE: stream.writeDoubles(ddata, 0, ddata.length); break; } } } } else if (sampleModel instanceof ComponentSampleModel) { // The others, must be a ComponentSampleModel switch (type) { case DataBuffer.TYPE_BYTE: bdata = ((DataBufferByte)data).getData(); break; case DataBuffer.TYPE_SHORT: sdata = ((DataBufferShort)data).getData(); break; case DataBuffer.TYPE_USHORT: sdata = ((DataBufferUShort)data).getData(); break; case DataBuffer.TYPE_INT: idata = ((DataBufferInt)data).getData(); break; case DataBuffer.TYPE_FLOAT: fdata = ((DataBufferFloat)data).getData(); break; case DataBuffer.TYPE_DOUBLE: ddata = ((DataBufferDouble)data).getData(); break; } ComponentSampleModel csm = (ComponentSampleModel)sampleModel; int offset = csm.getOffset(raster.getMinX()-raster.getSampleModelTranslateX(), raster.getMinY()-raster.getSampleModelTranslateY()) - bandOffsets[0]; int srcSkip = pxlStride; int copyLength = 1; int innerStep = pxlStride; int width = raster.getWidth(); int height = raster.getHeight(); int innerBound = width; int outerBound = height; if (srcSkip < lineStride) { if (bandStride > pxlStride) copyLength = width; srcSkip = lineStride; } else { if (bandStride > lineStride) copyLength = height; innerStep = lineStride; innerBound = height; outerBound = width; } int writeLength = innerBound * numBands; byte[] destBBuf = null; short[] destSBuf = null; int[] destIBuf = null; float[] destFBuf = null; double[] destDBuf = null; Object srcBuf = null; Object dstBuf = null; switch (type) { case DataBuffer.TYPE_BYTE: srcBuf = bdata; dstBuf = destBBuf = new byte[writeLength]; break; case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: srcBuf = sdata; dstBuf = destSBuf = new short[writeLength]; break; case DataBuffer.TYPE_INT: srcBuf = idata; dstBuf = destIBuf = new int[writeLength]; break; case DataBuffer.TYPE_FLOAT: srcBuf = fdata; dstBuf = destFBuf = new float[writeLength]; break; case DataBuffer.TYPE_DOUBLE: srcBuf = ddata; dstBuf = destDBuf = new double[writeLength]; break; } if (copyLength > 1) { for (int i = 0; i < outerBound; i++) { for (int b = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; System.arraycopy(srcBuf, offset + bandOffset, dstBuf, b * innerBound, innerBound); } switch (type) { case DataBuffer.TYPE_BYTE: stream.write((byte[])dstBuf, 0, writeLength); break; case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: stream.writeShorts((short[])dstBuf, 0, writeLength); break; case DataBuffer.TYPE_INT: stream.writeInts((int[])dstBuf, 0, writeLength); break; case DataBuffer.TYPE_FLOAT: stream.writeFloats((float[])dstBuf, 0, writeLength); break; case DataBuffer.TYPE_DOUBLE: stream.writeDoubles((double[])dstBuf, 0, writeLength); break; } offset += srcSkip; } } else { switch (type) { case DataBuffer.TYPE_BYTE: { for (int i = 0; i < outerBound; i++) { for (int b = 0, k = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; for (int j = 0, m = offset; j < innerBound; j++, m += innerStep) // copy one sample to the destination buffer destBBuf[k++] = bdata[m + bandOffset]; } stream.write(destBBuf, 0, writeLength); offset += srcSkip; } } break; case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: { for (int i = 0; i < outerBound; i++) { for (int b = 0, k = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; for (int j = 0, m = offset; j < innerBound; j++, m += innerStep) // copy one sample to the destination buffer destSBuf[k++] = sdata[m + bandOffset]; } stream.writeShorts(destSBuf, 0, writeLength); offset += srcSkip; } } break; case DataBuffer.TYPE_INT: { for (int i = 0; i < outerBound; i++) { for (int b = 0, k = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; for (int j = 0, m = offset; j < innerBound; j++, m += innerStep) // copy one sample to the destination buffer destIBuf[k++] = idata[m + bandOffset]; } stream.writeInts(destIBuf, 0, writeLength); offset += srcSkip; } } break; case DataBuffer.TYPE_FLOAT: { for (int i = 0; i < outerBound; i++) { for (int b = 0, k = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; for (int j = 0, m = offset; j < innerBound; j++, m += innerStep) // copy one sample to the destination buffer destFBuf[k++] = fdata[m + bandOffset]; } stream.writeFloats(destFBuf, 0, writeLength); offset += srcSkip; } } break; case DataBuffer.TYPE_DOUBLE: { for (int i = 0; i < outerBound; i++) { for (int b = 0, k = 0; b < numBands; b++) { int bandOffset = bandOffsets[b]; for (int j = 0, m = offset; j < innerBound; j++, m += innerStep) // copy one sample to the destination buffer destDBuf[k++] = ddata[m + bandOffset]; } stream.writeDoubles(destDBuf, 0, writeLength); offset += srcSkip; } } break; } } } } private Raster getTile(int tileX, int tileY) { int sx = tileXOffset + tileX * tileWidth; int sy = tileYOffset + tileY * tileHeight; Rectangle bounds = new Rectangle(sx, sy, tileWidth, tileHeight); if (writeRaster) { bounds = bounds.intersection(destinationRegion); if (noTransform) { return inputRaster.createChild(bounds.x, bounds.y, bounds.width, bounds.height, bounds.x, bounds.y, sourceBands); } sx = bounds.x; sy = bounds.y; WritableRaster ras = Raster.createWritableRaster(sampleModel, new Point(sx, sy)); int x = mapToSourceX(sx); int y = mapToSourceY(sy); int minY = inputRaster.getMinY(); int maxY = inputRaster.getMinY() + inputRaster.getHeight(); int cTileWidth = bounds.width; int length = (cTileWidth - 1) * scaleX + 1; for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) { if (y < minY || y >= maxY) continue; Raster source = inputRaster.createChild(x, y, length, 1, x, y, null); int tempX = sx; for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) { for (int k = 0; k < numBands; k++) { int p = source.getSample(offset, y, sourceBands[k]); ras.setSample(tempX, sy, k, p); } } } return ras; } else { if (noTransform) { Raster ras = input.getTile(tileX, tileY); if (destinationRegion.contains(bounds) && noSubband) return ras; else { bounds = bounds.intersection(destinationRegion); return ras.createChild(bounds.x, bounds.y, bounds.width, bounds.height, bounds.x, bounds.y, sourceBands); } } bounds = bounds.intersection(destinationRegion); sx = bounds.x; sy = bounds.y; WritableRaster ras = Raster.createWritableRaster(sampleModel, new Point(sx, sy)); int x = mapToSourceX(sx); int y = mapToSourceY(sy); int minY = input.getMinY(); int maxY = input.getMinY() + input.getHeight(); int cTileWidth = bounds.width; int length = (cTileWidth -1) * scaleX + 1; for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) { if (y < minY || y >= maxY) continue; Raster source = input.getData(new Rectangle(x, y, length, 1)); int tempX = sx; for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) { for (int k = 0; k < numBands; k++) { int p = source.getSample(offset, y, sourceBands[k]); ras.setSample(tempX, sy, k, p); } } } return ras; } } private int mapToSourceX(int x) { return x * scaleX + xOffset; } private int mapToSourceY(int y) { return y * scaleY + yOffset; } private int getMinTileX() { return ToTile(destinationRegion.x, tileXOffset, tileWidth); } private int getMaxTileX() { return ToTile(destinationRegion.x + destinationRegion.width - 1, tileXOffset, tileWidth); } private int getMinTileY() { return ToTile(destinationRegion.y, tileYOffset, tileHeight); } private int getMaxTileY() { return ToTile(destinationRegion.y + destinationRegion.height - 1, tileYOffset, tileHeight); } private static int ToTile(int pos, int tileOffset, int tileSize) { pos -= tileOffset; if (pos < 0) { pos += 1 - tileSize; // force round to -infinity (ceiling) } return pos/tileSize; } public void reset() { super.reset(); stream = null; optimal = false; sourceBands = null; destinationRegion = null; noTransform = true; noSubband = true; writeRaster = false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy