* @param width            width of image.
     * @param height           height of image.
     * @param colourSpace      colour space to apply to image.
     * @param bitsPerComponent bits used to represent a colour
     * @param fill             fill colour used in last draw operand.
     * @param maskImage        image mask if any, can be null.
     * @param sMaskImage       image smask if any, can be null.
     * @param maskMinRGB       mask minimum rgb value, optional.
     * @param maskMaxRGB       mask maximum rgb value, optional.
     * @return buffered image of the jpeg2000 image stream.  Null if a problem
     *         occurred during the decode.
     */
    private BufferedImage jpxDecode(int width, int height, PColorSpace colourSpace,
                                    int bitsPerComponent, Color fill,
                                    BufferedImage sMaskImage, BufferedImage maskImage,
                                    int[] maskMinRGB, int[] maskMaxRGB, Vector decode) {
        BufferedImage tmpImage = null;
        try {
            // Verify that ImageIO can read JPEG2000
            Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName("JPEG2000");
            if (!iterator.hasNext()) {
                logger.info(
                        "ImageIO missing required plug-in to read JPEG 2000 images. " +
                                "You can download the JAI ImageIO Tools from: " +
                                "https://jai-imageio.dev.java.net/");
                return null;
            }
            // decode the image.
            byte[] data = getDecodedStreamBytes();
            ImageInputStream imageInputStream = ImageIO.createImageInputStream(
                    new ByteArrayInputStream(data));
            tmpImage = ImageIO.read(imageInputStream);

            // check for an instance of ICCBased, we don't currently support
            // this colour mode well so we'll used the alternative colour
            if (colourSpace instanceof ICCBased) {
                ICCBased iccBased = (ICCBased) colourSpace;
                if (iccBased.getAlternate() != null) {
                    // set the alternate as the current
                    colourSpace = iccBased.getAlternate();
                }
                // try to process the ICC colour space
                else {
                    ColorSpace cs = iccBased.getColorSpace();
                    ColorConvertOp cco = new ColorConvertOp(cs, null);
                    tmpImage = cco.filter(tmpImage, null);
                }
            }

            // apply respective colour models to the JPEG2000 image.
            if (colourSpace instanceof DeviceRGB && bitsPerComponent == 8) {
                WritableRaster wr = tmpImage.getRaster();
                alterRasterRGB2PColorSpace(wr, colourSpace);
                tmpImage = makeRGBBufferedImage(wr);
            } else if (colourSpace instanceof DeviceCMYK && bitsPerComponent == 8) {
                WritableRaster wr = tmpImage.getRaster();
                tmpImage = alterRasterCMYK2BGRA(wr, sMaskImage, maskImage);
            } else if ((colourSpace instanceof DeviceGray ||
                    colourSpace instanceof Indexed)
                    && bitsPerComponent == 8) {
                WritableRaster wr = tmpImage.getRaster();
                tmpImage = makeGrayBufferedImage(wr);
            } else if (colourSpace instanceof Separation){
                WritableRaster wr = tmpImage.getRaster();
                alterRasterY2Gray(wr, bitsPerComponent, decode);
            }

            // check for a mask value
            if (maskImage != null) {
                applyExplicitMask(tmpImage, maskImage);
            }

        }
        catch (IOException e) {
            logger.log(Level.FINE, "Problem loading JPEG2000 image: ", e);
        }

        return tmpImage;
    }