2 // System.Drawing.Imaging.JPEGCodec.cs
5 // Alexandre Pigolkine (pigolkine@gmx.de)
7 // (C) 2002/2003 Ximian, Inc.
9 #if DECLARE_CDECL_DELEGATES
10 namespace cdeclCallback {
12 internal class cdeclRedirector {
13 internal delegate void MethodVoidIntPtr(IntPtr param);
14 internal delegate int MethodIntIntPtr(IntPtr param);
15 internal delegate void MethodVoidIntPtrInt(IntPtr param, int param1);
16 internal delegate int MethodIntIntPtrInt(IntPtr param,int param1);
17 internal delegate void MethodVoidIntPtrIntPtr(IntPtr png_structp,IntPtr png_const_charp);
18 internal delegate void MethodVoidIntPtrIntPtrInt(IntPtr png_structp,IntPtr bytep, int size);
23 namespace System.Drawing.Imaging
27 using System.Drawing.Imaging;
28 using System.Runtime.InteropServices;
32 /// Summary description for JPEGCodec.
34 internal class JPEGCodec
36 enum J_COLOR_SPACE : int {
37 JCS_UNKNOWN = 0, /* error/unspecified */
38 JCS_GRAYSCALE = 1, /* monochrome */
39 JCS_RGB = 2, /* red/green/blue */
40 JCS_YCbCr = 3, /* Y/Cb/Cr (also known as YUV) */
41 JCS_CMYK = 4, /* C/M/Y/K */
42 JCS_YCCK = 5 /* Y/Cb/Cr/K */
45 [StructLayout(LayoutKind.Sequential)]
46 internal struct jpeg_error_mgr_get {
53 [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=20)]
54 public int[] param_array;
55 public int trace_level;
56 public int num_warnings;
57 public int jpeg_message_table;
58 public int last_jpeg_message;
59 public int addon_message_table;
60 public int first_addon_message;
61 public int last_addon_message;
64 [StructLayout(LayoutKind.Sequential)]
65 internal struct jpeg_error_mgr {
66 public cdeclRedirector.MethodVoidIntPtr error_exit;
72 [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=20)]
73 public int[] param_array;
74 public int trace_level;
75 public int num_warnings;
76 public int jpeg_message_table;
77 public int last_jpeg_message;
78 public int addon_message_table;
79 public int first_addon_message;
80 public int last_addon_message;
83 [StructLayout(LayoutKind.Sequential)]
84 struct jpeg_source_mgr {
85 public IntPtr next_input_byte; /* => next byte to read from buffer */
86 public uint bytes_in_buffer; /* # of bytes remaining in buffer */
88 //[MarshalAs(UnmanagedType.FunctionPtr)]
89 public cdeclRedirector.MethodVoidIntPtr init_source;
90 //[MarshalAs(UnmanagedType.FunctionPtr)]
91 public cdeclRedirector.MethodIntIntPtr fill_input_buffer;
92 //[MarshalAs(UnmanagedType.FunctionPtr)]
93 public cdeclRedirector.MethodVoidIntPtrInt skip_input_data;
94 //[MarshalAs(UnmanagedType.FunctionPtr)]
95 public cdeclRedirector.MethodIntIntPtrInt resync_to_restart;
96 //[MarshalAs(UnmanagedType.FunctionPtr)]
97 public cdeclRedirector.MethodVoidIntPtr term_source;
100 [StructLayout(LayoutKind.Sequential)]
101 struct jpeg_destination_mgr {
102 public IntPtr next_output_byte; /* => next byte to write in buffer */
103 public uint free_in_buffer; /* # of byte spaces remaining in buffer */
105 //[MarshalAs(UnmanagedType.FunctionPtr)]
106 public cdeclRedirector.MethodVoidIntPtr init_destination;
107 //[MarshalAs(UnmanagedType.FunctionPtr)]
108 public cdeclRedirector.MethodIntIntPtr empty_output_buffer;
109 //[MarshalAs(UnmanagedType.FunctionPtr)]
110 public cdeclRedirector.MethodVoidIntPtr term_destination;
113 class jpeg_compress_decompress_base {
114 byte[] raw_struct_array;
115 IntPtr raw_error_mgr = IntPtr.Zero;
116 IntPtr raw_source_mgr = IntPtr.Zero;
117 IntPtr raw_destination_mgr = IntPtr.Zero;
119 internal struct structure_fields {
120 internal int structure_size;
121 internal int QUANTIZE_COLORS;
122 internal int ACTUAL_NUMBER_OF_COLORS;
123 internal int OUT_COLOR_SPACE;
124 internal int OUTPUT_WIDTH;
125 internal int OUTPUT_HEIGHT;
126 internal int OUT_COLOR_COMPONENT;
127 internal int OUTPUT_COMPONENTS;
128 internal int OUTPUT_SCANLINE;
129 internal int OUT_COLORMAP;
130 internal int IMAGE_WIDTH;
131 internal int IMAGE_HEIGHT;
132 internal int INPUT_COMPONENTS;
133 internal int IN_COLOR_SPACE;
134 internal int NEXT_SCAN_LINE;
137 structure_fields[] known_libraries;
138 int current_library_index;
140 public jpeg_compress_decompress_base(structure_fields[] known_libraries, int start_index) {
141 this.known_libraries = known_libraries;
142 current_library_index = start_index;
143 raw_struct_array = new byte[known_libraries[current_library_index].structure_size];
146 public void switch_to_struct_size(int size) {
147 if (raw_struct_array.Length == size) return;
149 bool structureFound = false;
150 for( int i = 0; i < known_libraries.Length; i++) {
151 if( known_libraries[i].structure_size == size) {
152 current_library_index = i;
153 raw_struct_array = new byte[known_libraries[current_library_index].structure_size];
154 structureFound = true;
158 if (!structureFound){
159 throw new Exception(String.Format("JPEG Codec cannot work with existing libjpeg.Structure size {0}.", size));
163 public byte[] raw_struct {
165 return raw_struct_array;
169 unsafe protected void copyToStruct( int value, int offset) {
170 fixed( byte* pd = raw_struct_array) {
171 *((int*)(pd + offset)) = value;
175 unsafe protected int copyFromStruct( int offset) {
177 fixed( byte* pd = raw_struct_array) {
178 result = *((int*)(pd + offset));
183 public jpeg_error_mgr jpeg_error_mgr {
185 raw_error_mgr = Marshal.AllocHGlobal(Marshal.SizeOf(value));
186 Marshal.StructureToPtr(value, raw_error_mgr, false);
187 copyToStruct(raw_error_mgr.ToInt32(), 0);
191 public jpeg_source_mgr jpeg_source_mgr {
193 raw_source_mgr = Marshal.AllocHGlobal( Marshal.SizeOf(value));
194 Marshal.StructureToPtr( value, raw_source_mgr, false);
195 copyToStruct(raw_source_mgr.ToInt32(), 24);
199 public jpeg_destination_mgr jpeg_destination_mgr {
201 raw_destination_mgr = Marshal.AllocHGlobal( Marshal.SizeOf(value));
202 Marshal.StructureToPtr( value, raw_destination_mgr, false);
203 copyToStruct(raw_destination_mgr.ToInt32(), 24);
209 return OutputWidth * OutputComponents;
213 public Color[] ColorMap {
215 int actual_number_of_colors = copyFromStruct(known_libraries[current_library_index].ACTUAL_NUMBER_OF_COLORS);
216 IntPtr nativeMap = (IntPtr)copyFromStruct(known_libraries[current_library_index].OUT_COLORMAP);
217 Color[] map = new Color[actual_number_of_colors];
218 if (nativeMap != IntPtr.Zero) {
219 byte[] byteMap = new byte[OutColorComponents * actual_number_of_colors];
220 Marshal.Copy( (IntPtr)Marshal.ReadInt32(nativeMap), byteMap, 0, byteMap.Length);
226 public J_COLOR_SPACE OutColorSpace {
228 return (J_COLOR_SPACE)copyFromStruct(known_libraries[current_library_index].OUT_COLOR_SPACE);
231 copyToStruct((int)value,known_libraries[current_library_index].OUT_COLOR_SPACE);
235 public bool QuantizeColors {
237 return raw_struct[known_libraries[current_library_index].QUANTIZE_COLORS] != (byte)0 ? true : false;
240 raw_struct[known_libraries[current_library_index].QUANTIZE_COLORS] = value ? (byte)1 : (byte)0;
244 public int OutputWidth {
246 return copyFromStruct(known_libraries[current_library_index].OUTPUT_WIDTH);
250 public int OutputHeight {
252 return copyFromStruct(known_libraries[current_library_index].OUTPUT_HEIGHT);
256 public int OutColorComponents {
258 return copyFromStruct(known_libraries[current_library_index].OUT_COLOR_COMPONENT);
262 public int OutputComponents {
264 return copyFromStruct(known_libraries[current_library_index].OUTPUT_COMPONENTS);
268 public int OutputScanLine {
270 return copyFromStruct(known_libraries[current_library_index].OUTPUT_SCANLINE);
274 public int ImageWidth {
276 copyToStruct(value, known_libraries[current_library_index].IMAGE_WIDTH);
280 public int ImageHeight {
282 return copyFromStruct(known_libraries[current_library_index].IMAGE_HEIGHT);
285 copyToStruct(value, known_libraries[current_library_index].IMAGE_HEIGHT);
289 public int InputComponents {
291 copyToStruct(value, known_libraries[current_library_index].INPUT_COMPONENTS);
295 public J_COLOR_SPACE InColorSpace {
297 copyToStruct((int)value, known_libraries[current_library_index].IN_COLOR_SPACE);
301 public int NextScanLine {
303 return copyFromStruct(known_libraries[current_library_index].NEXT_SCAN_LINE);
308 class jpeg_decompress_struct : jpeg_compress_decompress_base {
310 const int GNU_JPEG_DLL_WINDOWS = 0;
311 const int LINUX_LIBJPEG = 1;
312 const int KNOWN_JPEG_LINRARIES = 2;
314 static bool offsets_initialized;
315 static jpeg_compress_decompress_base.structure_fields[] known_jpeg_libraries;
316 static int current_library_index = LINUX_LIBJPEG;
318 static void initialize_jpeg_decompress_structs() {
319 if (!offsets_initialized) {
320 known_jpeg_libraries = new jpeg_compress_decompress_base.structure_fields[KNOWN_JPEG_LINRARIES];
321 // GNU JPEG Windows version
322 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].structure_size = 432;
323 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].QUANTIZE_COLORS = 74;
324 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].ACTUAL_NUMBER_OF_COLORS = 112;
325 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLOR_SPACE = 44;
326 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_WIDTH = 92;
327 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_HEIGHT = 96;
328 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLOR_COMPONENT = 100;
329 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_COMPONENTS = 104;
330 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_SCANLINE = 120;
331 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLORMAP = 116;
333 // libjpeg Linux version
334 known_jpeg_libraries[LINUX_LIBJPEG].structure_size = 464;
335 known_jpeg_libraries[LINUX_LIBJPEG].QUANTIZE_COLORS = 84;
336 known_jpeg_libraries[LINUX_LIBJPEG].ACTUAL_NUMBER_OF_COLORS = 132;
337 known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLOR_SPACE = 44;
338 known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_WIDTH = 112;
339 known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_HEIGHT = 116;
340 known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLOR_COMPONENT = 120;
341 known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_COMPONENTS = 124;
342 known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_SCANLINE = 140;
343 known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLORMAP = 136;
345 offsets_initialized = true;
349 static jpeg_decompress_struct() {
350 initialize_jpeg_decompress_structs();
353 public jpeg_decompress_struct() : base(known_jpeg_libraries, LINUX_LIBJPEG) {
357 class jpeg_compress_struct : jpeg_compress_decompress_base {
359 const int GNU_JPEG_DLL_WINDOWS = 0;
360 const int LINUX_LIBJPEG = 1;
361 const int KNOWN_JPEG_LINRARIES = 2;
363 static bool offsets_initialized;
364 static jpeg_compress_decompress_base.structure_fields[] known_jpeg_libraries;
365 static int current_library_index = LINUX_LIBJPEG;
367 static void initialize_jpeg_compress_structs() {
368 if (!offsets_initialized) {
369 known_jpeg_libraries = new jpeg_compress_decompress_base.structure_fields[KNOWN_JPEG_LINRARIES];
370 // GNU JPEG Windows version
371 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].structure_size = 360;
372 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IMAGE_WIDTH = 28;
373 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IMAGE_HEIGHT = 32;
374 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].INPUT_COMPONENTS = 36;
375 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IN_COLOR_SPACE = 40;
376 known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].NEXT_SCAN_LINE = 208;
378 // libjpeg Linux version
379 known_jpeg_libraries[LINUX_LIBJPEG].structure_size = 372;
380 known_jpeg_libraries[LINUX_LIBJPEG].IMAGE_WIDTH = 28;
381 known_jpeg_libraries[LINUX_LIBJPEG].IMAGE_HEIGHT = 32;
382 known_jpeg_libraries[LINUX_LIBJPEG].INPUT_COMPONENTS = 36;
383 known_jpeg_libraries[LINUX_LIBJPEG].IN_COLOR_SPACE = 40;
384 known_jpeg_libraries[LINUX_LIBJPEG].NEXT_SCAN_LINE = 220;
386 offsets_initialized = true;
390 static jpeg_compress_struct() {
391 initialize_jpeg_compress_structs();
394 public jpeg_compress_struct() : base(known_jpeg_libraries, LINUX_LIBJPEG) {
398 [StructLayout(LayoutKind.Sequential)]
399 internal struct JSAMPARRAY {
400 // FIXME: This code is not working on Mono(** ERROR **: Invalid IL code at...). Report a bug and change it later.
401 //const int MAX_SCAN_LINES = 10;
402 //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=MAX_SCAN_LINES)]
403 //internal IntPtr[] JSAMPLES;
404 internal IntPtr JSAMPLE0;
405 internal IntPtr JSAMPLE1;
407 internal JSAMPARRAY(int len) {
409 JSAMPLES = new IntPtr[MAX_SCAN_LINES];
410 for (int i = 0; i < MAX_SCAN_LINES; i++) {
411 JSAMPLES[i] = Marshal.AllocHGlobal(len);
414 JSAMPLE0 = Marshal.AllocHGlobal(len);
415 JSAMPLE1 = Marshal.AllocHGlobal(len);
418 internal void Dispose() {
420 for (int i = 0; i < MAX_SCAN_LINES; i++) {
421 Marshal.FreeHGlobal(JSAMPLES[i]);
424 Marshal.FreeHGlobal(JSAMPLE0);
425 Marshal.FreeHGlobal(JSAMPLE1);
429 const string JPEGLibrary = "jpeg";
430 [DllImport(JPEGLibrary, EntryPoint="jpeg_CreateCompress", CallingConvention=CallingConvention.Cdecl)]
431 internal static extern void jpeg_create_compress(byte[] info, int version, int structure_size);
433 [DllImport(JPEGLibrary, EntryPoint="jpeg_CreateDecompress", CallingConvention=CallingConvention.Cdecl)]
434 internal static extern void jpeg_create_decompress(byte[] info, int version, int structure_size);
436 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
437 internal static extern void jpeg_std_error(ref jpeg_error_mgr_get err_mgr);
439 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
440 internal static extern void jpeg_set_defaults(byte[] cinfo);
442 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
443 internal static extern void jpeg_set_quality(byte[] cinfo, int quality, int force_baseline);
\r
445 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
446 internal static extern int jpeg_read_header(byte[] cinfo, int condition);
448 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
449 internal static extern void jpeg_calc_output_dimensions(byte[] cinfo);
451 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
452 internal static extern int jpeg_start_compress(byte[] cinfo, int write_all_tables);
454 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
455 internal static extern int jpeg_start_decompress(byte[] cinfo);
457 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
458 internal static extern int jpeg_read_scanlines(byte[] cinfo, ref JSAMPARRAY buffer, int num);
460 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
461 internal static extern int jpeg_write_scanlines(byte[] cinfo, ref JSAMPARRAY scanlines, int num_lines);
\r
463 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
464 internal static extern int jpeg_finish_compress(byte[] cinfo);
466 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
467 internal static extern int jpeg_finish_decompress(byte[] cinfo);
469 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
470 internal static extern void jpeg_destroy_compress(byte[] cinfo);
472 [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
473 internal static extern void jpeg_destroy_decompress(byte[] cinfo);
477 int readwriteSize = 4096;
479 // Source manager callbacks
480 void init_source( IntPtr cinfo) {
481 buffer = Marshal.AllocHGlobal(readwriteSize);
484 int fill_input_buffer( IntPtr cinfo) {
485 byte[] result = new byte[readwriteSize];
486 int readed = fs.Read(result, 0, readwriteSize);
487 Marshal.Copy(result, 0, buffer, readed);
488 IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
489 Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
490 Marshal.WriteInt32(srcAddr, 4, readed);
494 void skip_input_data( IntPtr cinfo, int num_bytes) {
495 //byte[] result = new byte[num_bytes];
496 //fs.Read(result, 0, num_bytes);
497 fs.Seek(num_bytes, SeekOrigin.Current);
500 int resync_to_restart( IntPtr cinfo, int desired){
504 void term_source( IntPtr cinfo) {
505 Marshal.FreeHGlobal(buffer);
508 // Destination manager callbacks
509 void init_destination( IntPtr cinfo) {
510 buffer = Marshal.AllocHGlobal(readwriteSize);
511 IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
512 Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
513 Marshal.WriteInt32(srcAddr, 4, readwriteSize);
516 int empty_output_buffer( IntPtr cinfo) {
517 IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
518 IntPtr bufferPtr = (IntPtr)Marshal.ReadInt32(srcAddr, 0);
519 int bytes = readwriteSize - Marshal.ReadInt32(srcAddr, 4);
521 // FIXME: shall we have a buffer as a member variable here ?
522 byte[] result = new byte[readwriteSize];
523 Marshal.Copy(buffer, result, 0, readwriteSize);
524 fs.Write(result, 0, readwriteSize);
525 Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
526 Marshal.WriteInt32(srcAddr, 4, readwriteSize);
530 void term_destination( IntPtr cinfo) {
531 IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
532 IntPtr bufferPtr = (IntPtr)Marshal.ReadInt32(srcAddr, 0);
533 int bytes = readwriteSize - Marshal.ReadInt32(srcAddr, 4);
534 byte[] result = new byte[bytes];
535 Marshal.Copy(buffer, result, 0, bytes);
536 fs.Write(result, 0, bytes);
537 Marshal.FreeHGlobal(buffer);
540 class RetryInitializationException : Exception {
541 int libraryStructureSize;
542 public RetryInitializationException(int structureSize) {
543 this.libraryStructureSize = structureSize;
545 public int LibraryStructureSize {
547 return libraryStructureSize;
552 enum JPEGErrorCodes : int {
553 JERR_BAD_STRUCT_SIZE = 21
556 void error_exit( IntPtr cinfo) {
557 jpeg_error_mgr mgr = new jpeg_error_mgr();
558 IntPtr err_raw = (IntPtr)Marshal.ReadInt32(cinfo, 0);
559 mgr = (jpeg_error_mgr)Marshal.PtrToStructure(err_raw, mgr.GetType());
560 if ( mgr.msg_code == (int)JPEGErrorCodes.JERR_BAD_STRUCT_SIZE) {
561 throw new RetryInitializationException(mgr.param_array[0]);
563 throw new Exception();
566 internal JPEGCodec() {
569 internal static ImageCodecInfo CodecInfo {
571 ImageCodecInfo info = new ImageCodecInfo();
572 info.Flags = ImageCodecFlags.Encoder | ImageCodecFlags.Decoder | ImageCodecFlags.Builtin | ImageCodecFlags.SupportBitmap;
573 info.FormatDescription = "JPEG file format";
574 info.FormatID = System.Drawing.Imaging.ImageFormat.Jpeg.Guid;
575 info.MimeType = "image/jpeg";
577 byte[][] signaturePatterns = new byte[1][];
578 signaturePatterns[0] = new byte[]{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00};
579 info.SignaturePatterns = signaturePatterns;
580 byte[][] signatureMasks = new byte[1][];
581 signatureMasks[0] = new byte[]{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
582 info.SignatureMasks = signatureMasks;
583 info.decode += new ImageCodecInfo.DecodeFromStream(JPEGCodec.DecodeDelegate);
584 info.encode += new ImageCodecInfo.EncodeToStream(JPEGCodec.EncodeDelegate);
589 internal static void DecodeDelegate (Stream stream, InternalImageInfo info) {
590 JPEGCodec jpeg = new JPEGCodec();
591 jpeg.Decode (stream, info);
594 internal static void EncodeDelegate (Stream stream, InternalImageInfo info) {
595 JPEGCodec jpeg = new JPEGCodec();
596 jpeg.Encode (stream, info);
599 internal unsafe void switch_color_bytes( byte[] image) {
600 fixed(byte* start = image) {
603 for( int ic = 0; ic < image.Length; ic +=3) {
612 internal bool Decode( Stream stream, InternalImageInfo info) {
615 jpeg_error_mgr_get mgr = new jpeg_error_mgr_get();
616 mgr.param_array = new int[20];
617 jpeg_std_error( ref mgr);
618 jpeg_error_mgr mgr_real = new jpeg_error_mgr();
619 mgr_real.param_array = new int[20];
620 mgr_real.error_exit = new cdeclCallback.cdeclRedirector.MethodVoidIntPtr(this.error_exit);
621 mgr_real.msg_code = mgr.msg_code;
622 mgr_real.a2 = mgr.a2;
623 mgr_real.a3 = mgr.a3;
624 mgr_real.a4 = mgr.a4;
625 mgr_real.a5 = mgr.a5;
626 mgr_real.trace_level = mgr.trace_level;
627 mgr_real.num_warnings = mgr.num_warnings;
628 mgr_real.last_jpeg_message = mgr.last_jpeg_message;
629 mgr_real.first_addon_message = mgr.first_addon_message;
630 mgr_real.last_addon_message = mgr.last_addon_message;
631 mgr_real.jpeg_message_table = mgr.jpeg_message_table;
633 jpeg_decompress_struct cinfo = new jpeg_decompress_struct();
634 cinfo.jpeg_error_mgr = mgr_real;
635 bool initializedOk = false;
638 jpeg_create_decompress(cinfo.raw_struct, 62, cinfo.raw_struct.Length);
639 initializedOk = true;
641 catch( RetryInitializationException ex) {
642 initializedOk = false;
643 cinfo.switch_to_struct_size(ex.LibraryStructureSize);
644 cinfo.jpeg_error_mgr = mgr_real;
646 }while( !initializedOk);
648 jpeg_source_mgr smgr = new jpeg_source_mgr();
649 smgr.next_input_byte = IntPtr.Zero;
650 smgr.bytes_in_buffer = 0;
652 smgr.init_source = new cdeclRedirector.MethodVoidIntPtr(this.init_source);
653 smgr.fill_input_buffer = new cdeclRedirector.MethodIntIntPtr(this.fill_input_buffer);
654 smgr.skip_input_data = new cdeclRedirector.MethodVoidIntPtrInt(this.skip_input_data);
655 smgr.resync_to_restart = new cdeclRedirector.MethodIntIntPtrInt(this.resync_to_restart);
656 smgr.term_source = new cdeclRedirector.MethodVoidIntPtr(this.term_source);
657 cinfo.jpeg_source_mgr = smgr;
659 jpeg_read_header( cinfo.raw_struct, 1);
661 jpeg_calc_output_dimensions(cinfo.raw_struct);
662 jpeg_start_decompress(cinfo.raw_struct);
664 int row_width = cinfo.Stride;
665 while ((row_width & 3) != 0) row_width++;
666 int pad_bytes = (row_width - cinfo.Stride);
668 if (cinfo.OutColorSpace == J_COLOR_SPACE.JCS_RGB) {
669 if (cinfo.QuantizeColors) {
670 info.PixelFormat = PixelFormat.Format8bppIndexed;
673 info.PixelFormat = PixelFormat.Format24bppRgb;
677 info.PixelFormat = PixelFormat.Format8bppIndexed;
679 info.Size = new Size(cinfo.OutputWidth,cinfo.OutputHeight);
680 info.Stride = row_width;
681 info.Palette = new ColorPalette(1, cinfo.ColorMap);
682 info.PixelFormat = PixelFormat.Format24bppRgb;
683 info.RawImageBytes = new byte[(cinfo.OutputHeight) * row_width];
685 JSAMPARRAY outbuf = new JSAMPARRAY(cinfo.Stride);
686 int outputIndex = info.RawImageBytes.Length - row_width;
688 while (cinfo.OutputScanLine < cinfo.OutputHeight) {
689 // FIXME: switch to the Length after fixing a run-time error
690 int readed = jpeg_read_scanlines(cinfo.raw_struct, ref outbuf, 1 /*outbuf.JSAMPLES.Length*/);
691 for (int i = 0; i < readed; i++) {
692 // FIXME: switch to .JSAMPLES[i] after fix of run-time error
693 //Marshal.Copy(outbuf.JSAMPLES[i], info.RawImageBytes, outputIndex, cinfo.Stride);
694 Marshal.Copy(outbuf.JSAMPLE0, info.RawImageBytes, outputIndex, cinfo.Stride);
695 outputIndex -= row_width;
698 // FIXME: not sure if this always works
699 switch_color_bytes(info.RawImageBytes);
700 jpeg_finish_decompress(cinfo.raw_struct);
701 jpeg_destroy_decompress(cinfo.raw_struct);
705 internal unsafe bool Encode( Stream stream, InternalImageInfo info) {
707 int bpp = Image.GetPixelFormatSize(info.PixelFormat) / 8;
708 if( bpp != 3 && bpp != 4) {
709 throw new ArgumentException(String.Format("Supplied pixel format is not yet supported: {0}, {1} bpp", info.PixelFormat, Image.GetPixelFormatSize(info.PixelFormat)));
714 jpeg_error_mgr_get mgr = new jpeg_error_mgr_get();
715 mgr.param_array = new int[20];
716 jpeg_std_error( ref mgr);
717 jpeg_error_mgr mgr_real = new jpeg_error_mgr();
718 mgr_real.param_array = new int[20];
719 mgr_real.error_exit = new cdeclCallback.cdeclRedirector.MethodVoidIntPtr(this.error_exit);
720 mgr_real.msg_code = mgr.msg_code;
721 mgr_real.a2 = mgr.a2;
722 mgr_real.a3 = mgr.a3;
723 mgr_real.a4 = mgr.a4;
724 mgr_real.a5 = mgr.a5;
725 mgr_real.trace_level = mgr.trace_level;
726 mgr_real.num_warnings = mgr.num_warnings;
727 mgr_real.last_jpeg_message = mgr.last_jpeg_message;
728 mgr_real.first_addon_message = mgr.first_addon_message;
729 mgr_real.last_addon_message = mgr.last_addon_message;
730 mgr_real.jpeg_message_table = mgr.jpeg_message_table;
732 jpeg_compress_struct cinfo = new jpeg_compress_struct();
733 cinfo.jpeg_error_mgr = mgr_real;
734 bool initializedOk = false;
737 jpeg_create_compress(cinfo.raw_struct, 62, cinfo.raw_struct.Length);
738 initializedOk = true;
740 catch( RetryInitializationException ex) {
741 initializedOk = false;
742 cinfo.switch_to_struct_size(ex.LibraryStructureSize);
743 cinfo.jpeg_error_mgr = mgr_real;
745 }while( !initializedOk);
747 jpeg_destination_mgr dmgr = new jpeg_destination_mgr();
748 dmgr.next_output_byte = IntPtr.Zero;
749 dmgr.free_in_buffer = 0;
751 dmgr.init_destination = new cdeclRedirector.MethodVoidIntPtr(this.init_destination);
752 dmgr.empty_output_buffer = new cdeclRedirector.MethodIntIntPtr(this.empty_output_buffer);
753 dmgr.term_destination = new cdeclRedirector.MethodVoidIntPtr(this.term_destination);
754 cinfo.jpeg_destination_mgr = dmgr;
756 int row_width = info.Size.Width;
757 while ((row_width & 3) != 0) row_width++;
759 cinfo.ImageWidth = info.Size.Width;
760 cinfo.ImageHeight = info.Size.Height;
761 cinfo.InputComponents = 3;
762 cinfo.InColorSpace = J_COLOR_SPACE.JCS_RGB;
764 jpeg_set_defaults( cinfo.raw_struct);
766 jpeg_start_compress( cinfo.raw_struct, 1);
768 int row_bytes_width = row_width * 3;
769 int src_row_bytes_width = row_width * bpp;
770 JSAMPARRAY inbuf = new JSAMPARRAY(row_bytes_width);
772 int outputIndex = info.RawImageBytes.Length - src_row_bytes_width;
773 byte[] buffer = new byte[row_bytes_width];
774 fixed( byte *psrc = info.RawImageBytes, pbuf = buffer) {
777 while (cinfo.NextScanLine < cinfo.ImageHeight) {
778 curSrc = psrc + outputIndex;
780 for( int i = 0; i < row_width; i++) {
781 *curDst++ = *(curSrc+2);
782 *curDst++ = *(curSrc+1);
786 Marshal.Copy( buffer, 0, inbuf.JSAMPLE0, row_bytes_width);
787 outputIndex -= src_row_bytes_width;
788 jpeg_write_scanlines(cinfo.raw_struct, ref inbuf, 1 /*inbuf.JSAMPLES.Length*/);
792 jpeg_finish_compress(cinfo.raw_struct);
793 jpeg_destroy_compress(cinfo.raw_struct);