JPEGCodec.cs 27 KB

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