Search in sources :

Example 1 with Siz_params

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

the class JP2KKakaduImageWriter method initializeCodestream.

/**
 * Initialize the codestream params in compliance with the provided arguments.
 *
 * @param codeStream
 *                the output codestream
 * @param ycc
 *                the cycc parameter
 * @param cLevels
 *                the number of DWT decomposition levels
 * @param quality
 *                the quality factor (in the range 0.01 - 1. where 1 = LOSSLESS)
 * @param qualityLayers
 *                the number of quality layers
 * @param colorModel
 *                the input image's colorModel
 * @param writeCodeStreamOnly
 *                <code>true</code> if we need to write only codestream.
 * @param target
 *                the optional {@link Jp2_target} object in case we are
 *                writing only codestream.
 * @param orgGen_plt
 *                if {@code true}, request the insertion of packet length information
 *                in the header of tile-parts.
 * @param orgGen_tlm
 *                the Tile-part-lenght (TLM) marker marker segments in the main header.
 * @param orgT_parts
 *                parameter setting the division of each tile's packets into tile-parts
 * @param qGuard
 *                parameter setting the guard bits
 * @param cOrder
 *                the {@link ProgressionOrder} to be used.
 * @param cPrecincts
 *                the optional Precincts settings
 * @return {@code false} in case we aren't writing codestream only
 *         and a proper {@link Jp2_target} haven't been provided
 *
 * @throws KduException
 */
private boolean initializeCodestream(final Kdu_codestream codeStream, final boolean ycc, final int cLevels, final double quality, final int qualityLayers, final ColorModel colorModel, final boolean writeCodeStreamOnly, final int dataType, final Jp2_target target, final byte[] geoJp2, final boolean orgGen_plt, final int orgGen_tlm, final String orgT_parts, final int qGuard, final ProgressionOrder cOrder, final String cPrecincts, final Compression compression) throws KduException {
    final Siz_params params = codeStream.Access_siz();
    // //
    if (compression != null && compression == Compression.LOSSY) {
        params.Parse_string("Creversible=no");
    } else if (quality == 1 || colorModel instanceof IndexColorModel) {
        params.Parse_string("Creversible=yes");
    } else {
        params.Parse_string("Creversible=no");
    }
    if (cPrecincts != null && cPrecincts.trim().length() > 0) {
        params.Parse_string("Cuse_precincts=yes");
        params.Parse_string("Cprecincts=" + cPrecincts);
    }
    params.Parse_string("Cycc=" + (ycc ? "yes" : "no"));
    params.Parse_string("Clevels=" + cLevels);
    params.Parse_string("Clayers=" + qualityLayers);
    if (dataType == DataBuffer.TYPE_SHORT || dataType == DataBuffer.TYPE_USHORT) {
        params.Parse_string("Qstep=0.0000152588");
    }
    if (qGuard > 0) {
        params.Parse_string("Qguard=" + qGuard);
    }
    // //
    // 
    // Setting ORG_params
    // 
    // //
    Kdu_params org = params.Access_cluster(Kdu_global.ORG_params);
    if (orgGen_plt) {
        org.Set("ORGgen_plt", 0, 0, true);
    }
    if (orgGen_tlm != JP2KKakaduImageWriteParam.UNSPECIFIED_ORG_GEN_TLM) {
        org.Set("ORGgen_tlm", 0, 0, orgGen_tlm);
    }
    if (orgT_parts != null && orgT_parts.length() > 0) {
        org.Parse_string("ORGt_parts=" + orgT_parts);
    }
    // //
    // 
    // Setting COD_params
    // 
    // //
    Kdu_params cod = params.Access_cluster(Kdu_global.COD_params);
    if (cOrder != null) {
        cod.Set("Corder", 0, 0, cOrder.getValue());
    }
    // //
    // 
    // Finalizing params
    // 
    // //
    params.Finalize_all();
    if (!writeCodeStreamOnly) {
        if (target == null) {
            return false;
        }
        // //
        // 
        // Writing header
        // 
        // //
        initializeHeader(target, params, colorModel);
        if (geoJp2 != null && geoJp2.length > 0) {
            // Add geoJP2 box here.
            // This is a quick solution. The ideal would be to leverage on metadata or on top of a better
            // set of entities/helpers
            target.Open_next(UUIDBox.BOX_TYPE);
            byte[] outByte = new byte[GEOJP2_UUID.length];
            for (int i = 0; i < GEOJP2_UUID.length; i++) {
                outByte[i] = (byte) GEOJP2_UUID[i];
            }
            target.Write(outByte, GEOJP2_UUID.length);
            target.Write(geoJp2, geoJp2.length);
            target.Close();
        }
        target.Open_codestream();
    }
    return true;
}
Also used : Siz_params(kdu_jni.Siz_params) Kdu_params(kdu_jni.Kdu_params) IndexColorModel(java.awt.image.IndexColorModel)

Example 2 with Siz_params

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

IndexColorModel (java.awt.image.IndexColorModel)2 Siz_params (kdu_jni.Siz_params)2 Compression (it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.Compression)1 ProgressionOrder (it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageWriteParam.ProgressionOrder)1 Dimension (java.awt.Dimension)1 Rectangle (java.awt.Rectangle)1 ColorModel (java.awt.image.ColorModel)1 RenderedImage (java.awt.image.RenderedImage)1 SampleModel (java.awt.image.SampleModel)1 IOException (java.io.IOException)1 Jp2_family_tgt (kdu_jni.Jp2_family_tgt)1 Jp2_target (kdu_jni.Jp2_target)1 KduException (kdu_jni.KduException)1 Kdu_codestream (kdu_jni.Kdu_codestream)1 Kdu_compressed_target (kdu_jni.Kdu_compressed_target)1 Kdu_params (kdu_jni.Kdu_params)1 Kdu_simple_file_target (kdu_jni.Kdu_simple_file_target)1 Kdu_stripe_compressor (kdu_jni.Kdu_stripe_compressor)1