com.github.jaiimageio.jpeg2000.impl.J2KImageWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jai-imageio-jpeg2000 Show documentation
Show all versions of jai-imageio-jpeg2000 Show documentation
JPEG2000 support for Java Advanced Imaging Image I/O Tools API core.
This module is licensed under the [JJ2000 license](LICENSE.txt) and
is therefore NOT compatible with the GPL 3 license. It should be
compatible with the LGPL 2.1 license.
/* * $RCSfile: J2KImageWriter.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:34 $ * $State: Exp $ */ package com.github.jaiimageio.jpeg2000.impl; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; 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.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import javax.imageio.IIOException; import javax.imageio.IIOImage; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.spi.ImageWriterSpi; import javax.imageio.stream.ImageOutputStream; import jj2000.j2k.codestream.writer.FileCodestreamWriter; import jj2000.j2k.codestream.writer.HeaderEncoder; import jj2000.j2k.entropy.encoder.EntropyCoder; import jj2000.j2k.entropy.encoder.PostCompRateAllocator; import jj2000.j2k.fileformat.writer.FileFormatWriter; import jj2000.j2k.image.ImgDataConverter; import jj2000.j2k.image.Tiler; import jj2000.j2k.image.forwcomptransf.ForwCompTransf; import jj2000.j2k.quantization.quantizer.Quantizer; import jj2000.j2k.roi.encoder.ROIScaler; import jj2000.j2k.util.CodestreamManipulator; import jj2000.j2k.wavelet.analysis.ForwardWT; import com.github.jaiimageio.impl.common.ImageUtil; import com.github.jaiimageio.jpeg2000.J2KImageWriteParam; /** * The Java Image IO plugin writer for encoding a RenderedImage into * a JPEG 2000 part 1 file (JP2) format. * * This writer has the capability to (1) Losslessly encode *
* to allow the abortions be monitored byRenderedImage
s with anIndexColorModel
(for * example, bi-level or color indexed images). (2) Losslessly or lossy encode *RenderedImage
with a byte, short, ushort or integer types with * band number upto 16384. (3) Encode an image with alpha channel. * (4) Write the provided metadata into the code stream. It also can encode * a raster wrapped in the providedIIOImage
. * * The encoding process may re-tile image, clip, subsample, and select bands * using the parameters specified in theImageWriteParam
. * * @see com.sun.media.imageio.plugins.J2KImageWriteParam */ public class J2KImageWriter extends ImageWriter { /** Wrapper for the protected methodprocessImageProgress
* So it can be access from the classes which are not in *ImageWriter
hierachy. */ public void processImageProgressWrapper(float percentageDone) { processImageProgress(percentageDone); } /** When the writing is aborted,RenderedImageSrc
throws a *RuntimeException
. */ public static String WRITE_ABORTED = "Write aborted."; /** The output stream to write into */ private ImageOutputStream stream = null; /** ConstructsJ2KImageWriter
based on the provided *ImageWriterSpi
. */ public J2KImageWriter(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("J2KImageWriter0")); this.stream = (ImageOutputStream)output; } else this.stream = null; } public ImageWriteParam getDefaultWriteParam() { return new J2KImageWriteParam(); } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { return new J2KMetadata(imageType, param, this); } public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { return null; } public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { // Check arguments. if(inData == null) { throw new IllegalArgumentException("inData == null!"); } if(imageType == null) { throw new IllegalArgumentException("imageType == null!"); } // If it's one of ours, return a clone. if (inData instanceof J2KMetadata) { return (IIOMetadata)((J2KMetadata)inData).clone(); } try { J2KMetadata outData = new J2KMetadata(); List formats = Arrays.asList(inData.getMetadataFormatNames()); String format = null; if(formats.contains(J2KMetadata.nativeMetadataFormatName)) { // Initialize from native image metadata format. format = J2KMetadata.nativeMetadataFormatName; } else if(inData.isStandardMetadataFormatSupported()) { // Initialize from standard metadata form of the input tree. format = IIOMetadataFormatImpl.standardMetadataFormatName; } if(format != null) { outData.setFromTree(format, inData.getAsTree(format)); return outData; } } catch(IIOInvalidTreeException e) { return null; } return null; } public boolean canWriteRasters() { return true; } public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException { if (stream == null) { throw new IllegalStateException(I18N.getString("J2KImageWriter7")); } if (image == null) { throw new IllegalArgumentException(I18N.getString("J2KImageWriter8")); } clearAbortRequest(); processImageStarted(0); RenderedImage input = null; boolean writeRaster = image.hasRaster(); Raster raster = null; SampleModel sampleModel = null; if (writeRaster) { raster = image.getRaster(); sampleModel = raster.getSampleModel(); } else { input = image.getRenderedImage(); sampleModel = input.getSampleModel(); } checkSampleModel(sampleModel); if (param == null) param = getDefaultWriteParam(); J2KImageWriteParamJava j2kwparam = new J2KImageWriteParamJava(image, param); // Packet header cannot exist in two places. if (j2kwparam.getPackPacketHeaderInTile() && j2kwparam.getPackPacketHeaderInMain()) throw new IllegalArgumentException(I18N.getString("J2KImageWriter1")); // Lossless and encoding rate cannot be set at the same time if (j2kwparam.getLossless() && j2kwparam.getEncodingRate()!=Double.MAX_VALUE) throw new IllegalArgumentException(I18N.getString("J2KImageWriter2")); // If the source image is bilevel or color-indexed, or, the // encoding rate is Double.MAX_VALUE, use lossless if ((!writeRaster && input.getColorModel() instanceof IndexColorModel) || (writeRaster && raster.getSampleModel() instanceof MultiPixelPackedSampleModel)) { j2kwparam.setDecompositionLevel("0"); j2kwparam.setLossless(true); j2kwparam.setEncodingRate(Double.MAX_VALUE); j2kwparam.setQuantizationType("reversible"); j2kwparam.setFilters(J2KImageWriteParam.FILTER_53); } else if (j2kwparam.getEncodingRate() == Double.MAX_VALUE) { j2kwparam.setLossless(true); j2kwparam.setQuantizationType("reversible"); j2kwparam.setFilters(J2KImageWriteParam.FILTER_53); } // Gets parameters from the write parameter boolean pphTile = j2kwparam.getPackPacketHeaderInTile(); boolean pphMain = j2kwparam.getPackPacketHeaderInMain(); boolean tempSop = false; boolean tempEph = false; int[] bands = param.getSourceBands(); int ncomp = sampleModel.getNumBands(); if (bands != null) ncomp = bands.length; // create the encoding source recognized by jj2000 packages RenderedImageSrc imgsrc = null; if (writeRaster) imgsrc = new RenderedImageSrc(raster, j2kwparam, this); else imgsrc = new RenderedImageSrc(input, j2kwparam, this); // if the components signed boolean[] imsigned = new boolean[ncomp]; if (bands != null) { for (int i=0; irefx || trefy > refy) throw new IIOException(I18N.getString("J2KImageWriter4")); // Instantiate tiler Tiler imgtiler = new Tiler(imgsrc,refx,refy,trefx,trefy,tw,th); // Creates the forward component transform ForwCompTransf fctransf = new ForwCompTransf(imgtiler, j2kwparam); // Creates ImgDataConverter ImgDataConverter converter = new ImgDataConverter(fctransf); // Creates ForwardWT (forward wavelet transform) ForwardWT dwt = ForwardWT.createInstance(converter, j2kwparam); // Creates Quantizer Quantizer quant = Quantizer.createInstance(dwt,j2kwparam); // Creates ROIScaler ROIScaler rois = ROIScaler.createInstance(quant, j2kwparam); // Creates EntropyCoder EntropyCoder ecoder = EntropyCoder.createInstance(rois, j2kwparam, j2kwparam.getCodeBlockSize(), j2kwparam.getPrecinctPartition(), j2kwparam.getBypass(), j2kwparam.getResetMQ(), j2kwparam.getTerminateOnByte(), j2kwparam.getCausalCXInfo(), j2kwparam.getCodeSegSymbol(), j2kwparam.getMethodForMQLengthCalc(), j2kwparam.getMethodForMQTermination()); // Rely on rate allocator to limit amount of data File tmpFile = File.createTempFile("jiio-", ".tmp"); tmpFile.deleteOnExit(); // Creates CodestreamWriter FileCodestreamWriter bwriter = new FileCodestreamWriter(tmpFile, Integer.MAX_VALUE); // Creates the rate allocator float rate = (float)j2kwparam.getEncodingRate(); PostCompRateAllocator ralloc = PostCompRateAllocator.createInstance(ecoder, rate, bwriter, j2kwparam); // Instantiates the HeaderEncoder HeaderEncoder headenc = new HeaderEncoder(imgsrc, imsigned, dwt, imgtiler, j2kwparam, rois,ralloc); ralloc.setHeaderEncoder(headenc); // Writes header to be able to estimate header overhead headenc.encodeMainHeader(); //Initializes rate allocator, with proper header // overhead. This will also encode all the data try { ralloc.initialize(); } catch (RuntimeException e) { if (WRITE_ABORTED.equals(e.getMessage())) { bwriter.close(); tmpFile.delete(); processWriteAborted(); return; } else throw e; } // Write header (final) headenc.reset(); headenc.encodeMainHeader(); // Insert header into the codestream bwriter.commitBitstreamHeader(headenc); // Now do the rate-allocation and write result ralloc.runAndWrite(); //Done for data encoding bwriter.close(); // Calculate file length int fileLength = bwriter.getLength(); // Tile-parts and packed packet headers int pktspertp = j2kwparam.getPacketPerTilePart(); int ntiles = imgtiler.getNumTiles(); if (pktspertp>0 || pphTile || pphMain){ CodestreamManipulator cm = new CodestreamManipulator(tmpFile, ntiles, pktspertp, pphMain, pphTile, tempSop, tempEph); fileLength += cm.doCodestreamManipulation(); } // File Format int nc= imgsrc.getNumComps() ; int[] bpc = new int[nc]; for(int comp = 0; comp abortRequested J2KRenderedImage
. */ public boolean getAbortRequest() { return abortRequested(); } private void checkSampleModel(SampleModel sm) { int type = sm.getDataType(); if (type < DataBuffer.TYPE_BYTE || type > DataBuffer.TYPE_INT) throw new IllegalArgumentException(I18N.getString("J2KImageWriter5")); if (sm.getNumBands() > 16384) throw new IllegalArgumentException(I18N.getString("J2KImageWriter6")); } }