ImageGif.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "EditorDefs.h"
  9. #include "ImageGif.h"
  10. // Editor
  11. #include "Util/Image.h"
  12. //---------------------------------------------------------------------------
  13. #define NEXTBYTE (*ptr++)
  14. #define IMAGESEP 0x2c
  15. #define GRAPHIC_EXT 0xf9
  16. #define PLAINTEXT_EXT 0x01
  17. #define APPLICATION_EXT 0xff
  18. #define COMMENT_EXT 0xfe
  19. #define START_EXTENSION 0x21
  20. #define INTERLACEMASK 0x40
  21. #define COLORMAPMASK 0x80
  22. #define CHK(x) x
  23. #pragma pack(push,1)
  24. struct SGIFRGBcolor
  25. {
  26. uint8 red, green, blue;
  27. };
  28. struct SGIFRGBPixel
  29. {
  30. uint8 red, green, blue, alpha;
  31. };
  32. #pragma pack(pop)
  33. static int BitOffset = 0, /* Bit Offset of next code */
  34. XC = 0, YC = 0, /* Output X and Y coords of current pixel */
  35. Pass = 0, /* Used by output routine if interlaced pic */
  36. OutCount = 0, /* Decompressor output 'stack count' */
  37. RWidth, RHeight, /* screen dimensions */
  38. Width, Height, /* image dimensions */
  39. LeftOfs, TopOfs, /* image offset */
  40. BitsPerPixel, /* Bits per pixel, read from GIF header */
  41. BytesPerScanline, /* bytes per scanline in output raster */
  42. ColorMapSize, /* number of colors */
  43. Background, /* background color */
  44. CodeSize, /* Code size, read from GIF header */
  45. InitCodeSize, /* Starting code size, used during Clear */
  46. Code, /* Value returned by ReadCode */
  47. MaxCode, /* limiting value for current code size */
  48. ClearCode, /* GIF clear code */
  49. EOFCode, /* GIF end-of-information code */
  50. CurCode, OldCode, InCode, /* Decompressor variables */
  51. FirstFree, /* First free code, generated per GIF spec */
  52. FreeCode, /* Decompressor, next free slot in hash table*/
  53. FinChar, /* Decompressor variable */
  54. BitMask, /* AND mask for data size */
  55. ReadMask; /* Code AND mask for current code size */
  56. static bool Interlace, HasColormap;
  57. static SGIFRGBPixel* Image; /* The result array */
  58. static SGIFRGBcolor* Palette; /* The palette that is used */
  59. static uint8* IndexImage;
  60. static uint8* Raster; /* The raster data stream, unblocked */
  61. static uint8 used[256];
  62. static int numused;
  63. const char* id87 = "GIF87a";
  64. const char* id89 = "GIF89a";
  65. /* Fetch the next code from the raster data stream. The codes can be
  66. * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  67. * maintain our location in the Raster array as a BIT Offset. We compute
  68. * the uint8 Offset into the raster array by dividing this by 8, pick up
  69. * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  70. * bring the desired code to the bottom, then mask it off and return it.
  71. */
  72. inline int ReadCode (void)
  73. {
  74. int RawCode, ByteOffset;
  75. ByteOffset = BitOffset / 8;
  76. RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  77. if (CodeSize >= 8)
  78. {
  79. RawCode += (0x10000 * Raster[ByteOffset + 2]);
  80. }
  81. RawCode >>= (BitOffset % 8);
  82. BitOffset += CodeSize;
  83. return RawCode & ReadMask;
  84. }
  85. inline void AddToPixel (uint8 Index)
  86. {
  87. if (YC < Height)
  88. {
  89. SGIFRGBPixel* p = Image + YC * BytesPerScanline + XC;
  90. p->red = Palette[Index].red;
  91. p->green = Palette[Index].green;
  92. p->blue = Palette[Index].blue;
  93. p->alpha = 0;
  94. IndexImage[YC * BytesPerScanline + XC] = Index;
  95. }
  96. if (!used[Index])
  97. {
  98. used[Index] = 1;
  99. numused++;
  100. }
  101. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  102. if (++XC == Width)
  103. {
  104. /* If a non-interlaced picture, just increment YC to the next scan line.
  105. * If it's interlaced, deal with the interlace as described in the GIF
  106. * spec. Put the decoded scan line out to the screen if we haven't gone
  107. * past the bottom of it
  108. */
  109. XC = 0;
  110. if (!Interlace)
  111. {
  112. YC++;
  113. }
  114. else
  115. {
  116. switch (Pass)
  117. {
  118. case 0:
  119. YC += 8;
  120. if (YC >= Height)
  121. {
  122. Pass++;
  123. YC = 4;
  124. }
  125. break;
  126. case 1:
  127. YC += 8;
  128. if (YC >= Height)
  129. {
  130. Pass++;
  131. YC = 2;
  132. }
  133. break;
  134. case 2:
  135. YC += 4;
  136. if (YC >= Height)
  137. {
  138. Pass++;
  139. YC = 1;
  140. }
  141. break;
  142. case 3:
  143. YC += 2;
  144. break;
  145. default:
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. bool CImageGif::Load(const QString& fileName, CImageEx& outImage)
  152. {
  153. bool ret = false;
  154. std::vector<uint8> data;
  155. CCryFile file;
  156. if (!file.Open(fileName.toUtf8().data(), "rb"))
  157. {
  158. CLogFile::FormatLine("File not found %s", fileName.toUtf8().data());
  159. return false;
  160. }
  161. long filesize = static_cast<long>(file.GetLength());
  162. data.resize(filesize);
  163. uint8* ptr = &data[0];
  164. file.ReadRaw(ptr, filesize);
  165. /* Detect if this is a GIF file */
  166. if (strncmp ((char*)ptr, "GIF87a", 6) && strncmp ((char*)ptr, "GIF89a", 6))
  167. {
  168. CLogFile::FormatLine("Bad GIF file format %s", fileName.toUtf8().data());
  169. return false;
  170. }
  171. unsigned char ch, ch1;
  172. uint8* ptr1;
  173. int i;
  174. TImage<uint8> outImageIndex;
  175. /* The hash table used by the decompressor */
  176. int* Prefix;
  177. int* Suffix;
  178. /* An output array used by the decompressor */
  179. int* OutCode;
  180. CHK (Prefix = new int [4096]);
  181. CHK (Suffix = new int [4096]);
  182. CHK (OutCode = new int [1025]);
  183. BitOffset = 0;
  184. XC = YC = 0;
  185. Pass = 0;
  186. OutCount = 0;
  187. Palette = nullptr;
  188. CHK (Raster = new uint8 [filesize]);
  189. if (strncmp((char*) ptr, id87, 6))
  190. {
  191. if (strncmp((char*) ptr, id89, 6))
  192. {
  193. CLogFile::FormatLine("Bad GIF file format %s",fileName.toUtf8().data());
  194. goto cleanup;
  195. }
  196. }
  197. ptr += 6;
  198. /* Get variables from the GIF screen descriptor */
  199. ch = NEXTBYTE;
  200. RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
  201. ch = NEXTBYTE;
  202. RHeight = ch + 0x100 * NEXTBYTE;
  203. ch = NEXTBYTE;
  204. HasColormap = ((ch & COLORMAPMASK) ? true : false);
  205. BitsPerPixel = (ch & 7) + 1;
  206. BitMask = ColorMapSize - 1;
  207. Background = NEXTBYTE; /* background color... not used. */
  208. if (NEXTBYTE) /* supposed to be NULL */
  209. {
  210. CLogFile::FormatLine("Bad GIF file format %s", fileName.toUtf8().data());
  211. goto cleanup;
  212. }
  213. /* Read in global colormap. */
  214. SGIFRGBcolor mspPal[1024];
  215. if (HasColormap)
  216. {
  217. for (i = 0; i < ColorMapSize; i++)
  218. {
  219. mspPal[i].red = NEXTBYTE;
  220. mspPal[i].green = NEXTBYTE;
  221. mspPal[i].blue = NEXTBYTE;
  222. used[i] = 0;
  223. }
  224. Palette = mspPal;
  225. numused = 0;
  226. } /* else no colormap in GIF file */
  227. /* look for image separator */
  228. for (ch = NEXTBYTE; ch != IMAGESEP; ch = NEXTBYTE)
  229. {
  230. i = ch;
  231. if (ch != START_EXTENSION)
  232. {
  233. CLogFile::FormatLine("Bad GIF file format %s", fileName.toUtf8().data());
  234. goto cleanup;
  235. }
  236. /* handle image extensions */
  237. switch (ch = NEXTBYTE)
  238. {
  239. case GRAPHIC_EXT:
  240. ch = NEXTBYTE;
  241. ptr += ch;
  242. break;
  243. case PLAINTEXT_EXT:
  244. break;
  245. case APPLICATION_EXT:
  246. break;
  247. case COMMENT_EXT:
  248. break;
  249. default:
  250. {
  251. CLogFile::FormatLine("Invalid GIF89 extension %s", fileName.toUtf8().data());
  252. goto cleanup;
  253. }
  254. }
  255. ch = NEXTBYTE;
  256. while (ch)
  257. {
  258. ptr += ch;
  259. ch = NEXTBYTE;
  260. }
  261. }
  262. /* Now read in values from the image descriptor */
  263. ch = NEXTBYTE;
  264. LeftOfs = ch + 0x100 * NEXTBYTE;
  265. ch = NEXTBYTE;
  266. TopOfs = ch + 0x100 * NEXTBYTE;
  267. ch = NEXTBYTE;
  268. Width = ch + 0x100 * NEXTBYTE;
  269. ch = NEXTBYTE;
  270. Height = ch + 0x100 * NEXTBYTE;
  271. Interlace = ((NEXTBYTE & INTERLACEMASK) ? true : false);
  272. // Set the dimensions which will also allocate the image data
  273. // buffer.
  274. outImage.Allocate(Width, Height);
  275. //mfSet_dimensions (Width, Height);
  276. Image = (SGIFRGBPixel*)outImage.GetData();
  277. outImageIndex.Allocate(Width, Height);
  278. IndexImage = outImageIndex.GetData();
  279. /* Note that I ignore the possible existence of a local color map.
  280. * I'm told there aren't many files around that use them, and the spec
  281. * says it's defined for future use. This could lead to an error
  282. * reading some files.
  283. */
  284. /* Start reading the raster data. First we get the intial code size
  285. * and compute decompressor constant values, based on this code size.
  286. */
  287. CodeSize = NEXTBYTE;
  288. ClearCode = (1 << CodeSize);
  289. EOFCode = ClearCode + 1;
  290. FreeCode = FirstFree = ClearCode + 2;
  291. /* The GIF spec has it that the code size is the code size used to
  292. * compute the above values is the code size given in the file, but the
  293. * code size used in compression/decompression is the code size given in
  294. * the file plus one. (thus the ++).
  295. */
  296. CodeSize++;
  297. InitCodeSize = CodeSize;
  298. MaxCode = (1 << CodeSize);
  299. ReadMask = MaxCode - 1;
  300. /* Read the raster data. Here we just transpose it from the GIF array
  301. * to the Raster array, turning it from a series of blocks into one long
  302. * data stream, which makes life much easier for ReadCode().
  303. */
  304. ptr1 = Raster;
  305. do
  306. {
  307. ch = ch1 = NEXTBYTE;
  308. while (ch--)
  309. {
  310. *ptr1++ = NEXTBYTE;
  311. }
  312. if ((ptr1 - Raster) > filesize)
  313. {
  314. CLogFile::FormatLine("Corrupted GIF file (unblock) %s", fileName.toUtf8().data());
  315. goto cleanup;
  316. }
  317. }
  318. while (ch1);
  319. BytesPerScanline = Width;
  320. /* Decompress the file, continuing until you see the GIF EOF code.
  321. * One obvious enhancement is to add checking for corrupt files here.
  322. */
  323. Code = ReadCode ();
  324. while (Code != EOFCode)
  325. {
  326. /* Clear code sets everything back to its initial value, then reads the
  327. * immediately subsequent code as uncompressed data.
  328. */
  329. if (Code == ClearCode)
  330. {
  331. CodeSize = InitCodeSize;
  332. MaxCode = (1 << CodeSize);
  333. ReadMask = MaxCode - 1;
  334. FreeCode = FirstFree;
  335. CurCode = OldCode = Code = ReadCode();
  336. FinChar = CurCode & BitMask;
  337. AddToPixel(static_cast<uint8>(FinChar));
  338. }
  339. else
  340. {
  341. /* If not a clear code, then must be data: save same as CurCode and InCode */
  342. CurCode = InCode = Code;
  343. /* If greater or equal to FreeCode, not in the hash table yet;
  344. * repeat the last character decoded
  345. */
  346. if (CurCode >= FreeCode)
  347. {
  348. CurCode = OldCode;
  349. OutCode[OutCount++] = FinChar;
  350. }
  351. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  352. * through the hash table to its end; each code in the chain puts its
  353. * associated output code on the output queue.
  354. */
  355. while (CurCode > BitMask)
  356. {
  357. if (OutCount > 1024)
  358. {
  359. CLogFile::FormatLine("Corrupted GIF file (OutCount) %s", fileName.toUtf8().data());
  360. goto cleanup;
  361. }
  362. OutCode[OutCount++] = Suffix[CurCode];
  363. CurCode = Prefix[CurCode];
  364. }
  365. /* The last code in the chain is treated as raw data. */
  366. FinChar = CurCode & BitMask;
  367. OutCode[OutCount++] = FinChar;
  368. /* Now we put the data out to the Output routine.
  369. * It's been stacked LIFO, so deal with it that way...
  370. */
  371. for (i = OutCount - 1; i >= 0; i--)
  372. {
  373. AddToPixel(static_cast<uint8>(OutCode[i]));
  374. }
  375. OutCount = 0;
  376. /* Build the hash table on-the-fly. No table is stored in the file. */
  377. Prefix[FreeCode] = OldCode;
  378. Suffix[FreeCode] = FinChar;
  379. OldCode = InCode;
  380. /* Point to the next slot in the table. If we exceed the current
  381. * MaxCode value, increment the code size unless it's already 12. If it
  382. * is, do nothing: the next code decompressed better be CLEAR
  383. */
  384. FreeCode++;
  385. if (FreeCode >= MaxCode)
  386. {
  387. if (CodeSize < 12)
  388. {
  389. CodeSize++;
  390. MaxCode *= 2;
  391. ReadMask = (1 << CodeSize) - 1;
  392. }
  393. }
  394. }
  395. Code = ReadCode ();
  396. }
  397. ret = true;
  398. cleanup:
  399. if (Raster)
  400. {
  401. CHK (delete [] Raster);
  402. }
  403. if (Prefix)
  404. {
  405. CHK (delete [] Prefix);
  406. }
  407. if (Suffix)
  408. {
  409. CHK (delete [] Suffix);
  410. }
  411. if (OutCode)
  412. {
  413. CHK (delete [] OutCode);
  414. }
  415. return ret;
  416. }