Search in sources :

Example 1 with Kdu_codestream

use of kdu_jni.Kdu_codestream in project imageio-ext by geosolutions-it.

the class JP2KKakaduImageReader method setInput.

public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
    // //
    // 
    // Reset the reader prior to do anything with it
    // 
    // //
    reset();
    // //
    if (input == null)
        throw new NullPointerException("The provided input is null!");
    // Checking if the provided input is a File
    if (input instanceof File) {
        inputFile = (File) input;
    // Checking if the provided input is a FileImageInputStreamExt
    } else if (input instanceof FileImageInputStreamExt) {
        inputFile = ((FileImageInputStreamExt) input).getFile();
    // Checking if the provided input is a URL
    } else if (input instanceof URL) {
        final URL tempURL = (URL) input;
        if (tempURL.getProtocol().equalsIgnoreCase("file")) {
            inputFile = Utilities.urlToFile(tempURL);
        }
    } else if (input instanceof ImageInputStream) {
        try {
            inputFile = File.createTempFile("buffer", ".j2c");
            FileOutputStream fos = new FileOutputStream(inputFile);
            final byte[] buff = new byte[TEMP_BUFFER_SIZE];
            int bytesRead = 0;
            while ((bytesRead = ((ImageInputStream) input).read(buff)) != -1) fos.write(buff, 0, bytesRead);
            fos.close();
            input = inputFile;
            deleteInputFile = true;
        } catch (IOException ioe) {
            throw new RuntimeException("Unable to create a temp file", ioe);
        }
    }
    if (this.inputFile == null)
        throw new IllegalArgumentException("Invalid source provided.");
    fileName = inputFile.getAbsolutePath();
    // //
    // 
    // Open it up
    // 
    // //
    // Must be disposed last
    Kdu_simple_file_source rawSource = null;
    // Dispose
    final Jp2_family_src familySource = new Jp2_family_src();
    // last
    // Dispose in the
    final Jpx_source wrappedSource = new Jpx_source();
    // middle
    Kdu_codestream codestream = new Kdu_codestream();
    try {
        // Open input file as raw codestream or a JP2/JPX file
        familySource.Open(fileName);
        final int success = wrappedSource.Open(familySource, true);
        if (success < 0) {
            // //
            // 
            // Must open as raw file
            // 
            // //
            familySource.Close();
            wrappedSource.Close();
            rawSource = new Kdu_simple_file_source(fileName);
            if (rawSource != null) {
                if (fileName != null) {
                    FileInputStream fis = new FileInputStream(new File(fileName));
                    byte[] jp2SocMarker = new byte[2];
                    fis.read(jp2SocMarker);
                    if (jp2SocMarker[0] != (byte) 0xFF || jp2SocMarker[1] != (byte) 0x4F)
                        throw new IllegalArgumentException("Not a JP2K source.");
                    fis.close();
                }
                isRawSource = true;
                if (LOGGER.isLoggable(Level.FINE))
                    LOGGER.fine("Detected raw source");
                numImages = 1;
            }
        } else {
            // we have a valid jp2/jpx file
            isRawSource = false;
            // //
            // 
            // get the number of codestreams in this jpeg2000 file
            // 
            // //
            final int[] count = new int[1];
            if (wrappedSource.Count_codestreams(count))
                numImages = count[0];
            else
                numImages = 0;
        }
        if (!isRawSource)
            fileWalker = new JP2KFileWalker(this.fileName);
        for (int cs = 0; cs < numImages; cs++) {
            if (isRawSource) {
                codestream.Create(rawSource);
            } else {
                final Jpx_codestream_source stream = wrappedSource.Access_codestream(cs);
                final Jpx_input_box inputbox = stream.Open_stream();
                codestream.Create(inputbox);
            }
            final JP2KCodestreamProperties codestreamP = new JP2KCodestreamProperties();
            // //
            // 
            // Initializing size-related properties (Image dims, Tiles)
            // 
            // //
            final Kdu_dims imageDims = new Kdu_dims();
            codestream.Access_siz().Finalize_all();
            codestream.Get_dims(-1, imageDims, false);
            final Kdu_dims tileSize = new Kdu_dims();
            codestream.Get_tile_dims(new Kdu_coords(0, 0), -1, tileSize);
            int tileWidth = tileSize.Access_size().Get_x();
            int tileHeight = tileSize.Access_size().Get_y();
            // maximum integer
            if ((float) tileWidth * tileHeight >= Integer.MAX_VALUE) {
                // TODO: Customize these settings
                tileHeight = 1024;
                tileWidth = 1024;
            }
            codestreamP.setTileWidth(tileWidth);
            codestreamP.setTileHeight(tileHeight);
            codestreamP.setWidth(imageDims.Access_size().Get_x());
            codestreamP.setHeight(imageDims.Access_size().Get_y());
            final int nComponents = codestream.Get_num_components();
            int maxBitDepth = -1;
            int[] componentIndexes = new int[nComponents];
            int[] bitsPerComponent = new int[nComponents];
            boolean isSigned = false;
            for (int i = 0; i < nComponents; i++) {
                // TODO: FIX THIS
                bitsPerComponent[i] = codestream.Get_bit_depth(i);
                if (maxBitDepth < bitsPerComponent[i]) {
                    maxBitDepth = bitsPerComponent[i];
                }
                isSigned |= codestream.Get_signed(i);
                componentIndexes[i] = i;
            }
            codestreamP.setNumComponents(nComponents);
            codestreamP.setBitsPerComponent(bitsPerComponent);
            codestreamP.setComponentIndexes(componentIndexes);
            codestreamP.setMaxBitDepth(maxBitDepth);
            codestreamP.setSigned(isSigned);
            // Initializing Resolution levels and Quality Layers
            final int sourceDWTLevels = codestream.Get_min_dwt_levels();
            codestreamP.setSourceDWTLevels(sourceDWTLevels);
            codestreamP.setMaxSupportedSubSamplingFactor(1 << sourceDWTLevels);
            Kdu_coords tileCoords = new Kdu_coords();
            tileCoords.Set_x(0);
            tileCoords.Set_y(0);
            codestream.Open_tile(tileCoords);
            codestreamP.setMaxAvailableQualityLayers(codestream.Get_max_tile_layers());
            initializeSampleModelAndColorModel(codestreamP);
            codestream.Destroy();
            multipleCodestreams.add(codestreamP);
            if (isRawSource)
                break;
        }
    } catch (KduException e) {
        throw new RuntimeException("Error caused by a Kakadu exception during creation of key objects!", e);
    } catch (FileNotFoundException e) {
        throw new RuntimeException("Exception occurred during kakadu reader initialization", e);
    } catch (IOException e) {
        throw new RuntimeException("Exception occurred during kakadu reader initialization", e);
    } finally {
        if (!isRawSource && wrappedSource != null) {
            try {
                if (wrappedSource.Exists())
                    wrappedSource.Close();
            } catch (Throwable e) {
            // yeah I am eating this
            }
            try {
                wrappedSource.Native_destroy();
            } catch (Throwable e) {
            // yeah I am eating this
            }
            if (familySource != null) {
                try {
                    if (familySource.Exists())
                        familySource.Close();
                } catch (Throwable e) {
                // yeah I am eating this
                }
                try {
                    familySource.Native_destroy();
                } catch (Throwable e) {
                // yeah I am eating this
                }
            }
        } else if (isRawSource && rawSource != null) {
            try {
                if (wrappedSource.Exists())
                    wrappedSource.Close();
            } catch (Throwable e) {
            // yeah I am eating this
            }
        }
    }
    // //
    // 
    // Setting input for superclass
    // 
    // //
    super.setInput(input, seekForwardOnly, ignoreMetadata);
}
Also used : FileNotFoundException(java.io.FileNotFoundException) URL(java.net.URL) Jpx_source(kdu_jni.Jpx_source) Kdu_dims(kdu_jni.Kdu_dims) FileImageInputStreamExt(it.geosolutions.imageio.stream.input.FileImageInputStreamExt) Kdu_codestream(kdu_jni.Kdu_codestream) KduException(kdu_jni.KduException) Kdu_simple_file_source(kdu_jni.Kdu_simple_file_source) Jpx_codestream_source(kdu_jni.Jpx_codestream_source) ImageInputStream(javax.imageio.stream.ImageInputStream) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) FileOutputStream(java.io.FileOutputStream) Kdu_coords(kdu_jni.Kdu_coords) Jpx_input_box(kdu_jni.Jpx_input_box) Jp2_family_src(kdu_jni.Jp2_family_src) File(java.io.File)

