Search in sources :

Example 1 with Kdu_stripe_decompressor

use of kdu_jni.Kdu_stripe_decompressor 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)

Aggregations

Rectangle (java.awt.Rectangle)1 BufferedImage (java.awt.image.BufferedImage)1 ColorModel (java.awt.image.ColorModel)1 ComponentColorModel (java.awt.image.ComponentColorModel)1 DataBuffer (java.awt.image.DataBuffer)1 DataBufferByte (java.awt.image.DataBufferByte)1 DataBufferInt (java.awt.image.DataBufferInt)1 DataBufferUShort (java.awt.image.DataBufferUShort)1 IndexColorModel (java.awt.image.IndexColorModel)1 MultiPixelPackedSampleModel (java.awt.image.MultiPixelPackedSampleModel)1 PixelInterleavedSampleModel (java.awt.image.PixelInterleavedSampleModel)1 RasterFormatException (java.awt.image.RasterFormatException)1 SampleModel (java.awt.image.SampleModel)1 Jp2_family_src (kdu_jni.Jp2_family_src)1 Jpx_codestream_source (kdu_jni.Jpx_codestream_source)1 Jpx_input_box (kdu_jni.Jpx_input_box)1 Jpx_source (kdu_jni.Jpx_source)1 KduException (kdu_jni.KduException)1 Kdu_codestream (kdu_jni.Kdu_codestream)1 Kdu_dims (kdu_jni.Kdu_dims)1