*/
    private BufferedImage dctDecode(
            int width, int height, PColorSpace colourSpace, int bitspercomponent,
            BufferedImage smaskImage, BufferedImage maskImage,
            int[] maskMinRGB, int[] maskMaxRGB, Vector<Integer> decode) {

        // BIS's buffer size should be equal to mark() size, and greater than data size (below)
        InputStream input = getInputStreamForDecodedStreamBytes();
        // Used to just read 1000, but found a PDF that included thumbnails first
        final int MAX_BYTES_TO_READ_FOR_ENCODING = 2048;
        BufferedInputStream bufferedInput = new BufferedInputStream(
                input, MAX_BYTES_TO_READ_FOR_ENCODING);
        bufferedInput.mark(MAX_BYTES_TO_READ_FOR_ENCODING);

        // We don't use the PColorSpace to determine how to decode the JPEG, because it tends to be wrong
        // Some files say DeviceCMYK, or ICCBased, when neither would work, because it's really YCbCrA
        // What does work though, is to look into the JPEG headers themself, via getJPEGEncoding()

        int jpegEncoding = Stream.JPEG_ENC_UNKNOWN_PROBABLY_YCbCr;
        try {
            byte[] data = new byte[MAX_BYTES_TO_READ_FOR_ENCODING];
            int dataRead = bufferedInput.read(data);
            bufferedInput.reset();
            if (dataRead > 0)
                jpegEncoding = getJPEGEncoding(data, dataRead);
        } catch (IOException ioe) {
            logger.log(Level.FINE, "Problem determining JPEG type: ", ioe);
        }
        if (Tagger.tagging)
            Tagger.tagImage("DCTDecode_JpegEncoding=" + JPEG_ENC_NAMES[jpegEncoding]);
        //System.out.println("Stream.dctDecode()  objectNumber: " + getPObjectReference().getObjectNumber());
        //System.out.println("Stream.dctDecode()  jpegEncoding: " + JPEG_ENC_NAMES[jpegEncoding]);

        //System.out.println("Stream.dctDecode()  smask: " + smaskImage);
        //System.out.println("Stream.dctDecode()  mask: " + maskImage);
        //System.out.println("Stream.dctDecode()  maskMinRGB: " + maskMinRGB);
        //System.out.println("Stream.dctDecode()  maskMaxRGB: " + maskMaxRGB);

        //long beginUsedMem = (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
        //long beginTime = System.currentTimeMillis();
        BufferedImage tmpImage = null;

        if (tmpImage == null) {
            try {
                //System.out.println("Stream.dctDecode()  JPEGImageDecoder");
                JPEGImageDecoder imageDecoder = JPEGCodec.createJPEGDecoder(bufferedInput);

                int bizarreFudge = 64 * 1024 + (int) streamInput.getLength();
                checkMemory(width * height * 8 + bizarreFudge);

                if (jpegEncoding == JPEG_ENC_RGB && bitspercomponent == 8) {
                    //System.out.println("Stream.dctDecode()    JPEG_ENC_RGB");
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    alterRasterRGB2PColorSpace(wr, colourSpace);
                    tmpImage = makeRGBBufferedImage(wr);
                } else if (jpegEncoding == JPEG_ENC_CMYK && bitspercomponent == 8) {
                    //System.out.println("Stream.dctDecode()    JPEG_ENC_CMYK");
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    tmpImage = alterRasterCMYK2BGRA(wr, smaskImage, maskImage); //TODO Use maskMinRGB, maskMaxRGB or orig comp version here
                } else if (jpegEncoding == JPEG_ENC_YCbCr && bitspercomponent == 8) {
                    //System.out.println("Stream.dctDecode()    JPEG_ENC_YCbCr");
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    tmpImage = alterRasterYCbCr2RGB(wr, smaskImage, maskImage, decode, bitspercomponent);
                } else if (jpegEncoding == JPEG_ENC_YCCK && bitspercomponent == 8) {
                    //System.out.println("Stream.dctDecode()    JPEG_ENC_YCCK");
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    // YCCK to RGB works better if an CMYK intermediate is used, but slower.
                    alterRasterYCCK2CMYK(wr, decode, bitspercomponent);
                    tmpImage = alterRasterCMYK2BGRA(wr, smaskImage, maskImage);
                } else if (jpegEncoding == JPEG_ENC_GRAY && bitspercomponent == 8) {
                    //System.out.println("Stream.dctDecode()    JPEG_ENC_GRAY");
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    // In DCTDecode with ColorSpace=DeviceGray, the samples are gray values (2000_SID_Service_Info.core)
                    // In DCTDecode with ColorSpace=Separation, the samples are Y values (45-14550BGermanForWeb.core AKA 4570.core)
                    // Avoid converting images that are already likely gray.
                    if (!(colourSpace instanceof DeviceGray) &&
                            !(colourSpace instanceof ICCBased) &&
                            !(colourSpace instanceof Indexed)) {
                        if (Tagger.tagging)
                            Tagger.tagImage("DCTDecode_JpegSubEncoding=Y");
                        alterRasterY2Gray(wr, bitspercomponent, decode); //TODO Use smaskImage, maskImage, maskMinRGB, maskMaxRGB or orig comp version here
                    }
                    tmpImage = makeGrayBufferedImage(wr);
                    // apply mask value
                    if (maskImage != null) {
                        tmpImage = applyExplicitMask(tmpImage, maskImage);
                    }
                    if (smaskImage != null) {
                        tmpImage = applyExplicitSMask(tmpImage, smaskImage);
                    }
                } else {
                    //System.out.println("Stream.dctDecode()    Other");
                    //tmpImage = imageDecoder.decodeAsBufferedImage();
                    Raster r = imageDecoder.decodeAsRaster();
                    WritableRaster wr = (r instanceof WritableRaster)
                            ? (WritableRaster) r : r.createCompatibleWritableRaster();
                    //System.out.println("Stream.dctDecode()      EncodedColorID: " + imageDecoder.getJPEGDecodeParam().getEncodedColorID());
                    if (imageDecoder.getJPEGDecodeParam().getEncodedColorID() ==
                            com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_YCbCrA) {
                        if (Tagger.tagging)
                            Tagger.tagImage("DCTDecode_JpegSubEncoding=YCbCrA");
                        // YCbCrA, which is slightly different than YCCK
                        alterRasterYCbCrA2RGBA_new(wr, smaskImage, maskImage,
                                decode, bitspercomponent); //TODO Use maskMinRGB, maskMaxRGB or orig comp version here
                        tmpImage = makeRGBABufferedImage(wr);
                    } else {
                        if (Tagger.tagging)
                            Tagger.tagImage("DCTDecode_JpegSubEncoding=YCbCr");
                        alterRasterYCbCr2RGB(wr, smaskImage, maskImage, decode, bitspercomponent);
                        tmpImage = makeRGBBufferedImage(wr);
                        // special case to handle an smask on an RGB image.  In
                        // such a case we need to copy the rgb and soft mask effect
                        // to th new ARGB image.
                        if (smaskImage != null) {
                            BufferedImage argbImage = new BufferedImage(width,
                                    height, BufferedImage.TYPE_INT_ARGB);
                            int[] srcBand = new int[width];
                            int[] sMaskBand = new int[width];
                            // iterate over each band to apply the mask
                            for (int i = 0; i < height; i++) {
                                tmpImage.getRGB(0, i, width, 1, srcBand, 0, width);
                                smaskImage.getRGB(0, i, width, 1, sMaskBand, 0, width);
                                // apply the soft mask blending
                                for (int j = 0; j < width; j++) {
                                    sMaskBand[j] = ((sMaskBand[j] & 0xff) << 24)
                                            | (srcBand[j] & ~0xff000000);
                                }
                                argbImage.setRGB(0, i, width, 1, sMaskBand, 0, width);
                            }
                            tmpImage.flush();
                            tmpImage = argbImage;
                        }
                    }
                }
            } catch (Exception e) {
                logger.log(Level.FINE, "Problem loading JPEG image via JPEGImageDecoder: ", e);
            }
            if (tmpImage != null) {
                if (Tagger.tagging)
                    Tagger.tagImage("HandledBy=DCTDecode_SunJPEGImageDecoder");
            }
        }

        try {
            bufferedInput.close();
        } catch (IOException e) {
            logger.log(Level.FINE, "Error closing image stream.", e);
        }

        if (tmpImage == null) {
            try {
                //System.out.println("Stream.dctDecode()  JAI");
                Object javax_media_jai_RenderedOp_op = null;
                try {
                    // Have to reget the data
                    input = getInputStreamForDecodedStreamBytes();

                    /*
                    com.sun.media.jai.codec.SeekableStream s = com.sun.media.jai.codec.SeekableStream.wrapInputStream( new ByteArrayInputStream(data), true );
                    ParameterBlock pb = new ParameterBlock();
                    pb.add( s );
                    javax.media.jai.RenderedOp op = javax.media.jai.JAI.create( "jpeg", pb );
                    */
                    Class ssClass = Class.forName("com.sun.media.jai.codec.SeekableStream");
                    Method ssWrapInputStream = ssClass.getMethod("wrapInputStream", InputStream.class, Boolean.TYPE);
                    Object com_sun_media_jai_codec_SeekableStream_s =
                            ssWrapInputStream.invoke(null, input, Boolean.TRUE);
                    ParameterBlock pb = new ParameterBlock();
                    pb.add(com_sun_media_jai_codec_SeekableStream_s);
                    Class jaiClass = Class.forName("javax.media.jai.JAI");
                    Method jaiCreate = jaiClass.getMethod("create", String.class, ParameterBlock.class);
                    javax_media_jai_RenderedOp_op = jaiCreate.invoke(null, "jpeg", pb);
                } catch (Exception e) {
                }

                if (javax_media_jai_RenderedOp_op != null) {
                    if (jpegEncoding == JPEG_ENC_CMYK && bitspercomponent == 8) {
                        /*
                         * With or without alterRasterCMYK2BGRA(), give blank image
                        Raster r = op.copyData();
                        WritableRaster wr = (r instanceof WritableRaster)
                                ? (WritableRaster) r : r.createCompatibleWritableRaster();
                        alterRasterCMYK2BGRA( wr );
                        tmpImage = makeRGBABufferedImage( wr );
                        */
                        /*
                         * With alterRasterCMYK2BGRA() colors gibbled, without is blank
                         * Slower, uses more memory, than JPEGImageDecoder
                        BufferedImage img = op.getAsBufferedImage();
                        WritableRaster wr = img.getRaster();
                        alterRasterCMYK2BGRA( wr );
                        tmpImage = img;
                        */
                    } else if (jpegEncoding == JPEG_ENC_YCCK && bitspercomponent == 8) {
                        /*
                         * This way, with or without alterRasterYCbCrA2BGRA(), give blank image
                        Raster r = op.getData();
                        WritableRaster wr = (r instanceof WritableRaster)
                                ? (WritableRaster) r : r.createCompatibleWritableRaster();
                        alterRasterYCbCrA2BGRA( wr );
                        tmpImage = makeRGBABufferedImage( wr );
                        */
                        /*
                         * With alterRasterYCbCrA2BGRA() colors gibbled, without is blank
                         * Slower, uses more memory, than JPEGImageDecoder
                        BufferedImage img = op.getAsBufferedImage();
                        WritableRaster wr = img.getRaster();
                        alterRasterYCbCrA2BGRA( wr );
                        tmpImage = img;
                        */
                    } else {
                        //System.out.println("Stream.dctDecode()    Other");
                        /* tmpImage = op.getAsBufferedImage(); */
                        Class roClass = Class.forName("javax.media.jai.RenderedOp");
                        Method roGetAsBufferedImage = roClass.getMethod("getAsBufferedImage");
                        tmpImage = (BufferedImage) roGetAsBufferedImage.invoke(javax_media_jai_RenderedOp_op);
                        if (tmpImage != null) {
                            if (Tagger.tagging)
                                Tagger.tagImage("HandledBy=DCTDecode_JAI");
                        }
                    }
                }
            } catch (Exception e) {
                logger.log(Level.FINE, "Problem loading JPEG image via JAI: ", e);
            }

            try {
                input.close();
            } catch (IOException e) {
                logger.log(Level.FINE, "Problem closing image stream. ", e);
            }
        }

        if (tmpImage == null) {
            try {
                //System.out.println("Stream.dctDecode()  Toolkit");
                byte[] data = getDecodedStreamBytes();
                if (data != null) {
                    Image img = Toolkit.getDefaultToolkit().createImage(data);
                    if (img != null) {
                        tmpImage = makeRGBABufferedImageFromImage(img);
                        if (Tagger.tagging)
                            Tagger.tagImage("HandledBy=DCTDecode_ToolkitCreateImage");
                    }
                }
            } catch (Exception e) {
                logger.log(Level.FINE, "Problem loading JPEG image via Toolkit: ", e);
            }
        }

        //long endUsedMem = (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
        //long endTime = System.currentTimeMillis();
        //System.out.println("Mem used: " + (endUsedMem-beginUsedMem) + ",\ttime: " + (endTime-beginTime));
        return tmpImage;
    }