JPEGCodec.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. //
  2. // System.Drawing.Imaging.JPEGCodec.cs
  3. //
  4. // Author:
  5. // Alexandre Pigolkine ([email protected])
  6. //
  7. // (C) 2002/2003 Ximian, Inc.
  8. #if DECLARE_CDECL_DELEGATES
  9. namespace cdeclCallback {
  10. using System;
  11. internal class cdeclRedirector {
  12. internal delegate void MethodVoidIntPtr(IntPtr param);
  13. internal delegate int MethodIntIntPtr(IntPtr param);
  14. internal delegate void MethodVoidIntPtrInt(IntPtr param, int param1);
  15. internal delegate int MethodIntIntPtrInt(IntPtr param,int param1);
  16. }
  17. }
  18. #endif
  19. namespace System.Drawing.Imaging
  20. {
  21. using System;
  22. using System.IO;
  23. using System.Drawing.Imaging;
  24. using System.Runtime.InteropServices;
  25. using cdeclCallback;
  26. /// <summary>
  27. /// Summary description for JPEGCodec.
  28. /// </summary>
  29. internal class JPEGCodec
  30. {
  31. enum J_COLOR_SPACE : int {
  32. JCS_UNKNOWN = 0, /* error/unspecified */
  33. JCS_GRAYSCALE = 1, /* monochrome */
  34. JCS_RGB = 2, /* red/green/blue */
  35. JCS_YCbCr = 3, /* Y/Cb/Cr (also known as YUV) */
  36. JCS_CMYK = 4, /* C/M/Y/K */
  37. JCS_YCCK = 5 /* Y/Cb/Cr/K */
  38. }
  39. [StructLayout(LayoutKind.Sequential)]
  40. internal struct jpeg_error_mgr_get {
  41. public IntPtr a1;
  42. public IntPtr a2;
  43. public IntPtr a3;
  44. public IntPtr a4;
  45. public IntPtr a5;
  46. public int msg_code;
  47. [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=20)]
  48. public int[] param_array;
  49. public int trace_level;
  50. public int num_warnings;
  51. public int jpeg_message_table;
  52. public int last_jpeg_message;
  53. public int addon_message_table;
  54. public int first_addon_message;
  55. public int last_addon_message;
  56. };
  57. [StructLayout(LayoutKind.Sequential)]
  58. internal struct jpeg_error_mgr {
  59. public cdeclRedirector.MethodVoidIntPtr error_exit;
  60. public IntPtr a2;
  61. public IntPtr a3;
  62. public IntPtr a4;
  63. public IntPtr a5;
  64. public int msg_code;
  65. [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=20)]
  66. public int[] param_array;
  67. public int trace_level;
  68. public int num_warnings;
  69. public int jpeg_message_table;
  70. public int last_jpeg_message;
  71. public int addon_message_table;
  72. public int first_addon_message;
  73. public int last_addon_message;
  74. };
  75. [StructLayout(LayoutKind.Sequential)]
  76. struct jpeg_source_mgr {
  77. public IntPtr next_input_byte; /* => next byte to read from buffer */
  78. public uint bytes_in_buffer; /* # of bytes remaining in buffer */
  79. //[MarshalAs(UnmanagedType.FunctionPtr)]
  80. public cdeclRedirector.MethodVoidIntPtr init_source;
  81. //[MarshalAs(UnmanagedType.FunctionPtr)]
  82. public cdeclRedirector.MethodIntIntPtr fill_input_buffer;
  83. //[MarshalAs(UnmanagedType.FunctionPtr)]
  84. public cdeclRedirector.MethodVoidIntPtrInt skip_input_data;
  85. //[MarshalAs(UnmanagedType.FunctionPtr)]
  86. public cdeclRedirector.MethodIntIntPtrInt resync_to_restart;
  87. //[MarshalAs(UnmanagedType.FunctionPtr)]
  88. public cdeclRedirector.MethodVoidIntPtr term_source;
  89. };
  90. [StructLayout(LayoutKind.Sequential)]
  91. struct jpeg_destination_mgr {
  92. public IntPtr next_output_byte; /* => next byte to write in buffer */
  93. public uint free_in_buffer; /* # of byte spaces remaining in buffer */
  94. //[MarshalAs(UnmanagedType.FunctionPtr)]
  95. public cdeclRedirector.MethodVoidIntPtr init_destination;
  96. //[MarshalAs(UnmanagedType.FunctionPtr)]
  97. public cdeclRedirector.MethodIntIntPtr empty_output_buffer;
  98. //[MarshalAs(UnmanagedType.FunctionPtr)]
  99. public cdeclRedirector.MethodVoidIntPtr term_destination;
  100. };
  101. class jpeg_compress_decompress_base {
  102. byte[] raw_struct_array;
  103. IntPtr raw_error_mgr = IntPtr.Zero;
  104. IntPtr raw_source_mgr = IntPtr.Zero;
  105. IntPtr raw_destination_mgr = IntPtr.Zero;
  106. internal struct structure_fields {
  107. internal int structure_size;
  108. internal int QUANTIZE_COLORS;
  109. internal int ACTUAL_NUMBER_OF_COLORS;
  110. internal int OUT_COLOR_SPACE;
  111. internal int OUTPUT_WIDTH;
  112. internal int OUTPUT_HEIGHT;
  113. internal int OUT_COLOR_COMPONENT;
  114. internal int OUTPUT_COMPONENTS;
  115. internal int OUTPUT_SCANLINE;
  116. internal int OUT_COLORMAP;
  117. internal int IMAGE_WIDTH;
  118. internal int IMAGE_HEIGHT;
  119. internal int INPUT_COMPONENTS;
  120. internal int IN_COLOR_SPACE;
  121. internal int NEXT_SCAN_LINE;
  122. };
  123. structure_fields[] known_libraries;
  124. int current_library_index;
  125. public jpeg_compress_decompress_base(structure_fields[] known_libraries, int start_index) {
  126. this.known_libraries = known_libraries;
  127. current_library_index = start_index;
  128. raw_struct_array = new byte[known_libraries[current_library_index].structure_size];
  129. }
  130. public void switch_to_struct_size(int size) {
  131. if (raw_struct_array.Length == size) return;
  132. bool structureFound = false;
  133. for( int i = 0; i < known_libraries.Length; i++) {
  134. if( known_libraries[i].structure_size == size) {
  135. current_library_index = i;
  136. raw_struct_array = new byte[known_libraries[current_library_index].structure_size];
  137. structureFound = true;
  138. break;
  139. }
  140. }
  141. if (!structureFound){
  142. throw new Exception(String.Format("JPEG Codec cannot work with existing libjpeg.Structure size {0}.", size));
  143. }
  144. }
  145. public byte[] raw_struct {
  146. get {
  147. return raw_struct_array;
  148. }
  149. }
  150. unsafe protected void copyToStruct( int value, int offset) {
  151. fixed( byte* pd = raw_struct_array) {
  152. *((int*)(pd + offset)) = value;
  153. }
  154. }
  155. unsafe protected int copyFromStruct( int offset) {
  156. int result = 0;
  157. fixed( byte* pd = raw_struct_array) {
  158. result = *((int*)(pd + offset));
  159. }
  160. return result;
  161. }
  162. public jpeg_error_mgr jpeg_error_mgr {
  163. set {
  164. raw_error_mgr = Marshal.AllocHGlobal(Marshal.SizeOf(value));
  165. Marshal.StructureToPtr(value, raw_error_mgr, false);
  166. copyToStruct(raw_error_mgr.ToInt32(), 0);
  167. }
  168. }
  169. public jpeg_source_mgr jpeg_source_mgr {
  170. set {
  171. raw_source_mgr = Marshal.AllocHGlobal( Marshal.SizeOf(value));
  172. Marshal.StructureToPtr( value, raw_source_mgr, false);
  173. copyToStruct(raw_source_mgr.ToInt32(), 24);
  174. }
  175. }
  176. public jpeg_destination_mgr jpeg_destination_mgr {
  177. set {
  178. raw_destination_mgr = Marshal.AllocHGlobal( Marshal.SizeOf(value));
  179. Marshal.StructureToPtr( value, raw_destination_mgr, false);
  180. copyToStruct(raw_destination_mgr.ToInt32(), 24);
  181. }
  182. }
  183. public int Stride {
  184. get {
  185. return OutputWidth * OutputComponents;
  186. }
  187. }
  188. public Color[] ColorMap {
  189. get {
  190. int actual_number_of_colors = copyFromStruct(known_libraries[current_library_index].ACTUAL_NUMBER_OF_COLORS);
  191. IntPtr nativeMap = (IntPtr)copyFromStruct(known_libraries[current_library_index].OUT_COLORMAP);
  192. Color[] map = new Color[actual_number_of_colors];
  193. if (nativeMap != IntPtr.Zero) {
  194. byte[] byteMap = new byte[OutColorComponents * actual_number_of_colors];
  195. Marshal.Copy( (IntPtr)Marshal.ReadInt32(nativeMap), byteMap, 0, byteMap.Length);
  196. }
  197. return map;
  198. }
  199. }
  200. public J_COLOR_SPACE OutColorSpace {
  201. get {
  202. return (J_COLOR_SPACE)copyFromStruct(known_libraries[current_library_index].OUT_COLOR_SPACE);
  203. }
  204. set {
  205. copyToStruct((int)value,known_libraries[current_library_index].OUT_COLOR_SPACE);
  206. }
  207. }
  208. public bool QuantizeColors {
  209. get {
  210. return raw_struct[known_libraries[current_library_index].QUANTIZE_COLORS] != (byte)0 ? true : false;
  211. }
  212. set {
  213. raw_struct[known_libraries[current_library_index].QUANTIZE_COLORS] = value ? (byte)1 : (byte)0;
  214. }
  215. }
  216. public int OutputWidth {
  217. get {
  218. return copyFromStruct(known_libraries[current_library_index].OUTPUT_WIDTH);
  219. }
  220. }
  221. public int OutputHeight {
  222. get {
  223. return copyFromStruct(known_libraries[current_library_index].OUTPUT_HEIGHT);
  224. }
  225. }
  226. public int OutColorComponents {
  227. get {
  228. return copyFromStruct(known_libraries[current_library_index].OUT_COLOR_COMPONENT);
  229. }
  230. }
  231. public int OutputComponents {
  232. get {
  233. return copyFromStruct(known_libraries[current_library_index].OUTPUT_COMPONENTS);
  234. }
  235. }
  236. public int OutputScanLine {
  237. get {
  238. return copyFromStruct(known_libraries[current_library_index].OUTPUT_SCANLINE);
  239. }
  240. }
  241. public int ImageWidth {
  242. set {
  243. copyToStruct(value, known_libraries[current_library_index].IMAGE_WIDTH);
  244. }
  245. }
  246. public int ImageHeight {
  247. get {
  248. return copyFromStruct(known_libraries[current_library_index].IMAGE_HEIGHT);
  249. }
  250. set {
  251. copyToStruct(value, known_libraries[current_library_index].IMAGE_HEIGHT);
  252. }
  253. }
  254. public int InputComponents {
  255. set {
  256. copyToStruct(value, known_libraries[current_library_index].INPUT_COMPONENTS);
  257. }
  258. }
  259. public J_COLOR_SPACE InColorSpace {
  260. set {
  261. copyToStruct((int)value, known_libraries[current_library_index].IN_COLOR_SPACE);
  262. }
  263. }
  264. public int NextScanLine {
  265. get {
  266. return copyFromStruct(known_libraries[current_library_index].NEXT_SCAN_LINE);
  267. }
  268. }
  269. }
  270. class jpeg_decompress_struct : jpeg_compress_decompress_base {
  271. const int GNU_JPEG_DLL_WINDOWS = 0;
  272. const int LINUX_LIBJPEG = 1;
  273. const int KNOWN_JPEG_LINRARIES = 2;
  274. static bool offsets_initialized;
  275. static jpeg_compress_decompress_base.structure_fields[] known_jpeg_libraries;
  276. static int current_library_index = LINUX_LIBJPEG;
  277. static void initialize_jpeg_decompress_structs() {
  278. if (!offsets_initialized) {
  279. known_jpeg_libraries = new jpeg_compress_decompress_base.structure_fields[KNOWN_JPEG_LINRARIES];
  280. // GNU JPEG Windows version
  281. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].structure_size = 432;
  282. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].QUANTIZE_COLORS = 74;
  283. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].ACTUAL_NUMBER_OF_COLORS = 112;
  284. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLOR_SPACE = 44;
  285. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_WIDTH = 92;
  286. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_HEIGHT = 96;
  287. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLOR_COMPONENT = 100;
  288. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_COMPONENTS = 104;
  289. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUTPUT_SCANLINE = 120;
  290. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].OUT_COLORMAP = 116;
  291. // libjpeg Linux version
  292. known_jpeg_libraries[LINUX_LIBJPEG].structure_size = 464;
  293. known_jpeg_libraries[LINUX_LIBJPEG].QUANTIZE_COLORS = 84;
  294. known_jpeg_libraries[LINUX_LIBJPEG].ACTUAL_NUMBER_OF_COLORS = 132;
  295. known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLOR_SPACE = 44;
  296. known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_WIDTH = 112;
  297. known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_HEIGHT = 116;
  298. known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLOR_COMPONENT = 120;
  299. known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_COMPONENTS = 124;
  300. known_jpeg_libraries[LINUX_LIBJPEG].OUTPUT_SCANLINE = 140;
  301. known_jpeg_libraries[LINUX_LIBJPEG].OUT_COLORMAP = 136;
  302. offsets_initialized = true;
  303. }
  304. }
  305. static jpeg_decompress_struct() {
  306. initialize_jpeg_decompress_structs();
  307. }
  308. public jpeg_decompress_struct() : base(known_jpeg_libraries, LINUX_LIBJPEG) {
  309. }
  310. }
  311. class jpeg_compress_struct : jpeg_compress_decompress_base {
  312. const int GNU_JPEG_DLL_WINDOWS = 0;
  313. const int LINUX_LIBJPEG = 1;
  314. const int KNOWN_JPEG_LINRARIES = 2;
  315. static bool offsets_initialized;
  316. static jpeg_compress_decompress_base.structure_fields[] known_jpeg_libraries;
  317. static int current_library_index = LINUX_LIBJPEG;
  318. static void initialize_jpeg_compress_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 = 360;
  323. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IMAGE_WIDTH = 28;
  324. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IMAGE_HEIGHT = 32;
  325. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].INPUT_COMPONENTS = 36;
  326. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].IN_COLOR_SPACE = 40;
  327. known_jpeg_libraries[GNU_JPEG_DLL_WINDOWS].NEXT_SCAN_LINE = 208;
  328. // libjpeg Linux version
  329. known_jpeg_libraries[LINUX_LIBJPEG].structure_size = 372;
  330. known_jpeg_libraries[LINUX_LIBJPEG].IMAGE_WIDTH = 28;
  331. known_jpeg_libraries[LINUX_LIBJPEG].IMAGE_HEIGHT = 32;
  332. known_jpeg_libraries[LINUX_LIBJPEG].INPUT_COMPONENTS = 36;
  333. known_jpeg_libraries[LINUX_LIBJPEG].IN_COLOR_SPACE = 40;
  334. known_jpeg_libraries[LINUX_LIBJPEG].NEXT_SCAN_LINE = 220;
  335. offsets_initialized = true;
  336. }
  337. }
  338. static jpeg_compress_struct() {
  339. initialize_jpeg_compress_structs();
  340. }
  341. public jpeg_compress_struct() : base(known_jpeg_libraries, LINUX_LIBJPEG) {
  342. }
  343. }
  344. [StructLayout(LayoutKind.Sequential)]
  345. internal struct JSAMPARRAY {
  346. // FIXME: This code is not working on Mono(** ERROR **: Invalid IL code at...). Report a bug and change it later.
  347. //const int MAX_SCAN_LINES = 10;
  348. //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=MAX_SCAN_LINES)]
  349. //internal IntPtr[] JSAMPLES;
  350. internal IntPtr JSAMPLE0;
  351. internal IntPtr JSAMPLE1;
  352. internal JSAMPARRAY(int len) {
  353. /*
  354. JSAMPLES = new IntPtr[MAX_SCAN_LINES];
  355. for (int i = 0; i < MAX_SCAN_LINES; i++) {
  356. JSAMPLES[i] = Marshal.AllocHGlobal(len);
  357. }
  358. */
  359. JSAMPLE0 = Marshal.AllocHGlobal(len);
  360. JSAMPLE1 = Marshal.AllocHGlobal(len);
  361. }
  362. internal void Dispose() {
  363. /*
  364. for (int i = 0; i < MAX_SCAN_LINES; i++) {
  365. Marshal.FreeHGlobal(JSAMPLES[i]);
  366. }
  367. */
  368. Marshal.FreeHGlobal(JSAMPLE0);
  369. Marshal.FreeHGlobal(JSAMPLE1);
  370. }
  371. }
  372. const string JPEGLibrary = "jpeg";
  373. [DllImport(JPEGLibrary, EntryPoint="jpeg_CreateCompress", CallingConvention=CallingConvention.Cdecl)]
  374. internal static extern void jpeg_create_compress(byte[] info, int version, int structure_size);
  375. [DllImport(JPEGLibrary, EntryPoint="jpeg_CreateDecompress", CallingConvention=CallingConvention.Cdecl)]
  376. internal static extern void jpeg_create_decompress(byte[] info, int version, int structure_size);
  377. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  378. internal static extern void jpeg_std_error(ref jpeg_error_mgr_get err_mgr);
  379. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  380. internal static extern void jpeg_set_defaults(byte[] cinfo);
  381. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  382. internal static extern void jpeg_set_quality(byte[] cinfo, int quality, int force_baseline);
  383. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  384. internal static extern int jpeg_read_header(byte[] cinfo, int condition);
  385. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  386. internal static extern void jpeg_calc_output_dimensions(byte[] cinfo);
  387. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  388. internal static extern int jpeg_start_compress(byte[] cinfo, int write_all_tables);
  389. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  390. internal static extern int jpeg_start_decompress(byte[] cinfo);
  391. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  392. internal static extern int jpeg_read_scanlines(byte[] cinfo, ref JSAMPARRAY buffer, int num);
  393. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  394. internal static extern int jpeg_write_scanlines(byte[] cinfo, ref JSAMPARRAY scanlines, int num_lines);
  395. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  396. internal static extern int jpeg_finish_compress(byte[] cinfo);
  397. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  398. internal static extern int jpeg_finish_decompress(byte[] cinfo);
  399. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  400. internal static extern void jpeg_destroy_compress(byte[] cinfo);
  401. [DllImport(JPEGLibrary, CallingConvention=CallingConvention.Cdecl)]
  402. internal static extern void jpeg_destroy_decompress(byte[] cinfo);
  403. Stream fs;
  404. IntPtr buffer;
  405. int readwriteSize = 4096;
  406. // Source manager callbacks
  407. void init_source( IntPtr cinfo) {
  408. buffer = Marshal.AllocHGlobal(readwriteSize);
  409. }
  410. int fill_input_buffer( IntPtr cinfo) {
  411. byte[] result = new byte[readwriteSize];
  412. int readed = fs.Read(result, 0, readwriteSize);
  413. Marshal.Copy(result, 0, buffer, readed);
  414. IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
  415. Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
  416. Marshal.WriteInt32(srcAddr, 4, readed);
  417. return 1;
  418. }
  419. void skip_input_data( IntPtr cinfo, int num_bytes) {
  420. //byte[] result = new byte[num_bytes];
  421. //fs.Read(result, 0, num_bytes);
  422. fs.Seek(num_bytes, SeekOrigin.Current);
  423. }
  424. int resync_to_restart( IntPtr cinfo, int desired){
  425. return 0;
  426. }
  427. void term_source( IntPtr cinfo) {
  428. Marshal.FreeHGlobal(buffer);
  429. }
  430. // Destination manager callbacks
  431. void init_destination( IntPtr cinfo) {
  432. buffer = Marshal.AllocHGlobal(readwriteSize);
  433. IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
  434. Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
  435. Marshal.WriteInt32(srcAddr, 4, readwriteSize);
  436. }
  437. int empty_output_buffer( IntPtr cinfo) {
  438. IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
  439. IntPtr bufferPtr = (IntPtr)Marshal.ReadInt32(srcAddr, 0);
  440. int bytes = readwriteSize - Marshal.ReadInt32(srcAddr, 4);
  441. byte[] result = new byte[readwriteSize];
  442. Marshal.Copy(buffer, result, 0, readwriteSize);
  443. fs.Write(result, 0, readwriteSize);
  444. Marshal.WriteInt32(srcAddr, 0, buffer.ToInt32());
  445. Marshal.WriteInt32(srcAddr, 4, readwriteSize);
  446. return 1;
  447. }
  448. void term_destination( IntPtr cinfo) {
  449. IntPtr srcAddr = (IntPtr)Marshal.ReadInt32(cinfo, 24);
  450. IntPtr bufferPtr = (IntPtr)Marshal.ReadInt32(srcAddr, 0);
  451. int bytes = readwriteSize - Marshal.ReadInt32(srcAddr, 4);
  452. byte[] result = new byte[bytes];
  453. Marshal.Copy(buffer, result, 0, bytes);
  454. fs.Write(result, 0, bytes);
  455. Marshal.FreeHGlobal(buffer);
  456. }
  457. class RetryInitializationException : Exception {
  458. int libraryStructureSize;
  459. public RetryInitializationException(int structureSize) {
  460. this.libraryStructureSize = structureSize;
  461. }
  462. public int LibraryStructureSize {
  463. get {
  464. return libraryStructureSize;
  465. }
  466. }
  467. }
  468. enum JPEGErrorCodes : int {
  469. JERR_BAD_STRUCT_SIZE = 21
  470. }
  471. void error_exit( IntPtr cinfo) {
  472. jpeg_error_mgr mgr = new jpeg_error_mgr();
  473. IntPtr err_raw = (IntPtr)Marshal.ReadInt32(cinfo, 0);
  474. mgr = (jpeg_error_mgr)Marshal.PtrToStructure(err_raw, mgr.GetType());
  475. if ( mgr.msg_code == (int)JPEGErrorCodes.JERR_BAD_STRUCT_SIZE) {
  476. throw new RetryInitializationException(mgr.param_array[0]);
  477. }
  478. throw new Exception();
  479. }
  480. internal JPEGCodec() {
  481. }
  482. internal static ImageCodecInfo CodecInfo {
  483. get {
  484. ImageCodecInfo info = new ImageCodecInfo();
  485. info.Flags = ImageCodecFlags.Encoder | ImageCodecFlags.Decoder | ImageCodecFlags.Builtin | ImageCodecFlags.SupportBitmap;
  486. info.FormatDescription = "JPEG file format";
  487. info.FormatID = System.Drawing.Imaging.ImageFormat.Jpeg.Guid;
  488. info.MimeType = "image/jpeg";
  489. info.Version = 1;
  490. byte[][] signaturePatterns = new byte[1][];
  491. signaturePatterns[0] = new byte[]{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00};
  492. info.SignaturePatterns = signaturePatterns;
  493. byte[][] signatureMasks = new byte[1][];
  494. signatureMasks[0] = new byte[]{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
  495. info.SignatureMasks = signatureMasks;
  496. info.decode += new ImageCodecInfo.DecodeFromStream(JPEGCodec.DecodeDelegate);
  497. info.encode += new ImageCodecInfo.EncodeToStream(JPEGCodec.EncodeDelegate);
  498. return info;
  499. }
  500. }
  501. internal static void DecodeDelegate (Stream stream, InternalImageInfo info) {
  502. JPEGCodec jpeg = new JPEGCodec();
  503. jpeg.Decode (stream, info);
  504. }
  505. internal static void EncodeDelegate (Stream stream, InternalImageInfo info) {
  506. JPEGCodec jpeg = new JPEGCodec();
  507. jpeg.Encode (stream, info);
  508. }
  509. internal unsafe void switch_color_bytes( byte[] image) {
  510. fixed(byte* start = image) {
  511. byte *pb = start;
  512. byte t1;
  513. for( int ic = 0; ic < image.Length; ic +=3) {
  514. t1 = *pb;
  515. *(pb) = *(pb+2);
  516. *(pb+2) = t1;
  517. pb += 3;
  518. }
  519. }
  520. }
  521. internal bool Decode( Stream stream, InternalImageInfo info) {
  522. fs = stream;
  523. jpeg_error_mgr_get mgr = new jpeg_error_mgr_get();
  524. mgr.param_array = new int[20];
  525. jpeg_std_error( ref mgr);
  526. jpeg_error_mgr mgr_real = new jpeg_error_mgr();
  527. mgr_real.param_array = new int[20];
  528. mgr_real.error_exit = new cdeclCallback.cdeclRedirector.MethodVoidIntPtr(this.error_exit);
  529. mgr_real.msg_code = mgr.msg_code;
  530. mgr_real.a2 = mgr.a2;
  531. mgr_real.a3 = mgr.a3;
  532. mgr_real.a4 = mgr.a4;
  533. mgr_real.a5 = mgr.a5;
  534. mgr_real.trace_level = mgr.trace_level;
  535. mgr_real.num_warnings = mgr.num_warnings;
  536. mgr_real.last_jpeg_message = mgr.last_jpeg_message;
  537. mgr_real.first_addon_message = mgr.first_addon_message;
  538. mgr_real.last_addon_message = mgr.last_addon_message;
  539. mgr_real.jpeg_message_table = mgr.jpeg_message_table;
  540. jpeg_decompress_struct cinfo = new jpeg_decompress_struct();
  541. cinfo.jpeg_error_mgr = mgr_real;
  542. bool initializedOk = false;
  543. do {
  544. try {
  545. jpeg_create_decompress(cinfo.raw_struct, 62, cinfo.raw_struct.Length);
  546. initializedOk = true;
  547. }
  548. catch( RetryInitializationException ex) {
  549. initializedOk = false;
  550. cinfo.switch_to_struct_size(ex.LibraryStructureSize);
  551. cinfo.jpeg_error_mgr = mgr_real;
  552. }
  553. }while( !initializedOk);
  554. jpeg_source_mgr smgr = new jpeg_source_mgr();
  555. smgr.next_input_byte = IntPtr.Zero;
  556. smgr.bytes_in_buffer = 0;
  557. smgr.init_source = new cdeclRedirector.MethodVoidIntPtr(this.init_source);
  558. smgr.fill_input_buffer = new cdeclRedirector.MethodIntIntPtr(this.fill_input_buffer);
  559. smgr.skip_input_data = new cdeclRedirector.MethodVoidIntPtrInt(this.skip_input_data);
  560. smgr.resync_to_restart = new cdeclRedirector.MethodIntIntPtrInt(this.resync_to_restart);
  561. smgr.term_source = new cdeclRedirector.MethodVoidIntPtr(this.term_source);
  562. cinfo.jpeg_source_mgr = smgr;
  563. jpeg_read_header( cinfo.raw_struct, 1);
  564. jpeg_calc_output_dimensions(cinfo.raw_struct);
  565. jpeg_start_decompress(cinfo.raw_struct);
  566. int row_width = cinfo.Stride;
  567. while ((row_width & 3) != 0) row_width++;
  568. int pad_bytes = (row_width - cinfo.Stride);
  569. if (cinfo.OutColorSpace == J_COLOR_SPACE.JCS_RGB) {
  570. if (cinfo.QuantizeColors) {
  571. info.Format = PixelFormat.Format8bppIndexed;
  572. }
  573. else {
  574. info.Format = PixelFormat.Format24bppRgb;
  575. }
  576. }
  577. else {
  578. info.Format = PixelFormat.Format8bppIndexed;
  579. }
  580. info.Size = new Size(cinfo.OutputWidth,cinfo.OutputHeight);
  581. info.Stride = row_width;
  582. info.Palette = new ColorPalette(1, cinfo.ColorMap);
  583. info.Format = PixelFormat.Format24bppRgb;
  584. info.RawImageBytes = new byte[(cinfo.OutputHeight) * row_width];
  585. JSAMPARRAY outbuf = new JSAMPARRAY(cinfo.Stride);
  586. int outputIndex = info.RawImageBytes.Length - row_width;
  587. while (cinfo.OutputScanLine < cinfo.OutputHeight) {
  588. // FIXME: switch to the Length after fixing a run-time error
  589. int readed = jpeg_read_scanlines(cinfo.raw_struct, ref outbuf, 1 /*outbuf.JSAMPLES.Length*/);
  590. for (int i = 0; i < readed; i++) {
  591. // FIXME: switch to .JSAMPLES[i] after fix of run-time error
  592. //Marshal.Copy(outbuf.JSAMPLES[i], info.RawImageBytes, outputIndex, cinfo.Stride);
  593. Marshal.Copy(outbuf.JSAMPLE0, info.RawImageBytes, outputIndex, cinfo.Stride);
  594. outputIndex -= row_width;
  595. }
  596. }
  597. // FIXME: not sure if this always works
  598. switch_color_bytes(info.RawImageBytes);
  599. jpeg_finish_decompress(cinfo.raw_struct);
  600. jpeg_destroy_decompress(cinfo.raw_struct);
  601. return true;
  602. }
  603. internal unsafe bool Encode( Stream stream, InternalImageInfo info) {
  604. int bpp = Image.GetPixelFormatSize(info.Format) / 8;
  605. if( bpp != 3 && bpp != 4) {
  606. throw new ArgumentException(String.Format("Supplied pixel format is not yet supported: {0}, {1} bpp", info.Format, Image.GetPixelFormatSize(info.Format)));
  607. }
  608. fs = stream;
  609. jpeg_error_mgr_get mgr = new jpeg_error_mgr_get();
  610. mgr.param_array = new int[20];
  611. jpeg_std_error( ref mgr);
  612. jpeg_error_mgr mgr_real = new jpeg_error_mgr();
  613. mgr_real.param_array = new int[20];
  614. mgr_real.error_exit = new cdeclCallback.cdeclRedirector.MethodVoidIntPtr(this.error_exit);
  615. mgr_real.msg_code = mgr.msg_code;
  616. mgr_real.a2 = mgr.a2;
  617. mgr_real.a3 = mgr.a3;
  618. mgr_real.a4 = mgr.a4;
  619. mgr_real.a5 = mgr.a5;
  620. mgr_real.trace_level = mgr.trace_level;
  621. mgr_real.num_warnings = mgr.num_warnings;
  622. mgr_real.last_jpeg_message = mgr.last_jpeg_message;
  623. mgr_real.first_addon_message = mgr.first_addon_message;
  624. mgr_real.last_addon_message = mgr.last_addon_message;
  625. mgr_real.jpeg_message_table = mgr.jpeg_message_table;
  626. jpeg_compress_struct cinfo = new jpeg_compress_struct();
  627. cinfo.jpeg_error_mgr = mgr_real;
  628. bool initializedOk = false;
  629. do {
  630. try {
  631. jpeg_create_compress(cinfo.raw_struct, 62, cinfo.raw_struct.Length);
  632. initializedOk = true;
  633. }
  634. catch( RetryInitializationException ex) {
  635. initializedOk = false;
  636. cinfo.switch_to_struct_size(ex.LibraryStructureSize);
  637. cinfo.jpeg_error_mgr = mgr_real;
  638. }
  639. }while( !initializedOk);
  640. jpeg_destination_mgr dmgr = new jpeg_destination_mgr();
  641. dmgr.next_output_byte = IntPtr.Zero;
  642. dmgr.free_in_buffer = 0;
  643. dmgr.init_destination = new cdeclRedirector.MethodVoidIntPtr(this.init_destination);
  644. dmgr.empty_output_buffer = new cdeclRedirector.MethodIntIntPtr(this.empty_output_buffer);
  645. dmgr.term_destination = new cdeclRedirector.MethodVoidIntPtr(this.term_destination);
  646. cinfo.jpeg_destination_mgr = dmgr;
  647. int row_width = info.Size.Width;
  648. while ((row_width & 3) != 0) row_width++;
  649. cinfo.ImageWidth = info.Size.Width;
  650. cinfo.ImageHeight = info.Size.Height;
  651. cinfo.InputComponents = 3;
  652. cinfo.InColorSpace = J_COLOR_SPACE.JCS_RGB;
  653. jpeg_set_defaults( cinfo.raw_struct);
  654. jpeg_start_compress( cinfo.raw_struct, 1);
  655. int row_bytes_width = row_width * 3;
  656. int src_row_bytes_width = row_width * bpp;
  657. JSAMPARRAY inbuf = new JSAMPARRAY(row_bytes_width);
  658. int inputIndex = info.RawImageBytes.Length - src_row_bytes_width;
  659. byte[] buffer = new byte[row_bytes_width];
  660. fixed( byte *psrc = info.RawImageBytes, pbuf = buffer) {
  661. byte* curSrc = null;
  662. byte* curDst = null;
  663. while (cinfo.NextScanLine < cinfo.ImageHeight) {
  664. curSrc = psrc + inputIndex;
  665. curDst = pbuf;
  666. for( int i = 0; i < row_width; i++) {
  667. *curDst++ = *(curSrc+2);
  668. *curDst++ = *(curSrc+1);
  669. *curDst++ = *curSrc;
  670. curSrc += bpp;
  671. }
  672. Marshal.Copy( buffer, 0, inbuf.JSAMPLE0, row_bytes_width);
  673. inputIndex -= src_row_bytes_width;
  674. jpeg_write_scanlines(cinfo.raw_struct, ref inbuf, 1 /*inbuf.JSAMPLES.Length*/);
  675. }
  676. }
  677. jpeg_finish_compress(cinfo.raw_struct);
  678. jpeg_destroy_compress(cinfo.raw_struct);
  679. return true;
  680. }
  681. }
  682. }