0003-gifcodec.c-Include-copy-of-GifQuantizeBuffer-functio.patch 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. From afde9145030ff4989f0d7933389c20244eaf8039 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= <alex.koeplinger@outlook.com>
  3. Date: Thu, 1 Aug 2019 17:08:36 +0200
  4. Subject: [PATCH] gifcodec.c: Include copy of GifQuantizeBuffer function from
  5. giflib (#575)
  6. It was removed upstream so we need to include a copy of it.
  7. The upstream code is licensed as MIT.
  8. Fixes https://github.com/mono/libgdiplus/issues/546
  9. Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>
  10. ---
  11. src/gifcodec.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++--
  12. 1 file changed, 369 insertions(+), 8 deletions(-)
  13. diff --git a/src/gifcodec.c b/src/gifcodec.c
  14. index 6f8dedb..29a9899 100644
  15. --- a/src/gifcodec.c
  16. +++ b/src/gifcodec.c
  17. @@ -40,6 +40,374 @@ GUID gdip_gif_image_format_guid = {0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0
  18. #include "gifcodec.h"
  19. +/* START GifQuantizeBuffer copy from giflib
  20. +
  21. +The giflib 5.2.0 release notes mention:
  22. +
  23. +> The undocumented and deprecated GifQuantizeBuffer() entry point
  24. +> has been moved to the util library to reduce libgif size and attack
  25. +> surface. Applications needing this function are couraged to link the
  26. +> util library or make their own copy.
  27. +
  28. +Since the util library doesn't get installed in most distros we can't
  29. +link against it and need to make our own copy called LibgdiplusGifQuantizeBuffer.
  30. +This is taken from giflib 52b62de83d5facbbbde042b85bf3f61182e3bebd.
  31. +
  32. +> The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond
  33. +>
  34. +> Permission is hereby granted, free of charge, to any person obtaining a copy
  35. +> of this software and associated documentation files (the "Software"), to deal
  36. +> in the Software without restriction, including without limitation the rights
  37. +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  38. +> copies of the Software, and to permit persons to whom the Software is
  39. +> furnished to do so, subject to the following conditions:
  40. +>
  41. +> The above copyright notice and this permission notice shall be included in
  42. +> all copies or substantial portions of the Software.
  43. +>
  44. +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  45. +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  46. +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  47. +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  48. +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  49. +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  50. +> THE SOFTWARE.
  51. +
  52. +*/
  53. +
  54. +/*****************************************************************************
  55. +
  56. + quantize.c - quantize a high resolution image into lower one
  57. +
  58. + Based on: "Color Image Quantization for frame buffer Display", by
  59. + Paul Heckbert SIGGRAPH 1982 page 297-307.
  60. +
  61. + This doesn't really belong in the core library, was undocumented,
  62. + and was removed in 4.2. Then it turned out some client apps were
  63. + actually using it, so it was restored in 5.0.
  64. +
  65. +SPDX-License-Identifier: MIT
  66. +
  67. +******************************************************************************/
  68. +
  69. +#include <stdlib.h>
  70. +#include <stdio.h>
  71. +#include "gif_lib.h"
  72. +//#include "gif_lib_private.h"
  73. +
  74. +//#define ABS(x) ((x) > 0 ? (x) : (-(x)))
  75. +
  76. +#define COLOR_ARRAY_SIZE 32768
  77. +#define BITS_PER_PRIM_COLOR 5
  78. +#define MAX_PRIM_COLOR 0x1f
  79. +
  80. +static int SortRGBAxis;
  81. +
  82. +typedef struct QuantizedColorType {
  83. + GifByteType RGB[3];
  84. + GifByteType NewColorIndex;
  85. + long Count;
  86. + struct QuantizedColorType *Pnext;
  87. +} QuantizedColorType;
  88. +
  89. +typedef struct NewColorMapType {
  90. + GifByteType RGBMin[3], RGBWidth[3];
  91. + unsigned int NumEntries; /* # of QuantizedColorType in linked list below */
  92. + unsigned long Count; /* Total number of pixels in all the entries */
  93. + QuantizedColorType *QuantizedColors;
  94. +} NewColorMapType;
  95. +
  96. +static int SubdivColorMap(NewColorMapType * NewColorSubdiv,
  97. + unsigned int ColorMapSize,
  98. + unsigned int *NewColorMapSize);
  99. +static int SortCmpRtn(const void *Entry1, const void *Entry2);
  100. +
  101. +/******************************************************************************
  102. + Quantize high resolution image into lower one. Input image consists of a
  103. + 2D array for each of the RGB colors with size Width by Height. There is no
  104. + Color map for the input. Output is a quantized image with 2D array of
  105. + indexes into the output color map.
  106. + Note input image can be 24 bits at the most (8 for red/green/blue) and
  107. + the output has 256 colors at the most (256 entries in the color map.).
  108. + ColorMapSize specifies size of color map up to 256 and will be updated to
  109. + real size before returning.
  110. + Also non of the parameter are allocated by this routine.
  111. + This function returns GIF_OK if successful, GIF_ERROR otherwise.
  112. +******************************************************************************/
  113. +int
  114. +LibgdiplusGifQuantizeBuffer(unsigned int Width,
  115. + unsigned int Height,
  116. + int *ColorMapSize,
  117. + GifByteType * RedInput,
  118. + GifByteType * GreenInput,
  119. + GifByteType * BlueInput,
  120. + GifByteType * OutputBuffer,
  121. + GifColorType * OutputColorMap) {
  122. +
  123. + unsigned int Index, NumOfEntries;
  124. + int i, j, MaxRGBError[3];
  125. + unsigned int NewColorMapSize;
  126. + long Red, Green, Blue;
  127. + NewColorMapType NewColorSubdiv[256];
  128. + QuantizedColorType *ColorArrayEntries, *QuantizedColor;
  129. +
  130. + ColorArrayEntries = (QuantizedColorType *)malloc(
  131. + sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE);
  132. + if (ColorArrayEntries == NULL) {
  133. + return GIF_ERROR;
  134. + }
  135. +
  136. + for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
  137. + ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR);
  138. + ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) &
  139. + MAX_PRIM_COLOR;
  140. + ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
  141. + ColorArrayEntries[i].Count = 0;
  142. + }
  143. +
  144. + /* Sample the colors and their distribution: */
  145. + for (i = 0; i < (int)(Width * Height); i++) {
  146. + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
  147. + (2 * BITS_PER_PRIM_COLOR)) +
  148. + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
  149. + BITS_PER_PRIM_COLOR) +
  150. + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
  151. + ColorArrayEntries[Index].Count++;
  152. + }
  153. +
  154. + /* Put all the colors in the first entry of the color map, and call the
  155. + * recursive subdivision process. */
  156. + for (i = 0; i < 256; i++) {
  157. + NewColorSubdiv[i].QuantizedColors = NULL;
  158. + NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
  159. + for (j = 0; j < 3; j++) {
  160. + NewColorSubdiv[i].RGBMin[j] = 0;
  161. + NewColorSubdiv[i].RGBWidth[j] = 255;
  162. + }
  163. + }
  164. +
  165. + /* Find the non empty entries in the color table and chain them: */
  166. + for (i = 0; i < COLOR_ARRAY_SIZE; i++)
  167. + if (ColorArrayEntries[i].Count > 0)
  168. + break;
  169. + QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
  170. + NumOfEntries = 1;
  171. + while (++i < COLOR_ARRAY_SIZE)
  172. + if (ColorArrayEntries[i].Count > 0) {
  173. + QuantizedColor->Pnext = &ColorArrayEntries[i];
  174. + QuantizedColor = &ColorArrayEntries[i];
  175. + NumOfEntries++;
  176. + }
  177. + QuantizedColor->Pnext = NULL;
  178. +
  179. + NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */
  180. + NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */
  181. + NewColorMapSize = 1;
  182. + if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) !=
  183. + GIF_OK) {
  184. + free((char *)ColorArrayEntries);
  185. + return GIF_ERROR;
  186. + }
  187. + if (NewColorMapSize < *ColorMapSize) {
  188. + /* And clear rest of color map: */
  189. + for (i = NewColorMapSize; i < *ColorMapSize; i++)
  190. + OutputColorMap[i].Red = OutputColorMap[i].Green =
  191. + OutputColorMap[i].Blue = 0;
  192. + }
  193. +
  194. + /* Average the colors in each entry to be the color to be used in the
  195. + * output color map, and plug it into the output color map itself. */
  196. + for (i = 0; i < NewColorMapSize; i++) {
  197. + if ((j = NewColorSubdiv[i].NumEntries) > 0) {
  198. + QuantizedColor = NewColorSubdiv[i].QuantizedColors;
  199. + Red = Green = Blue = 0;
  200. + while (QuantizedColor) {
  201. + QuantizedColor->NewColorIndex = i;
  202. + Red += QuantizedColor->RGB[0];
  203. + Green += QuantizedColor->RGB[1];
  204. + Blue += QuantizedColor->RGB[2];
  205. + QuantizedColor = QuantizedColor->Pnext;
  206. + }
  207. + OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j;
  208. + OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j;
  209. + OutputColorMap[i].Blue = (Blue << (8 - BITS_PER_PRIM_COLOR)) / j;
  210. + }
  211. + }
  212. +
  213. + /* Finally scan the input buffer again and put the mapped index in the
  214. + * output buffer. */
  215. + MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
  216. + for (i = 0; i < (int)(Width * Height); i++) {
  217. + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
  218. + (2 * BITS_PER_PRIM_COLOR)) +
  219. + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
  220. + BITS_PER_PRIM_COLOR) +
  221. + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
  222. + Index = ColorArrayEntries[Index].NewColorIndex;
  223. + OutputBuffer[i] = Index;
  224. + if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
  225. + MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
  226. + if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
  227. + MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
  228. + if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
  229. + MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
  230. + }
  231. +
  232. +#ifdef DEBUG
  233. + fprintf(stderr,
  234. + "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
  235. + MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
  236. +#endif /* DEBUG */
  237. +
  238. + free((char *)ColorArrayEntries);
  239. +
  240. + *ColorMapSize = NewColorMapSize;
  241. +
  242. + return GIF_OK;
  243. +}
  244. +
  245. +/******************************************************************************
  246. + Routine to subdivide the RGB space recursively using median cut in each
  247. + axes alternatingly until ColorMapSize different cubes exists.
  248. + The biggest cube in one dimension is subdivide unless it has only one entry.
  249. + Returns GIF_ERROR if failed, otherwise GIF_OK.
  250. +*******************************************************************************/
  251. +static int
  252. +SubdivColorMap(NewColorMapType * NewColorSubdiv,
  253. + unsigned int ColorMapSize,
  254. + unsigned int *NewColorMapSize) {
  255. +
  256. + unsigned int i, j, Index = 0;
  257. + QuantizedColorType *QuantizedColor, **SortArray;
  258. +
  259. + while (ColorMapSize > *NewColorMapSize) {
  260. + /* Find candidate for subdivision: */
  261. + long Sum, Count;
  262. + int MaxSize = -1;
  263. + unsigned int NumEntries, MinColor, MaxColor;
  264. + for (i = 0; i < *NewColorMapSize; i++) {
  265. + for (j = 0; j < 3; j++) {
  266. + if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) &&
  267. + (NewColorSubdiv[i].NumEntries > 1)) {
  268. + MaxSize = NewColorSubdiv[i].RGBWidth[j];
  269. + Index = i;
  270. + SortRGBAxis = j;
  271. + }
  272. + }
  273. + }
  274. +
  275. + if (MaxSize == -1)
  276. + return GIF_OK;
  277. +
  278. + /* Split the entry Index into two along the axis SortRGBAxis: */
  279. +
  280. + /* Sort all elements in that entry along the given axis and split at
  281. + * the median. */
  282. + SortArray = (QuantizedColorType **)malloc(
  283. + sizeof(QuantizedColorType *) *
  284. + NewColorSubdiv[Index].NumEntries);
  285. + if (SortArray == NULL)
  286. + return GIF_ERROR;
  287. + for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
  288. + j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
  289. + j++, QuantizedColor = QuantizedColor->Pnext)
  290. + SortArray[j] = QuantizedColor;
  291. +
  292. + /*
  293. + * Because qsort isn't stable, this can produce differing
  294. + * results for the order of tuples depending on platform
  295. + * details of how qsort() is implemented.
  296. + *
  297. + * We mitigate this problem by sorting on all three axes rather
  298. + * than only the one specied by SortRGBAxis; that way the instability
  299. + * can only become an issue if there are multiple color indices
  300. + * referring to identical RGB tuples. Older versions of this
  301. + * sorted on only the one axis.
  302. + */
  303. + qsort(SortArray, NewColorSubdiv[Index].NumEntries,
  304. + sizeof(QuantizedColorType *), SortCmpRtn);
  305. +
  306. + /* Relink the sorted list into one: */
  307. + for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
  308. + SortArray[j]->Pnext = SortArray[j + 1];
  309. + SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL;
  310. + NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
  311. + free((char *)SortArray);
  312. +
  313. + /* Now simply add the Counts until we have half of the Count: */
  314. + Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count;
  315. + NumEntries = 1;
  316. + Count = QuantizedColor->Count;
  317. + while (QuantizedColor->Pnext != NULL &&
  318. + (Sum -= QuantizedColor->Pnext->Count) >= 0 &&
  319. + QuantizedColor->Pnext->Pnext != NULL) {
  320. + QuantizedColor = QuantizedColor->Pnext;
  321. + NumEntries++;
  322. + Count += QuantizedColor->Count;
  323. + }
  324. + /* Save the values of the last color of the first half, and first
  325. + * of the second half so we can update the Bounding Boxes later.
  326. + * Also as the colors are quantized and the BBoxes are full 0..255,
  327. + * they need to be rescaled.
  328. + */
  329. + MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */
  330. + /* coverity[var_deref_op] */
  331. + MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */
  332. + MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
  333. + MinColor <<= (8 - BITS_PER_PRIM_COLOR);
  334. +
  335. + /* Partition right here: */
  336. + NewColorSubdiv[*NewColorMapSize].QuantizedColors =
  337. + QuantizedColor->Pnext;
  338. + QuantizedColor->Pnext = NULL;
  339. + NewColorSubdiv[*NewColorMapSize].Count = Count;
  340. + NewColorSubdiv[Index].Count -= Count;
  341. + NewColorSubdiv[*NewColorMapSize].NumEntries =
  342. + NewColorSubdiv[Index].NumEntries - NumEntries;
  343. + NewColorSubdiv[Index].NumEntries = NumEntries;
  344. + for (j = 0; j < 3; j++) {
  345. + NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
  346. + NewColorSubdiv[Index].RGBMin[j];
  347. + NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
  348. + NewColorSubdiv[Index].RGBWidth[j];
  349. + }
  350. + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
  351. + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
  352. + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor;
  353. + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
  354. +
  355. + NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
  356. + MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
  357. +
  358. + (*NewColorMapSize)++;
  359. + }
  360. +
  361. + return GIF_OK;
  362. +}
  363. +
  364. +/****************************************************************************
  365. + Routine called by qsort to compare two entries.
  366. +*****************************************************************************/
  367. +
  368. +static int
  369. +SortCmpRtn(const void *Entry1,
  370. + const void *Entry2) {
  371. + QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1));
  372. + QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2));
  373. +
  374. + /* sort on all axes of the color space! */
  375. + int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256
  376. + + entry1->RGB[(SortRGBAxis+1) % 3] * 256
  377. + + entry1->RGB[(SortRGBAxis+2) % 3];
  378. + int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256
  379. + + entry2->RGB[(SortRGBAxis+1) % 3] * 256
  380. + + entry2->RGB[(SortRGBAxis+2) % 3];
  381. +
  382. + return hash1 - hash2;
  383. +}
  384. +
  385. +/* END GifQuantizeBuffer copy from giflib */
  386. +
  387. /* Data structure used for callback */
  388. typedef struct
  389. {
  390. @@ -851,14 +1219,7 @@ gdip_save_gif_image (void *stream, GpImage *image, BOOL from_file)
  391. v += 4;
  392. }
  393. }
  394. - if (
  395. -#if GIFLIB_MAJOR >= 5
  396. - GifQuantizeBuffer(
  397. -#else
  398. - QuantizeBuffer(
  399. -#endif
  400. - bitmap_data->width, bitmap_data->height, &cmap_size,
  401. - red, green, blue, pixbuf, cmap->Colors) == GIF_ERROR) {
  402. + if (LibgdiplusGifQuantizeBuffer(bitmap_data->width, bitmap_data->height, &cmap_size, red, green, blue, pixbuf, cmap->Colors) == GIF_ERROR) {
  403. goto error;
  404. }
  405. }
  406. --
  407. 2.20.1