Example 2 with Kdu_codestream

use of kdu_jni.Kdu_codestream in project imageio-ext by geosolutions-it.

the class JP2KKakaduImageReader method read.

/**
 * Read the image and returns it as a complete <code>BufferedImage</code>,
 * using a supplied <code>ImageReadParam</code>.
 *
 * @param imageIndex
 *                the index of the desired image.
 */
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    checkImageIndex(imageIndex);
    // ///////////////////////////////////////////////////////////
    // 
    // STEP 0.
    // -------
    // Setting local variables for i-th codestream
    // 
    // ///////////////////////////////////////////////////////////
    JP2KCodestreamProperties codestreamP = multipleCodestreams.get(imageIndex);
    final int maxAvailableQualityLayers = codestreamP.getMaxAvailableQualityLayers();
    final int[] componentIndexes = codestreamP.getComponentIndexes();
    final int nComponents = codestreamP.getNumComponents();
    final int maxBitDepth = codestreamP.getMaxBitDepth();
    final int height = codestreamP.getHeight();
    final int width = codestreamP.getWidth();
    final ColorModel cm = codestreamP.getColorModel();
    final SampleModel sm = codestreamP.getSampleModel();
    Kdu_simple_file_source localRawSource = null;
    Jp2_family_src localFamilySource = null;
    Jpx_source localWrappedSource = null;
    // get a default set of ImageReadParam if needed.
    if (param == null)
        param = getDefaultReadParam();
    // ///////////////////////////////////////////////////////////
    // 
    // STEP 1.
    // -------
    // local variables initialization
    // 
    // ///////////////////////////////////////////////////////////
    // The destination image properties
    final Rectangle destinationRegion = new Rectangle(0, 0, -1, -1);
    // The source region image properties
    final Rectangle sourceRegion = new Rectangle(0, 0, -1, -1);
    // The properties of the image we need to load from Kakadu
    final Rectangle requiredRegion = new Rectangle(0, 0, -1, -1);
    // Subsampling Factors
    int xSubsamplingFactor = -1;
    int ySubsamplingFactor = -1;
    // boolean used to specify when resampling is required (as an instance,
    // different subsampling factors (xSS != ySS) require resampling)
    boolean resamplingIsRequired = false;
    // ///////////////////////////////////////////////////////////
    if (!(param instanceof JP2KKakaduImageReadParam)) {
        // The parameter is not of JP2KakaduImageReadParam type but
        // simply an ImageReadParam instance (the superclass)
        // we need to build a proper JP2KakaduImageReadParam prior
        // to start parameters parsing.
        JP2KKakaduImageReadParam jp2kParam = (JP2KKakaduImageReadParam) getDefaultReadParam();
        jp2kParam.initialize(param);
        param = jp2kParam;
    }
    // selected interpolation type
    final int interpolationType = ((JP2KKakaduImageReadParam) param).getInterpolationType();
    // specified quality layers
    int qualityLayers = ((JP2KKakaduImageReadParam) param).getQualityLayers();
    if (qualityLayers != -1) {
        // qualityLayers != -1 means that the user have specified that value
        if (qualityLayers > maxAvailableQualityLayers)
            // correct the user defined qualityLayers parameter if this
            // exceed the max number of available quality layers
            qualityLayers = maxAvailableQualityLayers;
    } else
        qualityLayers = 0;
    // SubSampling variables initialization
    xSubsamplingFactor = param.getSourceXSubsampling();
    ySubsamplingFactor = param.getSourceYSubsampling();
    // //
    // Retrieving Information about Source Region and doing additional
    // initialization operations.
    // //
    computeRegions(width, height, param, sourceRegion, destinationRegion);
    // ////////////////////////////////////////////////////////////////////
    // 
    // STEP 3.
    // -------
    // check if the image need to be resampled/rescaled and find the proper
    // scale factor as well as the size of the required region we need to
    // provide to kakadu.
    // 
    // ////////////////////////////////////////////////////////////////////
    final int[] resolutionInfo = new int[2];
    resamplingIsRequired = getRequiredRegionsAndResolutions(codestreamP, xSubsamplingFactor, ySubsamplingFactor, sourceRegion, destinationRegion, requiredRegion, resolutionInfo);
    final int nDiscardLevels = resolutionInfo[1];
    // Setting the destination Buffer Size which will contains the samples
    // coming from stripe_decompressor
    BufferedImage bi = null;
    try {
        DataBuffer imageBuffer = null;
        // ////////////////////////////////////////////////////////////////
        // 
        // STEP 4.
        // -------
        // Initialize sources and codestream
        // ////////////////////////////////////////////////////////////////
        // Opening data source
        Kdu_codestream codestream = new Kdu_codestream();
        if (!isRawSource) {
            localFamilySource = new Jp2_family_src();
            localWrappedSource = new Jpx_source();
            localFamilySource.Open(fileName);
            localWrappedSource.Open(localFamilySource, true);
            final Jpx_codestream_source stream = localWrappedSource.Access_codestream(imageIndex);
            final Jpx_input_box inputbox = stream.Open_stream();
            codestream.Create(inputbox);
        } else {
            localRawSource = new Kdu_simple_file_source(fileName);
            codestream.Create(localRawSource);
        }
        // ////////////////////////////////////////////////////////////////
        // 
        // STEP 5.
        // -------
        // Set parameters for stripe decompression
        // ////////////////////////////////////////////////////////////////
        final Kdu_dims dims = new Kdu_dims();
        codestream.Apply_input_restrictions(0, nComponents, nDiscardLevels, qualityLayers, null, Kdu_global.KDU_WANT_OUTPUT_COMPONENTS);
        if (LOGGER.isLoggable(Level.FINE)) {
            final Kdu_dims original_dims = new Kdu_dims();
            codestream.Get_dims(-1, original_dims);
            StringBuilder sb = new StringBuilder("Original Hi-Res Image Region is: x=").append(original_dims.Access_pos().Get_x()).append("  y=").append(original_dims.Access_pos().Get_y()).append("  w=").append(original_dims.Access_size().Get_x()).append("  h=").append(original_dims.Access_size().Get_y());
            LOGGER.fine(sb.toString());
        }
        final Kdu_dims dimsROI = new Kdu_dims();
        codestream.Get_dims(0, dims);
        if (LOGGER.isLoggable(Level.FINE)) {
            final int mappedX = dims.Access_pos().Get_x();
            final int mappedY = dims.Access_pos().Get_y();
            final int mappedWidth = dims.Access_size().Get_x();
            final int mappedHeight = dims.Access_size().Get_y();
            StringBuilder sb = new StringBuilder("Mapped Region is: x=").append(mappedX).append("  y=").append(mappedY).append("  w=").append(mappedWidth).append("  h=").append(mappedHeight);
            LOGGER.fine(sb.toString());
        }
        // Checks on the required region and mapped region, in compliance with
        // Formula 11.1 of Taubman's JPEG2000 compression book.
        checkBounds(dims, requiredRegion);
        final int destBufferSize = (requiredRegion.height * requiredRegion.width) * nComponents;
        setDimsForCrop(dims, requiredRegion);
        // Getting a region of interest.
        codestream.Map_region(0, dims, dimsROI);
        if (LOGGER.isLoggable(Level.FINE)) {
            final int mappedROIWidth = dimsROI.Access_size().Get_x();
            final int mappedROIHeight = dimsROI.Access_size().Get_y();
            final int mappedROIX = dimsROI.Access_pos().Get_x();
            final int mappedROIY = dimsROI.Access_pos().Get_y();
            StringBuilder sb = new StringBuilder("ROI Region is: x=").append(mappedROIX).append("  y=").append(mappedROIY).append("  w=").append(mappedROIWidth).append("  h=").append(mappedROIHeight);
            LOGGER.fine(sb.toString());
        }
        codestream.Apply_input_restrictions(nComponents, componentIndexes, nDiscardLevels, qualityLayers, dimsROI, Kdu_global.KDU_WANT_OUTPUT_COMPONENTS);
        // //
        // 
        // Setting parameters for stripe decompression
        // 
        // //
        // Array with one entry for each image component, identifying the
        // number of lines to be decompressed for that component in the
        // present call. All entries must be non-negative.
        final int[] stripeHeights = new int[nComponents];
        // Array with one entry for each image component, identifying
        // the separation between horizontally adjacent samples within the
        // corresponding stripe buffer found in the stripe_bufs array.
        final int[] sampleGap = new int[nComponents];
        // Array with one entry for each image component, identifying
        // the separation between vertically adjacent samples within the
        // corresponding stripe buffer found in the stripe_bufs array.
        final int[] rowGap = new int[nComponents];
        // Array with one entry for each image component, identifying the
        // position of the first sample of that component within the buffer
        // array.
        final int[] sampleOffset = new int[nComponents];
        // Array with one entry for each image component, identifying the
        // number of significant bits used to represent each sample.
        // There is no implied connection between the precision values, P,
        // and the bit-depth, B, of each image component, as found in the
        // code-stream's SIZ marker segment, and returned via
        // kdu_codestream::get_bit_depth. The original image sample
        // bit-depth, B, may be larger or smaller than the value of P
        // supplied via the precisions argument. The samples returned by
        // pull_stripe all have a nominally signed representation unless
        // otherwise indicated by a non-NULL isSigned argument
        final int[] precision = new int[nComponents];
        for (int component = 0; component < nComponents; component++) {
            stripeHeights[component] = requiredRegion.height;
            sampleGap[component] = nComponents;
            rowGap[component] = requiredRegion.width * nComponents;
            sampleOffset[component] = component;
            precision[component] = codestream.Get_bit_depth(component);
        }
        // ////////////////////////////////////////////////////////////////
        // 
        // STEP 6.
        // -------
        // Stripe decompressor data loading
        // ////////////////////////////////////////////////////////////////
        Kdu_stripe_decompressor decompressor = new Kdu_stripe_decompressor();
        decompressor.Start(codestream);
        /**
         * @todo: actually, we only handle fixed point types. No float or
         *        double data are handled.
         */
        if (maxBitDepth <= 8) {
            final byte[] bufferValues = new byte[destBufferSize];
            decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision);
            imageBuffer = new DataBufferByte(bufferValues, destBufferSize);
        } else if (maxBitDepth > 8 && maxBitDepth <= 16) {
            final boolean[] isSigned = new boolean[nComponents];
            for (int i = 0; i < isSigned.length; i++) isSigned[i] = codestream.Get_signed(i);
            final short[] bufferValues = new short[destBufferSize];
            decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision, isSigned);
            imageBuffer = new DataBufferUShort(bufferValues, destBufferSize);
        } else if (maxBitDepth > 16 && maxBitDepth <= 32) {
            final int[] bufferValues = new int[destBufferSize];
            decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision);
            imageBuffer = new DataBufferInt(bufferValues, destBufferSize);
        }
        // ////////////////////////////////////////////////////////////////
        // 
        // STEP 6.bis
        // ----------
        // Kakadu items deallocation/finalization
        // ////////////////////////////////////////////////////////////////
        decompressor.Finish();
        decompressor.Native_destroy();
        codestream.Destroy();
        // ////////////////////////////////////////////////////////////////
        // 
        // STEP 7.
        // -------
        // BufferedImage Creation
        // 
        // ////////////////////////////////////////////////////////////////
        final SampleModel sampleModel = sm.createCompatibleSampleModel(requiredRegion.width, requiredRegion.height);
        bi = new BufferedImage(cm, Raster.createWritableRaster(sampleModel, imageBuffer, null), false, null);
    } catch (KduException e) {
        throw new RuntimeException("Error caused by a Kakadu exception during creation of key objects! ", e);
    } catch (RasterFormatException rfe) {
        throw new RuntimeException("Error during raster creation", rfe);
    } finally {
        if (!isRawSource) {
            try {
                if (localWrappedSource.Exists())
                    localWrappedSource.Close();
            } catch (KduException e) {
            }
            localWrappedSource.Native_destroy();
            try {
                if (localFamilySource.Exists())
                    localFamilySource.Close();
            } catch (KduException e) {
            }
            localFamilySource.Native_destroy();
        } else {
            localRawSource.Native_destroy();
        }
        if (deleteInputFile && inputFile.exists()) {
            inputFile.delete();
        }
    }
    // ////////////////////////////////////////////////////////////////
    if (resamplingIsRequired && bi != null)
        return KakaduUtilities.subsampleImage(codestreamP.getColorModel(), bi, destinationRegion.width, destinationRegion.height, interpolationType);
    return bi;
}
Also used : Kdu_stripe_decompressor(kdu_jni.Kdu_stripe_decompressor) Rectangle(java.awt.Rectangle) DataBufferInt(java.awt.image.DataBufferInt) DataBufferByte(java.awt.image.DataBufferByte) BufferedImage(java.awt.image.BufferedImage) Jpx_source(kdu_jni.Jpx_source) IndexColorModel(java.awt.image.IndexColorModel) ComponentColorModel(java.awt.image.ComponentColorModel) ColorModel(java.awt.image.ColorModel) Kdu_dims(kdu_jni.Kdu_dims) Kdu_codestream(kdu_jni.Kdu_codestream) DataBufferUShort(java.awt.image.DataBufferUShort) DataBuffer(java.awt.image.DataBuffer) KduException(kdu_jni.KduException) Kdu_simple_file_source(kdu_jni.Kdu_simple_file_source) Jpx_codestream_source(kdu_jni.Jpx_codestream_source) SampleModel(java.awt.image.SampleModel) PixelInterleavedSampleModel(java.awt.image.PixelInterleavedSampleModel) MultiPixelPackedSampleModel(java.awt.image.MultiPixelPackedSampleModel) Jpx_input_box(kdu_jni.Jpx_input_box) Jp2_family_src(kdu_jni.Jp2_family_src) RasterFormatException(java.awt.image.RasterFormatException)

