This class is responsible of all data type conversions. It should be used, at encoder side, between Tiler and ForwardWT modules and, at decoder side, between InverseWT/CompDemixer and ImgWriter modules. The conversion is realized when a block of data is requested: if source and destination data type are the same one, it does nothing, else appropriate cast is done. All the methods of the 'ImgData' interface are implemented by the 'ImgDataAdapter' class that is the superclass of this one, so they don't need to be reimplemented by subclasses.
Inheritance: CSJ2K.j2k.image.ImgDataAdapter, BlkImgDataSrc
Beispiel #1
0
        public static byte[] EncodeJPEG(Image jpgImage)
        {
            Tiler imgtiler;
            ForwCompTransf fctransf;
            ImgDataConverter converter;
            EncoderSpecs encSpec;
            ForwardWT dwt;
            Quantizer quant;
            ROIScaler rois;
            EntropyCoder ecoder;
            PostCompRateAllocator ralloc;
            HeaderEncoder headenc;
            CodestreamWriter bwriter;

            float rate = Single.MaxValue;

            ImgReaderGDI imgsrc = new ImgReaderGDI(jpgImage);

            imgtiler = new Tiler(imgsrc, 0, 0, 0, 0, jpgImage.Width, jpgImage.Height);
            int ntiles = imgtiler.getNumTiles();

            encSpec = new EncoderSpecs(ntiles, 3, imgsrc, pl);

            fctransf = new ForwCompTransf(imgtiler, encSpec);
            converter = new ImgDataConverter(fctransf);
            dwt = ForwardWT.createInstance(converter, pl, encSpec);
            quant = Quantizer.createInstance(dwt, encSpec);
            rois = ROIScaler.createInstance(quant, pl, encSpec);
            ecoder = EntropyCoder.createInstance(rois, pl, encSpec.cblks,
                encSpec.pss, encSpec.bms,
                encSpec.mqrs, encSpec.rts,
                encSpec.css, encSpec.sss,
                encSpec.lcs, encSpec.tts);

            using (MemoryStream stream = new MemoryStream())
            {
                bwriter = new FileCodestreamWriter(stream, Int32.MaxValue);
                ralloc = PostCompRateAllocator.createInstance(ecoder, pl, rate, bwriter, encSpec);

                headenc = new HeaderEncoder(imgsrc, new bool[3], dwt, imgtiler, encSpec, rois, ralloc, pl);
                ralloc.HeaderEncoder = headenc;
                headenc.encodeMainHeader();
                ralloc.initialize();
                headenc.reset();
                headenc.encodeMainHeader();
                bwriter.commitBitstreamHeader(headenc);

                ralloc.runAndWrite();
                bwriter.close();

                return stream.ToArray();
            }
        }
