/src/FreeImage/Source/FreeImage/Conversion32.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 345 lines · 246 code · 52 blank · 47 comment · 64 complexity · e3d1c136c9f4b98fb66ad5e21a65081a MD5 · raw file

  1. // ==========================================================
  2. // Bitmap conversion routines
  3. //
  4. // Design and implementation by
  5. // - Floris van den Berg (flvdberg@wxs.nl)
  6. // - Hervé Drolon (drolon@infonie.fr)
  7. // - Jani Kajala (janik@remedy.fi)
  8. // - Detlev Vendt (detlev.vendt@brillit.de)
  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 conversions X to 32 bits
  28. // ----------------------------------------------------------
  29. void DLL_CALLCONV
  30. FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
  31. for (int cols = 0; cols < width_in_pixels; cols++) {
  32. int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
  33. target[FI_RGBA_BLUE] = palette[index].rgbBlue;
  34. target[FI_RGBA_GREEN] = palette[index].rgbGreen;
  35. target[FI_RGBA_RED] = palette[index].rgbRed;
  36. target[FI_RGBA_ALPHA] = 0xFF;
  37. target += 4;
  38. }
  39. }
  40. void DLL_CALLCONV
  41. FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
  42. BOOL low_nibble = FALSE;
  43. int x = 0;
  44. for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
  45. if (low_nibble) {
  46. target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
  47. target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
  48. target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
  49. x++;
  50. } else {
  51. target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
  52. target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
  53. target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
  54. }
  55. low_nibble = !low_nibble;
  56. target[FI_RGBA_ALPHA] = 0xFF;
  57. target += 4;
  58. }
  59. }
  60. void DLL_CALLCONV
  61. FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
  62. for (int cols = 0; cols < width_in_pixels; cols++) {
  63. target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
  64. target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
  65. target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
  66. target[FI_RGBA_ALPHA] = 0xFF;
  67. target += 4;
  68. }
  69. }
  70. void DLL_CALLCONV
  71. FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels) {
  72. WORD *bits = (WORD *)source;
  73. for (int cols = 0; cols < width_in_pixels; cols++) {
  74. target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
  75. target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
  76. target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
  77. target[FI_RGBA_ALPHA] = 0xFF;
  78. target += 4;
  79. }
  80. }
  81. void DLL_CALLCONV
  82. FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels) {
  83. WORD *bits = (WORD *)source;
  84. for (int cols = 0; cols < width_in_pixels; cols++) {
  85. target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
  86. target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
  87. target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
  88. target[FI_RGBA_ALPHA] = 0xFF;
  89. target += 4;
  90. }
  91. }
  92. /*
  93. void DLL_CALLCONV
  94. FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
  95. for (int cols = 0; cols < width_in_pixels; cols++) {
  96. *(DWORD *)target = (*(DWORD *) source & FI_RGBA_RGB_MASK) | FI_RGBA_ALPHA_MASK;
  97. target += 4;
  98. source += 3;
  99. }
  100. }
  101. */
  102. /**
  103. This unoptimized version of the conversion function avoid an undetermined bug with VC++ SP6.
  104. The bug occurs in release mode only, when the image height is equal to 537
  105. (try e.g. a size of 432x537 to reproduce the bug with the optimized function).
  106. */
  107. void DLL_CALLCONV
  108. FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
  109. for (int cols = 0; cols < width_in_pixels; cols++) {
  110. target[FI_RGBA_RED] = source[FI_RGBA_RED];
  111. target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
  112. target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
  113. target[FI_RGBA_ALPHA] = 0xFF;
  114. target += 4;
  115. source += 3;
  116. }
  117. }
  118. // ----------------------------------------------------------
  119. inline void
  120. FreeImage_ConvertLine1To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
  121. for (int cols = 0; cols < width_in_pixels; cols++) {
  122. int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
  123. target[FI_RGBA_BLUE] = palette[index].rgbBlue;
  124. target[FI_RGBA_GREEN] = palette[index].rgbGreen;
  125. target[FI_RGBA_RED] = palette[index].rgbRed;
  126. target[FI_RGBA_ALPHA] = (index < transparent_pixels) ? table[index] : 255;
  127. target += 4;
  128. }
  129. }
  130. inline void
  131. FreeImage_ConvertLine4To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
  132. BOOL low_nibble = FALSE;
  133. int x = 0;
  134. for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
  135. if (low_nibble) {
  136. target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
  137. target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
  138. target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
  139. target[FI_RGBA_ALPHA] = (LOWNIBBLE(source[x]) < transparent_pixels) ? table[LOWNIBBLE(source[x])] : 255;
  140. x++;
  141. } else {
  142. target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
  143. target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
  144. target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
  145. target[FI_RGBA_ALPHA] = (HINIBBLE(source[x] >> 4) < transparent_pixels) ? table[HINIBBLE(source[x]) >> 4] : 255;
  146. }
  147. low_nibble = !low_nibble;
  148. target += 4;
  149. }
  150. }
  151. inline void
  152. FreeImage_ConvertLine8To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
  153. for (int cols = 0; cols < width_in_pixels; cols++) {
  154. target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
  155. target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
  156. target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
  157. target[FI_RGBA_ALPHA] = (source[cols] < transparent_pixels) ? table[source[cols]] : 255;
  158. target += 4;
  159. }
  160. }
  161. // ----------------------------------------------------------
  162. FIBITMAP * DLL_CALLCONV
  163. FreeImage_ConvertTo32Bits(FIBITMAP *dib) {
  164. if(!FreeImage_HasPixels(dib)) return NULL;
  165. const int bpp = FreeImage_GetBPP(dib);
  166. const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
  167. if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
  168. return NULL;
  169. }
  170. const int width = FreeImage_GetWidth(dib);
  171. const int height = FreeImage_GetHeight(dib);
  172. if(image_type == FIT_BITMAP) {
  173. if(bpp == 32) {
  174. return FreeImage_Clone(dib);
  175. }
  176. FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  177. if(new_dib == NULL) {
  178. return NULL;
  179. }
  180. // copy metadata from src to dst
  181. FreeImage_CloneMetadata(new_dib, dib);
  182. BOOL bIsTransparent = FreeImage_IsTransparent(dib);
  183. switch(bpp) {
  184. case 1:
  185. {
  186. if(bIsTransparent) {
  187. for (int rows = 0; rows < height; rows++) {
  188. FreeImage_ConvertLine1To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
  189. }
  190. } else {
  191. for (int rows = 0; rows < height; rows++) {
  192. FreeImage_ConvertLine1To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
  193. }
  194. }
  195. return new_dib;
  196. }
  197. case 4:
  198. {
  199. if(bIsTransparent) {
  200. for (int rows = 0; rows < height; rows++) {
  201. FreeImage_ConvertLine4To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
  202. }
  203. } else {
  204. for (int rows = 0; rows < height; rows++) {
  205. FreeImage_ConvertLine4To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
  206. }
  207. }
  208. return new_dib;
  209. }
  210. case 8:
  211. {
  212. if(bIsTransparent) {
  213. for (int rows = 0; rows < height; rows++) {
  214. FreeImage_ConvertLine8To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
  215. }
  216. } else {
  217. for (int rows = 0; rows < height; rows++) {
  218. FreeImage_ConvertLine8To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
  219. }
  220. }
  221. return new_dib;
  222. }
  223. case 16:
  224. {
  225. for (int rows = 0; rows < height; rows++) {
  226. if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
  227. FreeImage_ConvertLine16To32_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
  228. } else {
  229. // includes case where all the masks are 0
  230. FreeImage_ConvertLine16To32_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
  231. }
  232. }
  233. return new_dib;
  234. }
  235. case 24:
  236. {
  237. for (int rows = 0; rows < height; rows++) {
  238. FreeImage_ConvertLine24To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
  239. }
  240. return new_dib;
  241. }
  242. }
  243. } else if(image_type == FIT_RGB16) {
  244. FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  245. if(new_dib == NULL) {
  246. return NULL;
  247. }
  248. // copy metadata from src to dst
  249. FreeImage_CloneMetadata(new_dib, dib);
  250. const unsigned src_pitch = FreeImage_GetPitch(dib);
  251. const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
  252. const BYTE *src_bits = FreeImage_GetBits(dib);
  253. BYTE *dst_bits = FreeImage_GetBits(new_dib);
  254. for (int rows = 0; rows < height; rows++) {
  255. const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
  256. RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
  257. for(int cols = 0; cols < width; cols++) {
  258. dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
  259. dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
  260. dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
  261. dst_pixel[cols].rgbReserved = (BYTE)0xFF;
  262. }
  263. src_bits += src_pitch;
  264. dst_bits += dst_pitch;
  265. }
  266. return new_dib;
  267. } else if(image_type == FIT_RGBA16) {
  268. FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  269. if(new_dib == NULL) {
  270. return NULL;
  271. }
  272. // copy metadata from src to dst
  273. FreeImage_CloneMetadata(new_dib, dib);
  274. const unsigned src_pitch = FreeImage_GetPitch(dib);
  275. const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
  276. const BYTE *src_bits = FreeImage_GetBits(dib);
  277. BYTE *dst_bits = FreeImage_GetBits(new_dib);
  278. for (int rows = 0; rows < height; rows++) {
  279. const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
  280. RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
  281. for(int cols = 0; cols < width; cols++) {
  282. dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
  283. dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
  284. dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
  285. dst_pixel[cols].rgbReserved = (BYTE)(src_pixel[cols].alpha >> 8);
  286. }
  287. src_bits += src_pitch;
  288. dst_bits += dst_pitch;
  289. }
  290. return new_dib;
  291. }
  292. return NULL;
  293. }