/src/FreeImage/Source/FreeImage/PluginIFF.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 459 lines · 313 code · 86 blank · 60 comment · 68 complexity · f0d889cc10874e5739557471e6695c83 MD5 · raw file

  1. // ==========================================================
  2. // Deluxe Paint Loader
  3. //
  4. // Design and implementation by
  5. // - Floris van den Berg (flvdberg@wxs.nl)
  6. // - Mark Sibly (marksibly@blitzbasic.com)
  7. // - Aaron Shumate (trek@startreker.com)
  8. // - Hervé Drolon (drolon@infonie.fr)
  9. //
  10. // This file is part of FreeImage 3
  11. //
  12. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  13. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  14. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  15. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  16. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  17. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  18. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  19. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  20. // THIS DISCLAIMER.
  21. //
  22. // Use at your own risk!
  23. // ==========================================================
  24. #include "FreeImage.h"
  25. #include "Utilities.h"
  26. // ----------------------------------------------------------
  27. // Internal typedefs and structures
  28. // ----------------------------------------------------------
  29. #ifdef _WIN32
  30. #pragma pack(push, 1)
  31. #else
  32. #pragma pack(1)
  33. #endif
  34. typedef struct {
  35. WORD w, h; /* raster width & height in pixels */
  36. WORD x, y; /* position for this image */
  37. BYTE nPlanes; /* # source bitplanes */
  38. BYTE masking; /* masking technique */
  39. BYTE compression; /* compression algorithm */
  40. BYTE pad1; /* UNUSED. For consistency, put 0 here.*/
  41. WORD transparentColor; /* transparent "color number" */
  42. BYTE xAspect, yAspect; /* aspect ratio, a rational number x/y */
  43. WORD pageWidth, pageHeight; /* source "page" size in pixels */
  44. } BMHD;
  45. #ifdef _WIN32
  46. #pragma pack(pop)
  47. #else
  48. #pragma pack()
  49. #endif
  50. #ifndef FREEIMAGE_BIGENDIAN
  51. static void
  52. SwapHeader(BMHD *header) {
  53. SwapShort(&header->w);
  54. SwapShort(&header->h);
  55. SwapShort(&header->x);
  56. SwapShort(&header->y);
  57. SwapShort(&header->transparentColor);
  58. SwapShort(&header->pageWidth);
  59. SwapShort(&header->pageHeight);
  60. }
  61. #endif
  62. // ----------------------------------------------------------
  63. /* IFF chunk IDs */
  64. typedef DWORD IFF_ID;
  65. #define MAKE_ID(a, b, c, d) ((IFF_ID)(a)<<24 | (IFF_ID)(b)<<16 | (IFF_ID)(c)<<8 | (IFF_ID)(d))
  66. #define ID_FORM MAKE_ID('F', 'O', 'R', 'M') /* EA IFF 85 group identifier */
  67. #define ID_CAT MAKE_ID('C', 'A', 'T', ' ') /* EA IFF 85 group identifier */
  68. #define ID_LIST MAKE_ID('L', 'I', 'S', 'T') /* EA IFF 85 group identifier */
  69. #define ID_PROP MAKE_ID('P', 'R', 'O', 'P') /* EA IFF 85 group identifier */
  70. #define ID_END MAKE_ID('E', 'N', 'D', ' ') /* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3 page 376) */
  71. #define ID_ILBM MAKE_ID('I', 'L', 'B', 'M') /* EA IFF 85 raster bitmap form */
  72. #define ID_DEEP MAKE_ID('D', 'E', 'E', 'P') /* Chunky pixel image files (Used in TV Paint) */
  73. #define ID_RGB8 MAKE_ID('R', 'G', 'B', '8') /* RGB image forms, Turbo Silver (Impulse) */
  74. #define ID_RGBN MAKE_ID('R', 'G', 'B', 'N') /* RGB image forms, Turbo Silver (Impulse) */
  75. #define ID_PBM MAKE_ID('P', 'B', 'M', ' ') /* 256-color chunky format (DPaint 2 ?) */
  76. #define ID_ACBM MAKE_ID('A', 'C', 'B', 'M') /* Amiga Contiguous Bitmap (AmigaBasic) */
  77. /* generic */
  78. #define ID_FVER MAKE_ID('F', 'V', 'E', 'R') /* AmigaOS version string */
  79. #define ID_JUNK MAKE_ID('J', 'U', 'N', 'K') /* always ignore this chunk */
  80. #define ID_ANNO MAKE_ID('A', 'N', 'N', 'O') /* EA IFF 85 Generic Annotation chunk */
  81. #define ID_AUTH MAKE_ID('A', 'U', 'T', 'H') /* EA IFF 85 Generic Author chunk */
  82. #define ID_CHRS MAKE_ID('C', 'H', 'R', 'S') /* EA IFF 85 Generic character string chunk */
  83. #define ID_NAME MAKE_ID('N', 'A', 'M', 'E') /* EA IFF 85 Generic Name of art, music, etc. chunk */
  84. #define ID_TEXT MAKE_ID('T', 'E', 'X', 'T') /* EA IFF 85 Generic unformatted ASCII text chunk */
  85. #define ID_copy MAKE_ID('(', 'c', ')', ' ') /* EA IFF 85 Generic Copyright text chunk */
  86. /* ILBM chunks */
  87. #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* ILBM BitmapHeader */
  88. #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* ILBM 8bit RGB colormap */
  89. #define ID_GRAB MAKE_ID('G', 'R', 'A', 'B') /* ILBM "hotspot" coordiantes */
  90. #define ID_DEST MAKE_ID('D', 'E', 'S', 'T') /* ILBM destination image info */
  91. #define ID_SPRT MAKE_ID('S', 'P', 'R', 'T') /* ILBM sprite identifier */
  92. #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* Amiga viewportmodes */
  93. #define ID_BODY MAKE_ID('B', 'O', 'D', 'Y') /* ILBM image data */
  94. #define ID_CRNG MAKE_ID('C', 'R', 'N', 'G') /* color cycling */
  95. #define ID_CCRT MAKE_ID('C', 'C', 'R', 'T') /* color cycling */
  96. #define ID_CLUT MAKE_ID('C', 'L', 'U', 'T') /* Color Lookup Table chunk */
  97. #define ID_DPI MAKE_ID('D', 'P', 'I', ' ') /* Dots per inch chunk */
  98. #define ID_DPPV MAKE_ID('D', 'P', 'P', 'V') /* DPaint perspective chunk (EA) */
  99. #define ID_DRNG MAKE_ID('D', 'R', 'N', 'G') /* DPaint IV enhanced color cycle chunk (EA) */
  100. #define ID_EPSF MAKE_ID('E', 'P', 'S', 'F') /* Encapsulated Postscript chunk */
  101. #define ID_CMYK MAKE_ID('C', 'M', 'Y', 'K') /* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
  102. #define ID_CNAM MAKE_ID('C', 'N', 'A', 'M') /* Color naming chunk (Soft-Logik) */
  103. #define ID_PCHG MAKE_ID('P', 'C', 'H', 'G') /* Line by line palette control information (Sebastiano Vigna) */
  104. #define ID_PRVW MAKE_ID('P', 'R', 'V', 'W') /* A mini duplicate ILBM used for preview (Gary Bonham) */
  105. #define ID_XBMI MAKE_ID('X', 'B', 'M', 'I') /* eXtended BitMap Information (Soft-Logik) */
  106. #define ID_CTBL MAKE_ID('C', 'T', 'B', 'L') /* Newtek Dynamic Ham color chunk */
  107. #define ID_DYCP MAKE_ID('D', 'Y', 'C', 'P') /* Newtek Dynamic Ham chunk */
  108. #define ID_SHAM MAKE_ID('S', 'H', 'A', 'M') /* Sliced HAM color chunk */
  109. #define ID_ABIT MAKE_ID('A', 'B', 'I', 'T') /* ACBM body chunk */
  110. #define ID_DCOL MAKE_ID('D', 'C', 'O', 'L') /* unofficial direct color */
  111. // ==========================================================
  112. // Plugin Interface
  113. // ==========================================================
  114. static int s_format_id;
  115. // ==========================================================
  116. // Plugin Implementation
  117. // ==========================================================
  118. static const char * DLL_CALLCONV
  119. Format() {
  120. return "IFF";
  121. }
  122. static const char * DLL_CALLCONV
  123. Description() {
  124. return "IFF Interleaved Bitmap";
  125. }
  126. static const char * DLL_CALLCONV
  127. Extension() {
  128. return "iff,lbm";
  129. }
  130. static const char * DLL_CALLCONV
  131. RegExpr() {
  132. return NULL;
  133. }
  134. static const char * DLL_CALLCONV
  135. MimeType() {
  136. return "image/x-iff";
  137. }
  138. static BOOL DLL_CALLCONV
  139. Validate(FreeImageIO *io, fi_handle handle) {
  140. DWORD type = 0;
  141. // read chunk type
  142. io->read_proc(&type, 4, 1, handle);
  143. #ifndef FREEIMAGE_BIGENDIAN
  144. SwapLong(&type);
  145. #endif
  146. if(type != ID_FORM)
  147. return FALSE;
  148. // skip 4 bytes
  149. io->read_proc(&type, 4, 1, handle);
  150. // read chunk type
  151. io->read_proc(&type, 4, 1, handle);
  152. #ifndef FREEIMAGE_BIGENDIAN
  153. SwapLong(&type);
  154. #endif
  155. // File format : ID_PBM = Packed Bitmap, ID_ILBM = Interleaved Bitmap
  156. return (type == ID_ILBM) || (type == ID_PBM);
  157. }
  158. static BOOL DLL_CALLCONV
  159. SupportsExportDepth(int depth) {
  160. return FALSE;
  161. }
  162. static BOOL DLL_CALLCONV
  163. SupportsExportType(FREE_IMAGE_TYPE type) {
  164. return FALSE;
  165. }
  166. // ----------------------------------------------------------
  167. static FIBITMAP * DLL_CALLCONV
  168. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  169. if (handle != NULL) {
  170. FIBITMAP *dib = NULL;
  171. DWORD type, size;
  172. io->read_proc(&type, 4, 1, handle);
  173. #ifndef FREEIMAGE_BIGENDIAN
  174. SwapLong(&type);
  175. #endif
  176. if(type != ID_FORM)
  177. return NULL;
  178. io->read_proc(&size, 4, 1, handle);
  179. #ifndef FREEIMAGE_BIGENDIAN
  180. SwapLong(&size);
  181. #endif
  182. io->read_proc(&type, 4, 1, handle);
  183. #ifndef FREEIMAGE_BIGENDIAN
  184. SwapLong(&type);
  185. #endif
  186. if((type != ID_ILBM) && (type != ID_PBM))
  187. return NULL;
  188. size -= 4;
  189. unsigned width = 0, height = 0, planes = 0, depth = 0, comp = 0;
  190. while (size) {
  191. DWORD ch_type,ch_size;
  192. io->read_proc(&ch_type, 4, 1, handle);
  193. #ifndef FREEIMAGE_BIGENDIAN
  194. SwapLong(&ch_type);
  195. #endif
  196. io->read_proc(&ch_size,4,1,handle );
  197. #ifndef FREEIMAGE_BIGENDIAN
  198. SwapLong(&ch_size);
  199. #endif
  200. unsigned ch_end = io->tell_proc(handle) + ch_size;
  201. if (ch_type == ID_BMHD) { // Bitmap Header
  202. if (dib)
  203. FreeImage_Unload(dib);
  204. BMHD bmhd;
  205. io->read_proc(&bmhd, sizeof(bmhd), 1, handle);
  206. #ifndef FREEIMAGE_BIGENDIAN
  207. SwapHeader(&bmhd);
  208. #endif
  209. width = bmhd.w;
  210. height = bmhd.h;
  211. planes = bmhd.nPlanes;
  212. comp = bmhd.compression;
  213. if(bmhd.masking & 1)
  214. planes++; // there is a mask ( 'stencil' )
  215. if (planes > 8 && planes != 24)
  216. return NULL;
  217. depth = planes > 8 ? 24 : 8;
  218. if( depth == 24 ) {
  219. dib = FreeImage_Allocate(width, height, depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  220. } else {
  221. dib = FreeImage_Allocate(width, height, depth);
  222. }
  223. } else if (ch_type == ID_CMAP) { // Palette (Color Map)
  224. if (!dib)
  225. return NULL;
  226. RGBQUAD *pal = FreeImage_GetPalette(dib);
  227. if(pal != NULL) {
  228. unsigned palette_entries = MIN((unsigned)ch_size / 3, FreeImage_GetColorsUsed(dib));
  229. for (unsigned k = 0; k < palette_entries; k++) {
  230. io->read_proc(&pal[k].rgbRed, 1, 1, handle );
  231. io->read_proc(&pal[k].rgbGreen, 1, 1, handle );
  232. io->read_proc(&pal[k].rgbBlue, 1, 1, handle );
  233. }
  234. }
  235. } else if (ch_type == ID_BODY) {
  236. if (!dib)
  237. return NULL;
  238. if (type == ID_PBM) {
  239. // NON INTERLACED (LBM)
  240. unsigned line = FreeImage_GetLine(dib) + 1 & ~1;
  241. for (unsigned i = 0; i < FreeImage_GetHeight(dib); i++) {
  242. BYTE *bits = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1);
  243. if (comp == 1) {
  244. // use RLE compression
  245. DWORD number_of_bytes_written = 0;
  246. BYTE rle_count;
  247. BYTE byte;
  248. while (number_of_bytes_written < line) {
  249. io->read_proc(&rle_count, 1, 1, handle);
  250. if (rle_count < 128) {
  251. for (int k = 0; k < rle_count + 1; k++) {
  252. io->read_proc(&byte, 1, 1, handle);
  253. bits[number_of_bytes_written++] += byte;
  254. }
  255. } else if (rle_count > 128) {
  256. io->read_proc(&byte, 1, 1, handle);
  257. for (int k = 0; k < 257 - rle_count; k++) {
  258. bits[number_of_bytes_written++] += byte;
  259. }
  260. }
  261. }
  262. } else {
  263. // don't use compression
  264. io->read_proc(bits, line, 1, handle);
  265. }
  266. }
  267. return dib;
  268. } else {
  269. // INTERLACED (ILBM)
  270. unsigned pixel_size = depth/8;
  271. unsigned n_width=(width+15)&~15;
  272. unsigned plane_size = n_width/8;
  273. unsigned src_size = plane_size * planes;
  274. BYTE *src = (BYTE*)malloc(src_size);
  275. BYTE *dest = FreeImage_GetBits(dib);
  276. dest += FreeImage_GetPitch(dib) * height;
  277. for (unsigned y = 0; y < height; y++) {
  278. dest -= FreeImage_GetPitch(dib);
  279. // read all planes in one hit,
  280. // 'coz PSP compresses across planes...
  281. if (comp) {
  282. // unpacker algorithm
  283. for(unsigned x = 0; x < src_size;) {
  284. // read the next source byte into t
  285. signed char t = 0;
  286. io->read_proc(&t, 1, 1, handle);
  287. if (t >= 0) {
  288. // t = [0..127] => copy the next t+1 bytes literally
  289. unsigned size_to_read = t + 1;
  290. if((size_to_read + x) > src_size) {
  291. // sanity check for buffer overruns
  292. size_to_read = src_size - x;
  293. io->read_proc(src + x, size_to_read, 1, handle);
  294. x += (t + 1);
  295. } else {
  296. io->read_proc(src + x, size_to_read, 1, handle);
  297. x += size_to_read;
  298. }
  299. } else if (t != -128) {
  300. // t = [-1..-127] => replicate the next byte -t+1 times
  301. BYTE b = 0;
  302. io->read_proc(&b, 1, 1, handle);
  303. unsigned size_to_copy = (unsigned)(-(int)t + 1);
  304. if((size_to_copy + x) > src_size) {
  305. // sanity check for buffer overruns
  306. size_to_copy = src_size - x;
  307. memset(src + x, b, size_to_copy);
  308. x += (unsigned)(-(int)t + 1);
  309. } else {
  310. memset(src + x, b, size_to_copy);
  311. x += size_to_copy;
  312. }
  313. }
  314. // t = -128 => noop
  315. }
  316. } else {
  317. io->read_proc(src, src_size, 1, handle);
  318. }
  319. // lazy planar->chunky...
  320. for (unsigned x = 0; x < width; x++) {
  321. for (unsigned n = 0; n < planes; n++) {
  322. BYTE bit = (BYTE)( src[n * plane_size + (x / 8)] >> ((x^7) & 7) );
  323. dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7);
  324. }
  325. }
  326. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
  327. if (depth == 24) {
  328. for (unsigned x = 0; x < width; ++x){
  329. INPLACESWAP(dest[x * 3], dest[x * 3 + 2]);
  330. }
  331. }
  332. #endif
  333. }
  334. free(src);
  335. return dib;
  336. }
  337. }
  338. // Every odd-length chunk is followed by a 0 pad byte. This pad
  339. // byte is not counted in ch_size.
  340. if (ch_size & 1) {
  341. ch_size++;
  342. ch_end++;
  343. }
  344. io->seek_proc(handle, ch_end - io->tell_proc(handle), SEEK_CUR);
  345. size -= ch_size + 8;
  346. }
  347. if (dib)
  348. FreeImage_Unload(dib);
  349. }
  350. return 0;
  351. }
  352. // ==========================================================
  353. // Init
  354. // ==========================================================
  355. void DLL_CALLCONV
  356. InitIFF(Plugin *plugin, int format_id) {
  357. s_format_id = format_id;
  358. plugin->format_proc = Format;
  359. plugin->description_proc = Description;
  360. plugin->extension_proc = Extension;
  361. plugin->regexpr_proc = RegExpr;
  362. plugin->open_proc = NULL;
  363. plugin->close_proc = NULL;
  364. plugin->pagecount_proc = NULL;
  365. plugin->pagecapability_proc = NULL;
  366. plugin->load_proc = Load;
  367. plugin->save_proc = NULL;
  368. plugin->validate_proc = Validate;
  369. plugin->mime_proc = MimeType;
  370. plugin->supports_export_bpp_proc = SupportsExportDepth;
  371. plugin->supports_export_type_proc = SupportsExportType;
  372. plugin->supports_icc_profiles_proc = NULL;
  373. }