Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 571610 | Differences between
and this patch

Collapse All | Expand All

(-)a/src/gifcodec.c (+287 lines)
Lines 39-42 GUID gdip_gif_image_format_guid = {0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0 Link Here
39
39
40
#include "gifcodec.h"
40
#include "gifcodec.h"
41
41
42
#define COLOR_ARRAY_SIZE 32768
43
#define BITS_PER_PRIM_COLOR 5
44
#define MAX_PRIM_COLOR      0x1f
45
46
static int SortRGBAxis;
47
48
typedef struct QuantizedColorType {
49
    GifByteType RGB[3];
50
    GifByteType NewColorIndex;
51
    long Count;
52
    struct QuantizedColorType *Pnext;
53
} QuantizedColorType;
54
55
typedef struct NewColorMapType {
56
    GifByteType RGBMin[3], RGBWidth[3];
57
    unsigned int NumEntries; /* # of QuantizedColorType in linked list below */
58
    unsigned long Count; /* Total number of pixels in all the entries */
59
    QuantizedColorType *QuantizedColors;
60
} NewColorMapType;
61
62
63
/****************************************************************************
64
 * Routine called by qsort to compare two entries.
65
 ****************************************************************************/
66
static int
67
SortCmpRtn(const void *Entry1,
68
           const void *Entry2) {
69
70
    return (*((QuantizedColorType **) Entry1))->RGB[SortRGBAxis] -
71
       (*((QuantizedColorType **) Entry2))->RGB[SortRGBAxis];
72
}
73
74
/******************************************************************************
75
 * Routine to subdivide the RGB space recursively using median cut in each
76
 * axes alternatingly until ColorMapSize different cubes exists.
77
 * The biggest cube in one dimension is subdivide unless it has only one entry.
78
 * Returns GIF_ERROR if failed, otherwise GIF_OK.
79
 ******************************************************************************/
80
static int
81
SubdivColorMap(NewColorMapType * NewColorSubdiv,
82
               unsigned int ColorMapSize,
83
               unsigned int *NewColorMapSize) {
84
85
    int MaxSize;
86
    unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor;
87
    long Sum, Count;
88
    QuantizedColorType *QuantizedColor, **SortArray;
89
90
    while (ColorMapSize > *NewColorMapSize) {
91
        /* Find candidate for subdivision: */
92
        MaxSize = -1;
93
        for (i = 0; i < *NewColorMapSize; i++) {
94
            for (j = 0; j < 3; j++) {
95
                if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) &&
96
                      (NewColorSubdiv[i].NumEntries > 1)) {
97
                    MaxSize = NewColorSubdiv[i].RGBWidth[j];
98
                    Index = i;
99
                    SortRGBAxis = j;
100
                }
101
            }
102
        }
103
104
        if (MaxSize == -1)
105
            return GIF_OK;
106
107
        /* Split the entry Index into two along the axis SortRGBAxis: */
108
109
        /* Sort all elements in that entry along the given axis and split at
110
         * the median.  */
111
        SortArray = (QuantizedColorType **)malloc(
112
                      sizeof(QuantizedColorType *) *
113
                      NewColorSubdiv[Index].NumEntries);
114
        if (SortArray == NULL)
115
            return GIF_ERROR;
116
        for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
117
             j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
118
             j++, QuantizedColor = QuantizedColor->Pnext)
119
            SortArray[j] = QuantizedColor;
120
121
        qsort(SortArray, NewColorSubdiv[Index].NumEntries,
122
              sizeof(QuantizedColorType *), SortCmpRtn);
123
124
        /* Relink the sorted list into one: */
125
        for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
126
            SortArray[j]->Pnext = SortArray[j + 1];
127
        SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL;
128
        NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
129
        free((char *)SortArray);
130
131
        /* Now simply add the Counts until we have half of the Count: */
132
        Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count;
133
        NumEntries = 1;
134
        Count = QuantizedColor->Count;
135
        while (QuantizedColor->Pnext != NULL &&
136
              (Sum -= QuantizedColor->Pnext->Count) >= 0 &&
137
               QuantizedColor->Pnext->Pnext != NULL) {
138
            QuantizedColor = QuantizedColor->Pnext;
139
            NumEntries++;
140
            Count += QuantizedColor->Count;
141
        }
142
        /* Save the values of the last color of the first half, and first
143
         * of the second half so we can update the Bounding Boxes later.
144
         * Also as the colors are quantized and the BBoxes are full 0..255,
145
         * they need to be rescaled.
146
         */
147
        MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */
148
       /* coverity[var_deref_op] */
149
        MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */
150
        MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
151
        MinColor <<= (8 - BITS_PER_PRIM_COLOR);
152
153
        /* Partition right here: */
154
        NewColorSubdiv[*NewColorMapSize].QuantizedColors =
155
           QuantizedColor->Pnext;
156
        QuantizedColor->Pnext = NULL;
157
        NewColorSubdiv[*NewColorMapSize].Count = Count;
158
        NewColorSubdiv[Index].Count -= Count;
159
        NewColorSubdiv[*NewColorMapSize].NumEntries =
160
           NewColorSubdiv[Index].NumEntries - NumEntries;
161
        NewColorSubdiv[Index].NumEntries = NumEntries;
162
        for (j = 0; j < 3; j++) {
163
            NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
164
               NewColorSubdiv[Index].RGBMin[j];
165
            NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
166
               NewColorSubdiv[Index].RGBWidth[j];
167
        }
168
        NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
169
           NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
170
           NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor;
171
        NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
172
173
        NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
174
           MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
175
176
        (*NewColorMapSize)++;
177
    }
178
179
    return GIF_OK;
