/src/FreeImage/Source/FreeImage/PluginRAS.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 512 lines · 326 code · 115 blank · 71 comment · 46 complexity · adbe794f1c7fc3d69d6667dd89bc6509 MD5 · raw file

  1. // ==========================================================
  2. // Sun rasterfile Loader
  3. //
  4. // Design and implementation by
  5. // - Hervé Drolon (drolon@infonie.fr)
  6. //
  7. // This file is part of FreeImage 3
  8. //
  9. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  10. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  11. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  12. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  13. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  14. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  15. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  16. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  17. // THIS DISCLAIMER.
  18. //
  19. // Use at your own risk!
  20. // ==========================================================
  21. #include "FreeImage.h"
  22. #include "Utilities.h"
  23. // ----------------------------------------------------------
  24. // Constants + headers
  25. // ----------------------------------------------------------
  26. #ifdef _WIN32
  27. #pragma pack(push, 1)
  28. #else
  29. #pragma pack(1)
  30. #endif
  31. typedef struct tagSUNHEADER {
  32. DWORD magic; // Magic number
  33. DWORD width; // Image width in pixels
  34. DWORD height; // Image height in pixels
  35. DWORD depth; // Depth (1, 8, 24 or 32 bits) of each pixel
  36. DWORD length; // Image length (in bytes)
  37. DWORD type; // Format of file (see RT_* below)
  38. DWORD maptype; // Type of colormap (see RMT_* below)
  39. DWORD maplength; // Length of colormap (in bytes)
  40. } SUNHEADER;
  41. #ifdef _WIN32
  42. #pragma pack(pop)
  43. #else
  44. #pragma pack()
  45. #endif
  46. // ----------------------------------------------------------
  47. // Following the header is the colormap, for maplength bytes (unless maplength is zero),
  48. // then the image. Each row of the image is rounded to 2 bytes.
  49. #define RAS_MAGIC 0x59A66A95 // Magic number for Sun rasterfiles
  50. // Sun supported type's
  51. #define RT_OLD 0 // Old format (raw image in 68000 byte order)
  52. #define RT_STANDARD 1 // Raw image in 68000 byte order
  53. #define RT_BYTE_ENCODED 2 // Run-length encoding of bytes
  54. #define RT_FORMAT_RGB 3 // XRGB or RGB instead of XBGR or BGR
  55. #define RT_FORMAT_TIFF 4 // TIFF <-> standard rasterfile
  56. #define RT_FORMAT_IFF 5 // IFF (TAAC format) <-> standard rasterfile
  57. #define RT_EXPERIMENTAL 0xffff // Reserved for testing
  58. // These are the possible colormap types.
  59. // if it's in RGB format, the map is made up of three byte arrays
  60. // (red, green, then blue) that are each 1/3 of the colormap length.
  61. #define RMT_NONE 0 // maplength is expected to be 0
  62. #define RMT_EQUAL_RGB 1 // red[maplength/3], green[maplength/3], blue[maplength/3]
  63. #define RMT_RAW 2 // Raw colormap
  64. #define RESC 128 // Run-length encoding escape character
  65. // ----- NOTES -----
  66. // Each line of the image is rounded out to a multiple of 16 bits.
  67. // This corresponds to the rounding convention used by the memory pixrect
  68. // package (/usr/include/pixrect/memvar.h) of the SunWindows system.
  69. // The ras_encoding field (always set to 0 by Sun's supported software)
  70. // was renamed to ras_length in release 2.0. As a result, rasterfiles
  71. // of type 0 generated by the old software claim to have 0 length; for
  72. // compatibility, code reading rasterfiles must be prepared to compute the
  73. // TRUE length from the width, height, and depth fields.
  74. // ==========================================================
  75. // Internal functions
  76. // ==========================================================
  77. static void
  78. ReadData(FreeImageIO *io, fi_handle handle, BYTE *buf, DWORD length, BOOL rle) {
  79. // Read either Run-Length Encoded or normal image data
  80. static BYTE repchar, remaining= 0;
  81. if (rle) {
  82. // Run-length encoded read
  83. while(length--) {
  84. if (remaining) {
  85. remaining--;
  86. *(buf++)= repchar;
  87. } else {
  88. io->read_proc(&repchar, 1, 1, handle);
  89. if (repchar == RESC) {
  90. io->read_proc(&remaining, 1, 1, handle);
  91. if (remaining == 0) {
  92. *(buf++)= RESC;
  93. } else {
  94. io->read_proc(&repchar, 1, 1, handle);
  95. *(buf++)= repchar;
  96. }
  97. } else {
  98. *(buf++)= repchar;
  99. }
  100. }
  101. }
  102. } else {
  103. // Normal read
  104. io->read_proc(buf, length, 1, handle);
  105. }
  106. }
  107. // ==========================================================
  108. // Plugin Interface
  109. // ==========================================================
  110. static int s_format_id;
  111. // ==========================================================
  112. // Plugin Implementation
  113. // ==========================================================
  114. static const char * DLL_CALLCONV
  115. Format() {
  116. return "RAS";
  117. }
  118. static const char * DLL_CALLCONV
  119. Description() {
  120. return "Sun Raster Image";
  121. }
  122. static const char * DLL_CALLCONV
  123. Extension() {
  124. return "ras";
  125. }
  126. static const char * DLL_CALLCONV
  127. RegExpr() {
  128. return NULL;
  129. }
  130. static const char * DLL_CALLCONV
  131. MimeType() {
  132. return "image/x-cmu-raster";
  133. }
  134. static BOOL DLL_CALLCONV
  135. Validate(FreeImageIO *io, fi_handle handle) {
  136. BYTE ras_signature[] = { 0x59, 0xA6, 0x6A, 0x95 };
  137. BYTE signature[4] = { 0, 0, 0, 0 };
  138. io->read_proc(signature, 1, sizeof(ras_signature), handle);
  139. return (memcmp(ras_signature, signature, sizeof(ras_signature)) == 0);
  140. }
  141. static BOOL DLL_CALLCONV
  142. SupportsExportDepth(int depth) {
  143. return FALSE;
  144. }
  145. static BOOL DLL_CALLCONV
  146. SupportsExportType(FREE_IMAGE_TYPE type) {
  147. return FALSE;
  148. }
  149. static BOOL DLL_CALLCONV
  150. SupportsNoPixels() {
  151. return TRUE;
  152. }
  153. // ----------------------------------------------------------
  154. static FIBITMAP * DLL_CALLCONV
  155. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  156. SUNHEADER header; // Sun file header
  157. WORD linelength; // Length of raster line in bytes
  158. WORD fill; // Number of fill bytes per raster line
  159. BOOL rle; // TRUE if RLE file
  160. BOOL isRGB; // TRUE if file type is RT_FORMAT_RGB
  161. BYTE fillchar;
  162. FIBITMAP *dib = NULL;
  163. BYTE *bits; // Pointer to dib data
  164. WORD x, y;
  165. if(!handle) {
  166. return NULL;
  167. }
  168. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  169. try {
  170. // Read SUN raster header
  171. io->read_proc(&header, sizeof(SUNHEADER), 1, handle);
  172. #ifndef FREEIMAGE_BIGENDIAN
  173. // SUN rasterfiles are big endian only
  174. SwapLong(&header.magic);
  175. SwapLong(&header.width);
  176. SwapLong(&header.height);
  177. SwapLong(&header.depth);
  178. SwapLong(&header.length);
  179. SwapLong(&header.type);
  180. SwapLong(&header.maptype);
  181. SwapLong(&header.maplength);
  182. #endif
  183. // Verify SUN identifier
  184. if (header.magic != RAS_MAGIC) {
  185. throw FI_MSG_ERROR_MAGIC_NUMBER;
  186. }
  187. // Allocate a new DIB
  188. switch(header.depth) {
  189. case 1:
  190. case 8:
  191. dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth);
  192. break;
  193. case 24:
  194. dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  195. break;
  196. case 32:
  197. dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  198. break;
  199. }
  200. if (dib == NULL) {
  201. throw FI_MSG_ERROR_DIB_MEMORY;
  202. }
  203. // Check the file format
  204. rle = FALSE;
  205. isRGB = FALSE;
  206. switch(header.type) {
  207. case RT_OLD:
  208. case RT_STANDARD:
  209. case RT_FORMAT_TIFF: // I don't even know what these format are...
  210. case RT_FORMAT_IFF: //The TIFF and IFF format types indicate that the raster
  211. //file was originally converted from either of these file formats.
  212. //so lets at least try to process them as RT_STANDARD
  213. break;
  214. case RT_BYTE_ENCODED:
  215. rle = TRUE;
  216. break;
  217. case RT_FORMAT_RGB:
  218. isRGB = TRUE;
  219. break;
  220. default:
  221. throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
  222. }
  223. // set up the colormap if needed
  224. switch(header.maptype) {
  225. case RMT_NONE :
  226. {
  227. if (header.depth < 24) {
  228. // Create linear color ramp
  229. RGBQUAD *pal = FreeImage_GetPalette(dib);
  230. int numcolors = 1 << header.depth;
  231. for (int i = 0; i < numcolors; i++) {
  232. pal[i].rgbRed = (BYTE)((255 * i) / (numcolors - 1));
  233. pal[i].rgbGreen = (BYTE)((255 * i) / (numcolors - 1));
  234. pal[i].rgbBlue = (BYTE)((255 * i) / (numcolors - 1));
  235. }
  236. }
  237. break;
  238. }
  239. case RMT_EQUAL_RGB:
  240. {
  241. BYTE *r, *g, *b;
  242. // Read SUN raster colormap
  243. int numcolors = 1 << header.depth;
  244. if((DWORD)(3 * numcolors) > header.maplength) {
  245. // some RAS may have less colors than the full palette
  246. numcolors = header.maplength / 3;
  247. } else {
  248. throw "Invalid palette";
  249. }
  250. r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE));
  251. g = r + numcolors;
  252. b = g + numcolors;
  253. RGBQUAD *pal = FreeImage_GetPalette(dib);
  254. io->read_proc(r, 3 * numcolors, 1, handle);
  255. for (int i = 0; i < numcolors; i++) {
  256. pal[i].rgbRed = r[i];
  257. pal[i].rgbGreen = g[i];
  258. pal[i].rgbBlue = b[i];
  259. }
  260. free(r);
  261. break;
  262. }
  263. case RMT_RAW:
  264. {
  265. BYTE *colormap;
  266. // Read (skip) SUN raster colormap.
  267. colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE));
  268. io->read_proc(colormap, header.maplength, 1, handle);
  269. free(colormap);
  270. break;
  271. }
  272. }
  273. if(header_only) {
  274. // header only mode
  275. return dib;
  276. }
  277. // Calculate the line + pitch
  278. // Each row is multiple of 16 bits (2 bytes).
  279. if (header.depth == 1) {
  280. linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0));
  281. } else {
  282. linelength = (WORD)header.width;
  283. }
  284. fill = (linelength % 2) ? 1 : 0;
  285. unsigned pitch = FreeImage_GetPitch(dib);
  286. // Read the image data
  287. switch(header.depth) {
  288. case 1:
  289. case 8:
  290. {
  291. bits = FreeImage_GetBits(dib) + (header.height - 1) * pitch;
  292. for (y = 0; y < header.height; y++) {
  293. ReadData(io, handle, bits, linelength, rle);
  294. bits -= pitch;
  295. if (fill) {
  296. ReadData(io, handle, &fillchar, fill, rle);
  297. }
  298. }
  299. break;
  300. }
  301. case 24:
  302. {
  303. BYTE *buf, *bp;
  304. buf = (BYTE*)malloc(header.width * 3);
  305. for (y = 0; y < header.height; y++) {
  306. bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
  307. ReadData(io, handle, buf, header.width * 3, rle);
  308. bp = buf;
  309. if (isRGB) {
  310. for (x = 0; x < header.width; x++) {
  311. bits[FI_RGBA_RED] = *(bp++); // red
  312. bits[FI_RGBA_GREEN] = *(bp++); // green
  313. bits[FI_RGBA_BLUE] = *(bp++); // blue
  314. bits += 3;
  315. }
  316. } else {
  317. for (x = 0; x < header.width; x++) {
  318. bits[FI_RGBA_RED] = *(bp + 2); // red
  319. bits[FI_RGBA_GREEN] = *(bp + 1);// green
  320. bits[FI_RGBA_BLUE] = *bp; // blue
  321. bits += 3; bp += 3;
  322. }
  323. }
  324. if (fill) {
  325. ReadData(io, handle, &fillchar, fill, rle);
  326. }
  327. }
  328. free(buf);
  329. break;
  330. }
  331. case 32:
  332. {
  333. BYTE *buf, *bp;
  334. buf = (BYTE*)malloc(header.width * 4);
  335. for (y = 0; y < header.height; y++) {
  336. bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;
  337. ReadData(io, handle, buf, header.width * 4, rle);
  338. bp = buf;
  339. if (isRGB) {
  340. for (x = 0; x < header.width; x++) {
  341. bits[FI_RGBA_ALPHA] = *(bp++); // alpha
  342. bits[FI_RGBA_RED] = *(bp++); // red
  343. bits[FI_RGBA_GREEN] = *(bp++); // green
  344. bits[FI_RGBA_BLUE] = *(bp++); // blue
  345. bits += 4;
  346. }
  347. }
  348. else {
  349. for (x = 0; x < header.width; x++) {
  350. bits[FI_RGBA_RED] = *(bp + 3); // red
  351. bits[FI_RGBA_GREEN] = *(bp + 2); // green
  352. bits[FI_RGBA_BLUE] = *(bp + 1); // blue
  353. bits[FI_RGBA_ALPHA] = *bp; // alpha
  354. bits += 4;
  355. bp += 4;
  356. }
  357. }
  358. if (fill) {
  359. ReadData(io, handle, &fillchar, fill, rle);
  360. }
  361. }
  362. free(buf);
  363. break;
  364. }
  365. }
  366. return dib;
  367. } catch (const char *text) {
  368. if(dib) {
  369. FreeImage_Unload(dib);
  370. }
  371. FreeImage_OutputMessageProc(s_format_id, text);
  372. }
  373. return NULL;
  374. }
  375. // ==========================================================
  376. // Init
  377. // ==========================================================
  378. void DLL_CALLCONV
  379. InitRAS(Plugin *plugin, int format_id) {
  380. s_format_id = format_id;
  381. plugin->format_proc = Format;
  382. plugin->description_proc = Description;
  383. plugin->extension_proc = Extension;
  384. plugin->regexpr_proc = RegExpr;
  385. plugin->open_proc = NULL;
  386. plugin->close_proc = NULL;
  387. plugin->pagecount_proc = NULL;
  388. plugin->pagecapability_proc = NULL;
  389. plugin->load_proc = Load;
  390. plugin->save_proc = NULL;
  391. plugin->validate_proc = Validate;
  392. plugin->mime_proc = MimeType;
  393. plugin->supports_export_bpp_proc = SupportsExportDepth;
  394. plugin->supports_export_type_proc = SupportsExportType;
  395. plugin->supports_icc_profiles_proc = NULL;
  396. plugin->supports_no_pixels_proc = SupportsNoPixels;
  397. }