Beispiel #2
0
        public static Image FromStream(Stream stream)
        {
            RandomAccessIO in_stream = new ISRandomAccessIO(stream);

            // Initialize default parameters
            ParameterList defpl = GetDefaultParameterList(decoder_pinfo);

            // Create parameter list using defaults
            ParameterList pl = new ParameterList(defpl);

            // **** File Format ****
            // If the codestream is wrapped in the jp2 fileformat, Read the
            // file format wrapper
            FileFormatReader ff = new FileFormatReader(in_stream);
            ff.readFileFormat();
            if (ff.JP2FFUsed)
            {
                in_stream.seek(ff.FirstCodeStreamPos);
            }

            // +----------------------------+
            // | Instantiate decoding chain |
            // +----------------------------+

            // **** Header decoder ****
            // Instantiate header decoder and read main header 
            HeaderInfo hi = new HeaderInfo();
            HeaderDecoder hd;
            try
            {
                hd = new HeaderDecoder(in_stream, pl, hi);
            }
            catch (EndOfStreamException e)
            {
                throw new ApplicationException("Codestream too short or bad header, unable to decode.", e);
            }

            int nCompCod = hd.NumComps;
            int nTiles = hi.sizValue.NumTiles;
            DecoderSpecs decSpec = hd.DecoderSpecs;

            // Get demixed bitdepths
            int[] depth = new int[nCompCod];
            for (int i = 0; i < nCompCod; i++)
            {
                depth[i] = hd.getOriginalBitDepth(i);
            }

            // **** Bit stream reader ****
            BitstreamReaderAgent breader;
            try
            {
                breader = BitstreamReaderAgent.
                    createInstance(in_stream, hd, pl, decSpec,
                                   false, hi);
            }
            catch (IOException e)
            {
                throw new ApplicationException("Error while reading bit stream header or parsing packets.", e);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate bit stream reader.", e);
            }

            // **** Entropy decoder ****
            EntropyDecoder entdec;
            try
            {
                entdec = hd.createEntropyDecoder(breader, pl);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate entropy decoder.", e);
            }

            // **** ROI de-scaler ****
            ROIDeScaler roids;
            try
            {
                roids = hd.createROIDeScaler(entdec, pl, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate roi de-scaler.", e);
            }

            // **** Dequantizer ****
            Dequantizer deq;
            try
            {
                deq = hd.createDequantizer(roids, depth, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate dequantizer.", e);
            }

            // **** Inverse wavelet transform ***
            InverseWT invWT;
            try
            {
                // full page inverse wavelet transform
                invWT = InverseWT.createInstance(deq, decSpec);
            }
            catch (ArgumentException e)
            {
                throw new ApplicationException("Cannot instantiate inverse wavelet transform.", e);
            }

            int res = breader.ImgRes;
            invWT.ImgResLevel = res;

            // **** Data converter **** (after inverse transform module)
            ImgDataConverter converter = new ImgDataConverter(invWT, 0);

            // **** Inverse component transformation **** 
            InvCompTransf ictransf = new InvCompTransf(converter, decSpec, depth, pl);

            // **** Color space mapping ****
            BlkImgDataSrc color;
            if (ff.JP2FFUsed && pl.getParameter("nocolorspace").Equals("off"))
            {
                try
                {
                    ColorSpace csMap = new ColorSpace(in_stream, hd, pl);
                    BlkImgDataSrc channels = hd.createChannelDefinitionMapper(ictransf, csMap);
                    BlkImgDataSrc resampled = hd.createResampler(channels, csMap);
                    BlkImgDataSrc palettized = hd.createPalettizedColorSpaceMapper(resampled, csMap);
                    color = hd.createColorSpaceMapper(palettized, csMap);
                }
                catch (ArgumentException e)
                {
                    throw new ApplicationException("Could not instantiate ICC profiler.", e);
                }
                catch (ColorSpaceException e)
                {
                    throw new ApplicationException("Error processing ColorSpace information.", e);
                }
            }
            else
            { // Skip colorspace mapping
                color = ictransf;
            }

            // This is the last image in the decoding chain and should be
            // assigned by the last transformation:
            BlkImgDataSrc decodedImage = color;
            if (color == null)
            {
                decodedImage = ictransf;
            }
            int numComps = decodedImage.NumComps;

            int bytesPerPixel = (numComps == 4 ? 4 : 3);

            // **** Copy to Bitmap ****
            PixelFormat pixelFormat;
            switch (numComps)
            {
                case 1:
                    pixelFormat = PixelFormat.Format24bppRgb; break;
                case 3:
                    pixelFormat = PixelFormat.Format24bppRgb; break;
                case 4:
                    pixelFormat = PixelFormat.Format32bppArgb; break;
                default:
                    throw new ApplicationException("Unsupported PixelFormat.  " + numComps + " components.");
            }

            Bitmap dst = new Bitmap(decodedImage.ImgWidth, decodedImage.ImgHeight, pixelFormat);

            Coord numTiles = decodedImage.getNumTiles(null);

            int tIdx = 0;

            for (int y = 0; y < numTiles.y; y++)
            {
                // Loop on horizontal tiles
                for (int x = 0; x < numTiles.x; x++, tIdx++)
                {
                    decodedImage.setTile(x, y);

                    int height = decodedImage.getTileCompHeight(tIdx, 0);
                    int width = decodedImage.getTileCompWidth(tIdx, 0);

                    int tOffx = decodedImage.getCompULX(0) -
                        (int)Math.Ceiling(decodedImage.ImgULX /
                           (double)decodedImage.getCompSubsX(0));

                    int tOffy = decodedImage.getCompULY(0) -
                        (int)Math.Ceiling(decodedImage.ImgULY /
                            (double)decodedImage.getCompSubsY(0));

                    DataBlkInt[] db = new DataBlkInt[numComps];
                    int[] ls = new int[numComps];
                    int[] mv = new int[numComps];
                    int[] fb = new int[numComps];
                    for (int i = 0; i < numComps; i++)
                    {
                        db[i] = new DataBlkInt();
                        ls[i] = 1 << (decodedImage.getNomRangeBits(0) - 1);
                        mv[i] = (1 << decodedImage.getNomRangeBits(0)) - 1;
                        fb[i] = decodedImage.getFixedPoint(0);
                    }
                    for (int l = 0; l < height; l++)
                    {
                        for (int i = numComps - 1; i >= 0; i--)
                        {
                            db[i].ulx = 0;
                            db[i].uly = l;
                            db[i].w = width;
                            db[i].h = 1;
                            decodedImage.getInternCompData(db[i], i);
                        }
                        int[] k = new int[numComps];
                        for (int i = numComps - 1; i >= 0; i--) k[i] = db[i].offset + width - 1;

                        byte[] rowvalues = new byte[width * bytesPerPixel];

                        for (int i = width - 1; i >= 0; i--)
                        {
                            int[] tmp = new int[numComps];
                            for (int j = numComps - 1; j >= 0; j--)
                            {
                                tmp[j] = (db[j].data_array[k[j]--] >> fb[j]) + ls[j];
                                tmp[j] = (tmp[j] < 0) ? 0 : ((tmp[j] > mv[j]) ? mv[j] : tmp[j]);

                                if (decodedImage.getNomRangeBits(j) != 8)
                                    tmp[j] = (int)Math.Round(((double)tmp[j] / Math.Pow(2D, (double)decodedImage.getNomRangeBits(j))) * 255D);

                            }
                            int offset = i * bytesPerPixel;
                            switch (numComps)
                            {
                                case 1:
                                    rowvalues[offset + 0] = (byte)tmp[0];
                                    rowvalues[offset + 1] = (byte)tmp[0];
                                    rowvalues[offset + 2] = (byte)tmp[0];
                                    break;
                                case 3:
                                    rowvalues[offset + 0] = (byte)tmp[2];
                                    rowvalues[offset + 1] = (byte)tmp[1];
                                    rowvalues[offset + 2] = (byte)tmp[0];
                                    break;
                                case 4:
                                    rowvalues[offset + 0] = (byte)tmp[3];
                                    rowvalues[offset + 1] = (byte)tmp[2];
                                    rowvalues[offset + 2] = (byte)tmp[1];
                                    rowvalues[offset + 3] = (byte)tmp[0];
                                    break;
                            }
                        }

                        BitmapData dstdata = dst.LockBits(
                            new System.Drawing.Rectangle(tOffx, tOffy + l, width, 1),
                            ImageLockMode.ReadWrite, pixelFormat);

                        IntPtr ptr = dstdata.Scan0;
                        System.Runtime.InteropServices.Marshal.Copy(rowvalues, 0, ptr, rowvalues.Length);
                        dst.UnlockBits(dstdata);
                    }
                }
            }
            return dst;
        }
Beispiel #3
0
        public static byte[] ToBytes(BlkImgDataSrc imgsrc, ParameterList parameters = null)
        {
            // Initialize default parameters
            ParameterList defpl = GetDefaultEncoderParameterList(encoder_pinfo);

            // Create parameter list using defaults
            ParameterList pl = parameters ?? new ParameterList(defpl);

            bool useFileFormat = false;
            bool pphTile = false;
            bool pphMain = false;
            bool tempSop = false;
            bool tempEph = false;

            // **** Get general parameters ****

            if (pl.getParameter("file_format").Equals("on"))
            {
                useFileFormat = true;
                if (pl.getParameter("rate") != null && pl.getFloatParameter("rate") != defpl.getFloatParameter("rate"))
                {
                    warning("Specified bit-rate applies only on the codestream but not on the whole file.");
                }
            }

            if (pl.getParameter("tiles") == null)
            {
                error("No tiles option specified", 2);
                return null;
            }

            if (pl.getParameter("pph_tile").Equals("on"))
            {
                pphTile = true;

                if (pl.getParameter("Psop").Equals("off"))
                {
                    pl["Psop"] = "on";
                    tempSop = true;
                }
                if (pl.getParameter("Peph").Equals("off"))
                {
                    pl["Peph"] = "on";
                    tempEph = true;
                }
            }

            if (pl.getParameter("pph_main").Equals("on"))
            {
                pphMain = true;

                if (pl.getParameter("Psop").Equals("off"))
                {
                    pl["Psop"] = "on";
                    tempSop = true;
                }
                if (pl.getParameter("Peph").Equals("off"))
                {
                    pl["Peph"] = "on";
                    tempEph = true;
                }
            }

            if (pphTile && pphMain) error("Can't have packed packet headers in both main and" + " tile headers", 2);

            if (pl.getBooleanParameter("lossless") && pl.getParameter("rate") != null
                && pl.getFloatParameter("rate") != defpl.getFloatParameter("rate")) throw new ArgumentException("Cannot use '-rate' and " + "'-lossless' option at " + " the same time.");

            if (pl.getParameter("rate") == null)
            {
                error("Target bitrate not specified", 2);
                return null;
            }
            float rate;
            try
            {
                rate = pl.getFloatParameter("rate");
                if (rate == -1)
                {
                    rate = float.MaxValue;
                }
            }
            catch (FormatException e)
            {
                error("Invalid value in 'rate' option: " + pl.getParameter("rate"), 2);
                return null;
            }
            int pktspertp;
            try
            {
                pktspertp = pl.getIntParameter("tile_parts");
                if (pktspertp != 0)
                {
                    if (pl.getParameter("Psop").Equals("off"))
                    {
                        pl["Psop"] = "on";
                        tempSop = true;
                    }
                    if (pl.getParameter("Peph").Equals("off"))
                    {
                        pl["Peph"] = "on";
                        tempEph = true;
                    }
                }
            }
            catch (FormatException e)
            {
                error("Invalid value in 'tile_parts' option: " + pl.getParameter("tile_parts"), 2);
                return null;
            }

            // **** ImgReader ****
            var ncomp = imgsrc.NumComps;
            var ppminput = imgsrc.NumComps > 1;

            // **** Tiler ****
            // get nominal tile dimensions
            SupportClass.StreamTokenizerSupport stok =
                new SupportClass.StreamTokenizerSupport(new StringReader(pl.getParameter("tiles")));
            stok.EOLIsSignificant(false);

            stok.NextToken();
            if (stok.ttype != SupportClass.StreamTokenizerSupport.TT_NUMBER)
            {
                error("An error occurred while parsing the tiles option: " + pl.getParameter("tiles"), 2);
                return null;
            }
            var tw = (int)stok.nval;
            stok.NextToken();
            if (stok.ttype != SupportClass.StreamTokenizerSupport.TT_NUMBER)
            {
                error("An error occurred while parsing the tiles option: " + pl.getParameter("tiles"), 2);
                return null;
            }
            var th = (int)stok.nval;

            // Get image reference point
            var refs = pl.getParameter("ref").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            int refx;
            int refy;
            try
            {
                refx = Int32.Parse(refs[0]);
                refy = Int32.Parse(refs[1]);
            }
            catch (IndexOutOfRangeException e)
            {
                throw new ArgumentException("Error while parsing 'ref' " + "option");
            }
            catch (FormatException e)
            {
                throw new ArgumentException("Invalid number type in " + "'ref' option");
            }
            if (refx < 0 || refy < 0)
            {
                throw new ArgumentException("Invalid value in 'ref' " + "option ");
            }

            // Get tiling reference point
            var trefs = pl.getParameter("tref").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            int trefx;
            int trefy;
            try
            {
                trefx = Int32.Parse(trefs[0]);
                trefy = Int32.Parse(trefs[1]);
            }
            catch (IndexOutOfRangeException e)
            {
                throw new ArgumentException("Error while parsing 'tref' " + "option");
            }
            catch (FormatException e)
            {
                throw new ArgumentException("Invalid number type in " + "'tref' option");
            }
            if (trefx < 0 || trefy < 0 || trefx > refx || trefy > refy)
            {
                throw new ArgumentException("Invalid value in 'tref' " + "option ");
            }

            // Instantiate tiler
            Tiler imgtiler;
            try
            {
                imgtiler = new Tiler(imgsrc, refx, refy, trefx, trefy, tw, th);
            }
            catch (ArgumentException e)
            {
                error("Could not tile image" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                return null;
            }
            int ntiles = imgtiler.getNumTiles();

            // **** Encoder specifications ****
            var encSpec = new EncoderSpecs(ntiles, ncomp, imgsrc, pl);

            // **** Component transformation ****
            if (ppminput && pl.getParameter("Mct") != null && pl.getParameter("Mct").Equals("off"))
            {
                FacilityManager.getMsgLogger()
                    .printmsg(
                        MsgLogger_Fields.WARNING,
                        "Input image is RGB and no color transform has "
                        + "been specified. Compression performance and "
                        + "image quality might be greatly degraded. Use "
                        + "the 'Mct' option to specify a color transform");
            }
            ForwCompTransf fctransf;
            try
            {
                fctransf = new ForwCompTransf(imgtiler, encSpec);
            }
            catch (ArgumentException e)
            {
                error(
                    "Could not instantiate forward component " + "transformation"
                    + ((e.Message != null) ? (":\n" + e.Message) : ""),
                    2);
                return null;
            }

            // **** ImgDataConverter ****
            var converter = new ImgDataConverter(fctransf);

            // **** ForwardWT ****
            ForwardWT dwt;
            try
            {
                dwt = ForwardWT.createInstance(converter, pl, encSpec);
            }
            catch (ArgumentException e)
            {
                error("Could not instantiate wavelet transform" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                return null;
            }

            // **** Quantizer ****
            Quantizer quant;
            try
            {
                quant = Quantizer.createInstance(dwt, encSpec);
            }
            catch (ArgumentException e)
            {
                error("Could not instantiate quantizer" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                return null;
            }

            // **** ROIScaler ****
            ROIScaler rois;
            try
            {
                rois = ROIScaler.createInstance(quant, pl, encSpec);
            }
            catch (ArgumentException e)
            {
                error("Could not instantiate ROI scaler" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                return null;
            }

            // **** EntropyCoder ****
            EntropyCoder ecoder;
            try
            {
                ecoder = EntropyCoder.createInstance(
                    rois,
                    pl,
                    encSpec.cblks,
                    encSpec.pss,
                    encSpec.bms,
                    encSpec.mqrs,
                    encSpec.rts,
                    encSpec.css,
                    encSpec.sss,
                    encSpec.lcs,
                    encSpec.tts);
            }
            catch (ArgumentException e)
            {
                error("Could not instantiate entropy coder" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                return null;
            }

            // **** CodestreamWriter ****
            using (var outStream = new MemoryStream())
            {
                CodestreamWriter bwriter;
                try
                {
                    // Rely on rate allocator to limit amount of data
                    bwriter = new FileCodestreamWriter(outStream, Int32.MaxValue);
                }
                catch (IOException e)
                {
                    error("Could not open output file" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                    return null;
                }

                // **** Rate allocator ****
                PostCompRateAllocator ralloc;
                try
                {
                    ralloc = PostCompRateAllocator.createInstance(ecoder, pl, rate, bwriter, encSpec);
                }
                catch (ArgumentException e)
                {
                    error("Could not instantiate rate allocator" + ((e.Message != null) ? (":\n" + e.Message) : ""), 2);
                    return null;
                }

                // **** HeaderEncoder ****
                var imsigned = Enumerable.Repeat(false, ncomp).ToArray();   // TODO Consider supporting signed components.
                var headenc = new HeaderEncoder(imgsrc, imsigned, dwt, imgtiler, encSpec, rois, ralloc, pl);
                ralloc.HeaderEncoder = headenc;

                // **** Write header to be able to estimate header overhead ****
                headenc.encodeMainHeader();

                // **** Initialize rate allocator, with proper header
                // overhead. This will also encode all the data ****
                ralloc.initialize();

                // **** Write header (final) ****
                headenc.reset();
                headenc.encodeMainHeader();

                // Insert header into the codestream
                bwriter.commitBitstreamHeader(headenc);

                // **** Now do the rate-allocation and write result ****
                ralloc.runAndWrite();

                // **** Done ****
                bwriter.close();

                // **** Calculate file length ****
                int fileLength = bwriter.Length;

                // **** Tile-parts and packed packet headers ****
                if (pktspertp > 0 || pphTile || pphMain)
                {
                    try
                    {
                        CodestreamManipulator cm = new CodestreamManipulator(
                            outStream,
                            ntiles,
                            pktspertp,
                            pphMain,
                            pphTile,
                            tempSop,
                            tempEph);
                        fileLength += cm.doCodestreamManipulation();
                        //String res="";
                        if (pktspertp > 0)
                        {
                            FacilityManager.getMsgLogger()
                                .println(
                                    "Created tile-parts " + "containing at most " + pktspertp + " packets per tile.",
                                    4,
                                    6);
                        }
                        if (pphTile)
                        {
                            FacilityManager.getMsgLogger().println("Moved packet headers " + "to tile headers", 4, 6);
                        }
                        if (pphMain)
                        {
                            FacilityManager.getMsgLogger().println("Moved packet headers " + "to main header", 4, 6);
                        }
                    }
                    catch (IOException e)
                    {
                        error(
                            "Error while creating tileparts or packed packet" + " headers"
                            + ((e.Message != null) ? (":\n" + e.Message) : ""),
                            2);
                        return null;
                    }
                }

                // **** File Format ****
                if (useFileFormat)
                {
                    try
                    {
                        int nc = imgsrc.NumComps;
                        int[] bpc = new int[nc];
                        for (int comp = 0; comp < nc; comp++)
                        {
                            bpc[comp] = imgsrc.getNomRangeBits(comp);
                        }

                        outStream.Seek(0, SeekOrigin.Begin);
                        var ffw = new FileFormatWriter(
                            outStream,
                            imgsrc.ImgHeight,
                            imgsrc.ImgWidth,
                            nc,
                            bpc,
                            fileLength);
                        fileLength += ffw.writeFileFormat();
                    }
                    catch (IOException e)
                    {
                        throw new InvalidOperationException("Error while writing JP2 file format: " + e.Message);
                    }
                }

                // **** Close image readers ***
                imgsrc.close();

                return outStream.ToArray();
            }
        }