예제 #1
0
        // the algorithm flow is based on:
        // https://bitmiracle.github.io/libjpeg.net/help/articles/KB/decompression-details.html
        private DecompressionResult DecompressJpgToRaw(byte[] image)
        {
            var cinfo = new jpeg_decompress_struct(new jpeg_error_mgr());

            using (var memoryStream = new MemoryStream(image))
            {
                cinfo.jpeg_stdio_src(memoryStream);
                cinfo.jpeg_read_header(true);

                cinfo.Out_color_space = J_COLOR_SPACE.JCS_RGB;

                cinfo.jpeg_start_decompress();

                // there are 3 components: R, G, B
                var rowStride    = 3 * cinfo.Output_width;
                var result       = new byte[rowStride * cinfo.Output_height];
                var resultOffset = 0;

                var buffer = new byte[1][];
                buffer[0] = new byte[rowStride];

                while (cinfo.Output_scanline < cinfo.Output_height)
                {
                    var ct = cinfo.jpeg_read_scanlines(buffer, 1);
                    if (ct > 0)
                    {
                        Array.Copy(buffer[0], 0, result, resultOffset, buffer[0].Length);
                        resultOffset += buffer[0].Length;
                    }
                }

                cinfo.jpeg_finish_decompress();
                return(new DecompressionResult(result, cinfo.Output_width, cinfo.Output_height));
            }
        }
예제 #2
0
        /// <summary>
        /// Decompresses JPEG image to any image described as ICompressDestination
        /// </summary>
        /// <param name="jpeg">Stream with JPEG data</param>
        /// <param name="destination">Stream for output of compressed JPEG</param>
        public void Decompress(Stream jpeg, IDecompressDestination destination)
        {
            if (jpeg == null)
            {
                throw new ArgumentNullException("jpeg");
            }

            if (destination == null)
            {
                throw new ArgumentNullException("destination");
            }

            beforeDecompress(jpeg);

            // Start decompression
            m_decompressor.jpeg_start_decompress();

            LoadedImageAttributes parameters = getImageParametersFromDecompressor();

            destination.SetImageAttributes(parameters);
            destination.BeginWrite();

            /* Process data */
            while (m_decompressor.Output_scanline < m_decompressor.Output_height)
            {
                byte[][] row = jpeg_common_struct.AllocJpegSamples(m_decompressor.Output_width * m_decompressor.Output_components, 1);
                m_decompressor.jpeg_read_scanlines(row, 1);
                destination.ProcessPixelsRow(row[0]);
            }

            destination.EndWrite();

            // Finish decompression and release memory.
            m_decompressor.jpeg_finish_decompress();
        }
예제 #3
0
        protected void decodeToStream()
        {
            var jpeg = new jpeg_decompress_struct(new LibJpegErrorHandler());

            startDecompression(jpeg);

            var buffer = new byte[jpeg.Output_width * jpeg.Output_components];

            var scanlines = new byte[1][];

            scanlines[0] = buffer;

            int height = jpeg.Output_height;

            for (int i = 0; i < height; i++)
            {
                if (jpeg.jpeg_read_scanlines(scanlines, 1) != 1)
                {
                    throw new InvalidProgramException("Failed to decompress JPEG image data.");
                }

                m_output.Write(buffer, 0, buffer.Length);
            }
        }
예제 #4
0
        private static void decompress(Stream input, DecompressOptions options, Stream output)
        {
            Debug.Assert(input != null);
            Debug.Assert(options != null);
            Debug.Assert(output != null);

            /* Initialize the JPEG decompression object with default error handling. */
            jpeg_decompress_struct cinfo = new jpeg_decompress_struct(new cd_jpeg_error_mgr());

            /* Insert custom marker processor for COM and APP12.
             * APP12 is used by some digital camera makers for textual info,
             * so we provide the ability to display it as text.
             * If you like, additional APPn marker types can be selected for display,
             * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
             */
            cinfo.jpeg_set_marker_processor((int)JPEG_MARKER.COM, new jpeg_decompress_struct.jpeg_marker_parser_method(printTextMarker));
            cinfo.jpeg_set_marker_processor((int)JPEG_MARKER.APP0 + 12, printTextMarker);

            /* Specify data source for decompression */
            cinfo.jpeg_stdio_src(input);

            /* Read file header, set default decompression parameters */
            cinfo.jpeg_read_header(true);

            applyOptions(cinfo, options);

            /* Initialize the output module now to let it override any crucial
             * option settings (for instance, GIF wants to force color quantization).
             */
            djpeg_dest_struct dest_mgr = null;

            switch (options.OutputFormat)
            {
            case IMAGE_FORMATS.FMT_BMP:
                dest_mgr = new bmp_dest_struct(cinfo, false);
                break;

            case IMAGE_FORMATS.FMT_OS2:
                dest_mgr = new bmp_dest_struct(cinfo, true);
                break;

            default:
                cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_UNSUPPORTED_FORMAT);
                break;
            }

            dest_mgr.output_file = output;

            /* Start decompressor */
            cinfo.jpeg_start_decompress();

            /* Write output file header */
            dest_mgr.start_output();

            /* Process data */
            while (cinfo.Output_scanline < cinfo.Output_height)
            {
                int num_scanlines = cinfo.jpeg_read_scanlines(dest_mgr.buffer, dest_mgr.buffer_height);
                dest_mgr.put_pixel_rows(num_scanlines);
            }

            /* Finish decompression and release memory.
             * I must do it in this order because output module has allocated memory
             * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
             */
            dest_mgr.finish_output();
            cinfo.jpeg_finish_decompress();

            /* All done. */
            if (cinfo.Err.Num_warnings != 0)
            {
                Console.WriteLine("Corrupt-data warning count is not zero");
            }
        }