180
}
181
182
/******************************************************************************
183
 * Quantize high resolution image into lower one. Input image consists of a
184
 * 2D array for each of the RGB colors with size Width by Height. There is no
185
 * Color map for the input. Output is a quantized image with 2D array of
186
 * indexes into the output color map.
187
 *   Note input image can be 24 bits at the most (8 for red/green/blue) and
188
 * the output has 256 colors at the most (256 entries in the color map.).
189
 * ColorMapSize specifies size of color map up to 256 and will be updated to
190
 * real size before returning.
191
 *   Also non of the parameter are allocated by this routine.
192
 *   This function returns GIF_OK if succesfull, GIF_ERROR otherwise.
193
 ******************************************************************************/
194
static int
195
QuantizeBuffer(unsigned int Width,
196
               unsigned int Height,
197
               int *ColorMapSize,
198
               GifByteType * RedInput,
199
               GifByteType * GreenInput,
200
               GifByteType * BlueInput,
201
               GifByteType * OutputBuffer,
202
               GifColorType * OutputColorMap) {
203
204
    unsigned int Index, NumOfEntries;
205
    int i, j, MaxRGBError[3];
206
    unsigned int NewColorMapSize;
207
    long Red, Green, Blue;
208
    NewColorMapType NewColorSubdiv[256];
209
    QuantizedColorType *ColorArrayEntries, *QuantizedColor;
210
211
    ColorArrayEntries = (QuantizedColorType *)malloc(
212
                           sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE);
213
    if (ColorArrayEntries == NULL) {
214
        return GIF_ERROR;
215
    }
216
217
    for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
218
        ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR);
219
        ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) &
220
           MAX_PRIM_COLOR;
221
        ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
222
        ColorArrayEntries[i].Count = 0;
223
    }
224
225
    /* Sample the colors and their distribution: */
226
    for (i = 0; i < (int)(Width * Height); i++) {
227
        Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
228
                  (2 * BITS_PER_PRIM_COLOR)) +
229
                ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
230
                  BITS_PER_PRIM_COLOR) +
231
                (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
232
        ColorArrayEntries[Index].Count++;
233
    }
234
235
    /* Put all the colors in the first entry of the color map, and call the
236
     * recursive subdivision process.  */
237
    for (i = 0; i < 256; i++) {
238
        NewColorSubdiv[i].QuantizedColors = NULL;
239
        NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
240
        for (j = 0; j < 3; j++) {
241
            NewColorSubdiv[i].RGBMin[j] = 0;
242
            NewColorSubdiv[i].RGBWidth[j] = 255;
243
        }
244
    }
245
246
    /* Find the non empty entries in the color table and chain them: */
247
    for (i = 0; i < COLOR_ARRAY_SIZE; i++)
248
        if (ColorArrayEntries[i].Count > 0)
249
            break;
250
    QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
251
    NumOfEntries = 1;
252
    while (++i < COLOR_ARRAY_SIZE)
253
        if (ColorArrayEntries[i].Count > 0) {
254
            QuantizedColor->Pnext = &ColorArrayEntries[i];
255
            QuantizedColor = &ColorArrayEntries[i];
256
            NumOfEntries++;
257
        }
258
    QuantizedColor->Pnext = NULL;
259
260
    NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */
261
    NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */
262
    NewColorMapSize = 1;
263
    if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) !=
264
       GIF_OK) {
265
        free((char *)ColorArrayEntries);
266
        return GIF_ERROR;
267
    }
268
    if (NewColorMapSize < *ColorMapSize) {
269
        /* And clear rest of color map: */
270
        for (i = NewColorMapSize; i < *ColorMapSize; i++)
271
            OutputColorMap[i].Red = OutputColorMap[i].Green =
272
                OutputColorMap[i].Blue = 0;
273
    }
274
275
    /* Average the colors in each entry to be the color to be used in the
276
     * output color map, and plug it into the output color map itself. */
277
    for (i = 0; i < NewColorMapSize; i++) {
278
        if ((j = NewColorSubdiv[i].NumEntries) > 0) {
279
            QuantizedColor = NewColorSubdiv[i].QuantizedColors;
280
            Red = Green = Blue = 0;
281
            while (QuantizedColor) {
282
                QuantizedColor->NewColorIndex = i;
283
                Red += QuantizedColor->RGB[0];
284
                Green += QuantizedColor->RGB[1];
285
                Blue += QuantizedColor->RGB[2];
286
                QuantizedColor = QuantizedColor->Pnext;
287
            }
288
            OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j;
289
            OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j;
290
            OutputColorMap[i].Blue = (Blue << (8 - BITS_PER_PRIM_COLOR)) / j;
291
        } else
292
            fprintf(stderr,
293
                    "\n%s: Null entry in quantized color map - that's weird.\n",
294
                    "libgdiplus");
295
    }
296
297
    /* Finally scan the input buffer again and put the mapped index in the
298
     * output buffer.  */
299
    MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
300
    for (i = 0; i < (int)(Width * Height); i++) {
301
        Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
302
                 (2 * BITS_PER_PRIM_COLOR)) +
303
                ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
304
                 BITS_PER_PRIM_COLOR) +
305
                (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
306
        Index = ColorArrayEntries[Index].NewColorIndex;
307
        OutputBuffer[i] = Index;
308
        if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
309
            MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
310
        if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
311
            MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
312
        if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
313
            MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
314
    }
315
316
#ifdef DEBUG
317
    fprintf(stderr,
318
            "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
319
            MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
320
#endif /* DEBUG */
321
322
    free((char *)ColorArrayEntries);
323
324
    *ColorMapSize = NewColorMapSize;
325
326
    return GIF_OK;
327
}
328
42
/* Data structure used for callback */
329
/* Data structure used for callback */

Return to bug 571610