Example 3 with Kdu_codestream

use of kdu_jni.Kdu_codestream in project imageio-ext by geosolutions-it.

the class JP2KKakaduImageWriter method write.

@Override
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
    // ////////////////////////////////////////////////////////////////////
    // 
    // Variables initialization
    // 
    // ////////////////////////////////////////////////////////////////////
    final String fileName = outputFile.getAbsolutePath();
    JP2KKakaduImageWriteParam jp2Kparam;
    final boolean writeCodeStreamOnly;
    final double quality;
    int cLayers = 1;
    int cLevels;
    final boolean cycc;
    byte[] geoJp2 = null;
    final boolean orgGen_plt;
    int orgGen_tlm = JP2KKakaduImageWriteParam.UNSPECIFIED_ORG_GEN_TLM;
    int qGuard = -1;
    String orgT_parts = null;
    String cPrecincts = null;
    boolean setTiling = false;
    int tileW = Integer.MIN_VALUE;
    int tileH = Integer.MIN_VALUE;
    ProgressionOrder cOrder = null;
    double[] bitRates = null;
    boolean addCommentMarker = ADD_COMMENT_MARKER;
    int sProfile = JP2KKakaduImageWriteParam.DEFAULT_SPROFILE;
    Compression compression = Compression.UNDEFINED;
    // //
    if (param == null) {
        param = getDefaultWriteParam();
    }
    if (param instanceof JP2KKakaduImageWriteParam) {
        jp2Kparam = (JP2KKakaduImageWriteParam) param;
        writeCodeStreamOnly = jp2Kparam.isWriteCodeStreamOnly();
        bitRates = jp2Kparam.getQualityLayersBitRates();
        double q = jp2Kparam.getQuality();
        if (q < 0.01) {
            q = 0.01;
            if (LOGGER.isLoggable(Level.FINE))
                LOGGER.fine("Quality level should be in the range 0.01 - 1. /n Reassigning it to 0.01");
        }
        quality = q;
        geoJp2 = jp2Kparam.getGeoJp2();
        setTiling = jp2Kparam.getTilingMode() == ImageWriteParam.MODE_EXPLICIT;
        if (setTiling) {
            tileH = jp2Kparam.getTileHeight();
            tileW = jp2Kparam.getTileWidth();
        }
        // COD PARAMS
        cOrder = jp2Kparam.getcOrder();
        cPrecincts = jp2Kparam.getcPrecincts();
        cLevels = jp2Kparam.getCLevels();
        cLayers = jp2Kparam.getQualityLayers();
        // ORG PARAMS
        orgGen_plt = jp2Kparam.isOrgGen_plt();
        orgGen_tlm = jp2Kparam.getOrgGen_tlm();
        orgT_parts = jp2Kparam.getOrgT_parts();
        qGuard = jp2Kparam.getqGuard();
        addCommentMarker &= jp2Kparam.isAddCommentMarker();
        sProfile = jp2Kparam.getsProfile();
        compression = jp2Kparam.getCompression();
        if (bitRates != null && bitRates.length != cLayers) {
            throw new IllegalArgumentException(" Specified bitRates parameter's length " + bitRates.length + " should match the quality layers parameter " + "(cLayers): " + cLayers);
        }
        if (compression != null) {
            switch(compression) {
                case LOSSY:
                    if (bitRates != null) {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Applying lossy compression leveraging on provided quality bit rates");
                        }
                    } else {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Applying lossy compression leveraging on quality factor");
                        }
                    }
                    break;
                case NUMERICALLY_LOSSLESS:
                    if (bitRates != null) {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Applying numerically lossless compression leveraging on " + "provided quality bit rates");
                        }
                        if (KakaduUtilities.notEqual(bitRates[bitRates.length - 1], 0)) {
                            throw new IllegalArgumentException("Asking for a Numerically Lossless " + "but the last quality layer's bit rate should be 0 " + " instead of " + bitRates[bitRates.length - 1]);
                        }
                    } else {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Applying numerically lossless compression");
                        }
                    }
                    break;
            }
        } else {
            compression = Compression.UNDEFINED;
        }
    } else {
        orgGen_plt = false;
        writeCodeStreamOnly = true;
        quality = JP2KKakaduImageWriteParam.DEFAULT_QUALITY;
        cLevels = JP2KKakaduImageWriteParam.DEFAULT_C_LEVELS;
    }
    // ////////////////////////////////////////////////////////////////////
    // 
    // Image properties initialization
    // 
    // ////////////////////////////////////////////////////////////////////
    final RenderedImage inputRenderedImage = image.getRenderedImage();
    final int sourceWidth = inputRenderedImage.getWidth();
    final int sourceHeight = inputRenderedImage.getHeight();
    final int sourceMinX = inputRenderedImage.getMinX();
    final int sourceMinY = inputRenderedImage.getMinY();
    final SampleModel sm = inputRenderedImage.getSampleModel();
    final int dataType = sm.getDataType();
    final boolean isDataSigned = (dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_BYTE);
    final ColorModel colorModel = inputRenderedImage.getColorModel();
    final boolean hasPalette = colorModel instanceof IndexColorModel ? true : false;
    final int[] numberOfBits = colorModel.getComponentSize();
    // The number of bytes used by header, markers, boxes
    int bytesOverHead = 0;
    // We suppose all bands share the same bitDepth
    final int bits = numberOfBits[0];
    int nComponents = sm.getNumBands();
    // Array to store optional look up table entries
    byte[] reds = null;
    byte[] greens = null;
    byte[] blues = null;
    // //
    if (hasPalette) {
        cycc = false;
        cLevels = 1;
        IndexColorModel icm = (IndexColorModel) colorModel;
        final int lutSize = icm.getMapSize();
        final int numColorComponents = colorModel.getNumColorComponents();
        // Updating the number of components to write as RGB (3 bands)
        if (writeCodeStreamOnly) {
            nComponents = numColorComponents;
            // //
            // 
            // Caching look up table for future accesses.
            // 
            // //
            reds = new byte[lutSize];
            blues = new byte[lutSize];
            greens = new byte[lutSize];
            icm.getReds(reds);
            icm.getGreens(greens);
            icm.getBlues(blues);
        } else {
            // adding pclr and cmap boxes overhead bytes
            // NE + NC + Bi
            bytesOverHead += (4 + 2 + numColorComponents + 1);
            // pclr LUT
            bytesOverHead += lutSize * numColorComponents + 4;
            // cmap
            bytesOverHead += 20;
        }
    } else if (quality == 1) {
        cycc = false;
    } else {
        cycc = true;
    }
    // //
    // 
    // Setting regions and sizes and retrieving parameters
    // 
    // //
    final int xSubsamplingFactor = param.getSourceXSubsampling();
    final int ySubsamplingFactor = param.getSourceYSubsampling();
    final Rectangle originalBounds = new Rectangle(sourceMinX, sourceMinY, sourceWidth, sourceHeight);
    final Rectangle imageBounds = (Rectangle) originalBounds.clone();
    final Dimension destSize = new Dimension();
    KakaduUtilities.computeRegions(imageBounds, destSize, param);
    boolean resampleInputImage = false;
    if (xSubsamplingFactor != 1 || ySubsamplingFactor != 1 || !imageBounds.equals(originalBounds)) {
        resampleInputImage = true;
    }
    // Destination sizes
    final int destinationWidth = destSize.width;
    final int destinationHeight = destSize.height;
    final int rowSize = (destinationWidth * nComponents);
    final int bandSize = destinationHeight * destinationWidth;
    final int imageSize = bandSize * nComponents;
    // ////////////////////////////////////////////////////////////////////
    // 
    // Kakadu objects initialization
    // 
    // ////////////////////////////////////////////////////////////////////
    Kdu_compressed_target outputTarget = null;
    Jp2_target target = null;
    Jp2_family_tgt familyTarget = null;
    // Setting decomposition levels
    cLevels = setDecompositionLevels(cLevels, destinationWidth);
    try {
        if (writeCodeStreamOnly) {
            // Open a simple file target
            outputTarget = new Kdu_simple_file_target();
            ((Kdu_simple_file_target) outputTarget).Open(fileName);
            final int extensionIndex = fileName.lastIndexOf(".");
            final String suffix = fileName.substring(extensionIndex, fileName.length());
            if (suffix.equalsIgnoreCase(".jp2") && LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("When writing codestreams, the \".j2c\" file suffix is suggested instead of \".jp2\"");
            }
        } else {
            familyTarget = new Jp2_family_tgt();
            familyTarget.Open(fileName);
            target = new Jp2_target();
            target.Open(familyTarget);
            // Adding signature, fileType, image header, Jp2Header box bytes
            // + jp2c marker.
            bytesOverHead += 84;
            if (geoJp2 != null) {
                bytesOverHead += geoJp2.length;
            }
        }
        bytesOverHead += addMarkerBytes(nComponents, destinationWidth, destinationHeight, tileW, tileH, orgGen_tlm, addCommentMarker);
        if (bytesOverHead >= imageSize) {
            bytesOverHead = 0;
        }
        final long qualityLayersSize = bitRates != null ? imageSize : (long) ((imageSize - bytesOverHead) * quality * bits * KakaduUtilities.BIT_TO_BYTE_FACTOR);
        // //
        // 
        // Parameters initialization
        // 
        // //
        final Kdu_codestream codeStream = new Kdu_codestream();
        Siz_params params = new Siz_params();
        initializeParams(params, destinationWidth, destinationHeight, bits, nComponents, isDataSigned, tileW, tileH, sProfile);
        // Create a codestream on the proper output object.
        if (writeCodeStreamOnly) {
            codeStream.Create(params, outputTarget, null);
        } else {
            codeStream.Create(params, target, null);
        }
        if (!initializeCodestream(codeStream, cycc, cLevels, quality, cLayers, colorModel, writeCodeStreamOnly, dataType, target, geoJp2, orgGen_plt, orgGen_tlm, orgT_parts, qGuard, cOrder, cPrecincts, compression)) {
            throw new IOException("Unable to initialize the codestream due to a missing " + "Jp2_target object");
        }
        // //
        // 
        // Preparing parameters for stripe compression
        // 
        // //
        final Kdu_stripe_compressor compressor = new Kdu_stripe_compressor();
        // Array with one entry for each image component, identifying the
        // number of lines supplied for that component in the present call.
        // All entries must be non-negative.
        final int[] stripeHeights = new int[nComponents];
        // Array with one entry for each image component, identifying
        // the separation between horizontally adjacent samples within the
        // corresponding stripe buffer found in the stripe_bufs array.
        final int[] sampleGaps = new int[nComponents];
        // Array with one entry for each image component, identifying
        // the separation between vertically adjacent samples within the
        // corresponding stripe buffer found in the stripe_bufs array.
        final int[] rowGaps = new int[nComponents];
        // Array with one entry for each image component, identifying the
        // position of the first sample of that component within the buffer array.
        final int[] sampleOffsets = new int[nComponents];
        // Array with one entry for each image component, identifying the
        // number of significant bits used to represent each sample.
        final int[] precisions = new int[nComponents];
        initializeStripeCompressor(compressor, codeStream, quality, cLayers, qualityLayersSize, bitRates, compression, rowSize, destinationHeight, destinationWidth, nComponents, stripeHeights, sampleGaps, rowGaps, sampleOffsets, precisions, numberOfBits, addCommentMarker);
        // ////////////////////////////////////////////////////////////////
        // 
        // Pushing Stripes
        // 
        // ////////////////////////////////////////////////////////////////
        pushStripes(compressor, inputRenderedImage, imageBounds, originalBounds, isDataSigned, resampleInputImage, writeCodeStreamOnly, hasPalette, nComponents, bits, destinationWidth, destinationHeight, xSubsamplingFactor, ySubsamplingFactor, stripeHeights, sampleGaps, rowGaps, sampleOffsets, precisions, reds, greens, blues);
        // ////////////////////////////////////////////////////////////////
        // 
        // Kakadu Objects Finalization
        // 
        // ////////////////////////////////////////////////////////////////
        compressor.Finish();
        compressor.Native_destroy();
        codeStream.Destroy();
    } catch (KduException e) {
        throw (IOException) new IOException("Error caused by a Kakadu exception during write operation").initCause(e);
    } finally {
        // //
        if (!writeCodeStreamOnly && target != null) {
            try {
                if (target.Exists())
                    target.Close();
            } catch (Throwable e) {
            // Does Nothing
            }
            try {
                target.Native_destroy();
            } catch (Throwable e) {
            // Does Nothing
            }
            if (familyTarget != null) {
                try {
                    if (familyTarget.Exists())
                        familyTarget.Close();
                } catch (Throwable e) {
                // Does Nothing
                }
                try {
                    familyTarget.Native_destroy();
                } catch (Throwable e) {
                // Does Nothing
                }
            }
        } else if (writeCodeStreamOnly && outputTarget != null) {
            try {
                outputTarget.Close();
            } catch (Throwable e) {
            // Does Nothing
            }
            try {
                outputTarget.Native_destroy();
            } catch (Throwable e) {
            // Does Nothing
            }
        }
        // //
        if (outputStream != null) {
            writeOnStream();
        }
    }
}
Also used : ProgressionOrder(it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.ProgressionOrder) Compression(it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.Compression) Rectangle(java.awt.Rectangle) Kdu_stripe_compressor(kdu_jni.Kdu_stripe_compressor) Kdu_simple_file_target(kdu_jni.Kdu_simple_file_target) IndexColorModel(java.awt.image.IndexColorModel) ColorModel(java.awt.image.ColorModel) Kdu_compressed_target(kdu_jni.Kdu_compressed_target) Kdu_codestream(kdu_jni.Kdu_codestream) IndexColorModel(java.awt.image.IndexColorModel) KduException(kdu_jni.KduException) Siz_params(kdu_jni.Siz_params) Dimension(java.awt.Dimension) IOException(java.io.IOException) Jp2_target(kdu_jni.Jp2_target) SampleModel(java.awt.image.SampleModel) Jp2_family_tgt(kdu_jni.Jp2_family_tgt) RenderedImage(java.awt.image.RenderedImage)

Aggregations

KduException (kdu_jni.KduException)3 Kdu_codestream (kdu_jni.Kdu_codestream)3 Rectangle (java.awt.Rectangle)2 ColorModel (java.awt.image.ColorModel)2 IndexColorModel (java.awt.image.IndexColorModel)2 SampleModel (java.awt.image.SampleModel)2 IOException (java.io.IOException)2 Jp2_family_src (kdu_jni.Jp2_family_src)2 Jpx_codestream_source (kdu_jni.Jpx_codestream_source)2 Jpx_input_box (kdu_jni.Jpx_input_box)2 Jpx_source (kdu_jni.Jpx_source)2 Kdu_dims (kdu_jni.Kdu_dims)2 Kdu_simple_file_source (kdu_jni.Kdu_simple_file_source)2 Compression (it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.Compression)1 ProgressionOrder (it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.ProgressionOrder)1 FileImageInputStreamExt (it.geosolutions.imageio.stream.input.FileImageInputStreamExt)1 Dimension (java.awt.Dimension)1 BufferedImage (java.awt.image.BufferedImage)1 ComponentColorModel (java.awt.image.ComponentColorModel)1 DataBuffer (java.awt.image.DataBuffer)1