예제 #5
0
        static string outfilename; /* for -outfile switch */

        public static void Main(string[] args)
        {
            progname = Path.GetFileName(Environment.GetCommandLineArgs()[0]);

            /* Initialize the JPEG decompression object with default error handling. */
            cd_jpeg_error_mgr      err   = new cd_jpeg_error_mgr();
            jpeg_decompress_struct cinfo = new jpeg_decompress_struct(err);

            /* Insert custom marker processor for COM and APP12.
             * APP12 is used by some digital camera makers for textual info,
             * so we provide the ability to display it as text.
             * If you like, additional APPn marker types can be selected for display,
             * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
             */
            cinfo.jpeg_set_marker_processor((int)JPEG_MARKER.COM, new jpeg_decompress_struct.jpeg_marker_parser_method(print_text_marker));
            cinfo.jpeg_set_marker_processor((int)JPEG_MARKER.APP0 + 12, print_text_marker);

            /* Scan command line to find file names. */

            /* It is convenient to use just one switch-parsing routine, but the switch
             * values read here are ignored; we will rescan the switches after opening
             * the input file.
             * (Exception: tracing level set here controls verbosity for COM markers
             * found during jpeg_read_header...)
             */
            int file_index;

            if (!parse_switches(cinfo, args, false, out file_index))
            {
                usage();
                return;
            }

            /* Must have either -outfile switch or explicit output file name */
            if (outfilename == null)
            {
                // file_index should point to input file
                if (file_index != args.Length - 2)
                {
                    Console.WriteLine(string.Format("{0}: must name one input and one output file.", progname));
                    usage();
                    return;
                }

                // output file comes right after input one
                outfilename = args[file_index + 1];
            }
            else
            {
                // file_index should point to input file
                if (file_index != args.Length - 1)
                {
                    Console.WriteLine(string.Format("{0}: must name one input and one output file.", progname));
                    usage();
                    return;
                }
            }

            /* Open the input file. */
            FileStream input_file = null;

            if (file_index < args.Length)
            {
                try
                {
                    input_file = new FileStream(args[file_index], FileMode.Open);
                }
                catch (Exception e)
                {
                    Console.WriteLine(string.Format("{0}: can't open {1}", progname, args[file_index]));
                    Console.WriteLine(e.Message);
                    return;
                }
            }
            else
            {
                Console.WriteLine(string.Format("{0}: sorry, can't read file from console"));
                return;
            }

            /* Open the output file. */
            FileStream output_file = null;

            if (outfilename != null)
            {
                try
                {
                    output_file = new FileStream(outfilename, FileMode.Create);
                }
                catch (Exception e)
                {
                    Console.WriteLine(string.Format("{0}: can't open {1}", progname, args[file_index]));
                    Console.WriteLine(e.Message);
                    return;
                }
            }
            else
            {
                Console.WriteLine(string.Format("{0}: sorry, can't write file to console"));
                return;
            }

            /* Specify data source for decompression */
            cinfo.jpeg_stdio_src(input_file);

            /* Read file header, set default decompression parameters */
            cinfo.jpeg_read_header(true);

            /* Adjust default decompression parameters by re-parsing the options */
            parse_switches(cinfo, args, true, out file_index);

            /* Initialize the output module now to let it override any crucial
             * option settings (for instance, GIF wants to force color quantization).
             */
            djpeg_dest_struct dest_mgr = null;

            switch (requested_fmt)
            {
            case IMAGE_FORMATS.FMT_BMP:
                dest_mgr = new bmp_dest_struct(cinfo, false);
                break;

            case IMAGE_FORMATS.FMT_OS2:
                dest_mgr = new bmp_dest_struct(cinfo, true);
                break;

            default:
                cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_UNSUPPORTED_FORMAT);
                break;
            }

            dest_mgr.output_file = output_file;

            /* Start decompressor */
            cinfo.jpeg_start_decompress();

            /* Write output file header */
            dest_mgr.start_output();

            /* Process data */
            while (cinfo.Output_scanline < cinfo.Output_height)
            {
                int num_scanlines = cinfo.jpeg_read_scanlines(dest_mgr.buffer, dest_mgr.buffer_height);
                dest_mgr.put_pixel_rows(num_scanlines);
            }

            /* Finish decompression and release memory.
             * I must do it in this order because output module has allocated memory
             * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
             */
            dest_mgr.finish_output();
            cinfo.jpeg_finish_decompress();

            /* Close files, if we opened them */
            input_file.Close();
            input_file.Dispose();

            output_file.Close();
            output_file.Dispose();

            /* All done. */
            if (cinfo.Err.Num_warnings != 0)
            {
                Console.WriteLine("Corrupt-data warning count is not zero");
            }
        }