00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012
00013 typedef unsigned char byte;
00014 typedef struct GifColorType {
00015 byte Red, Green, Blue;
00016 } GifColorType;
00017
00018 #define ABS(x) ((x) > 0 ? (x) : (-(x)))
00019
00020 #define GIF_ERROR 0
00021 #define GIF_OK 1
00022
00023
00024 #define COLOR_ARRAY_SIZE 32768
00025 #define BITS_PER_PRIM_COLOR 5
00026 #define MAX_PRIM_COLOR 0x1f
00027
00028
00029 static int SortRGBAxis;
00030
00031 typedef struct QuantizedColorType {
00032 byte RGB[3];
00033 byte NewColorIndex;
00034 long Count;
00035 struct QuantizedColorType *Pnext;
00036 } QuantizedColorType;
00037
00038 typedef struct NewColorMapType {
00039 byte RGBMin[3], RGBWidth[3];
00040 unsigned int NumEntries;
00041 long Count;
00042 QuantizedColorType *QuantizedColors;
00043 } NewColorMapType;
00044
00045 static int SubdivColorMap(NewColorMapType *NewColorSubdiv,
00046 unsigned int ColorMapSize,
00047 unsigned int *NewColorMapSize);
00048 static int SortCmpRtn(const void *Entry1, const void *Entry2);
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 int GIFquantize(unsigned int Width, unsigned int Height, int *ColorMapSize,
00064 byte *RedInput, byte *GreenInput, byte *BlueInput,
00065 byte *OutputBuffer, GifColorType *OutputColorMap)
00066 {
00067 unsigned int Index, NumOfEntries, newsize;
00068 int i, j, MaxRGBError[3];
00069 int NewColorMapSize;
00070 long Red, Green, Blue;
00071 NewColorMapType NewColorSubdiv[256];
00072 QuantizedColorType *ColorArrayEntries, *QuantizedColor;
00073
00074 if ((ColorArrayEntries = (QuantizedColorType *)
00075 malloc(sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE)) == NULL) {
00076 fprintf(stderr, "QuantizeBuffer: not enough memory\n");
00077 return GIF_ERROR;
00078 }
00079
00080 for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
00081 ColorArrayEntries[i].RGB[0]= i >> (2 * BITS_PER_PRIM_COLOR);
00082 ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & MAX_PRIM_COLOR;
00083 ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
00084 ColorArrayEntries[i].Count = 0;
00085 }
00086
00087
00088 for (i = 0; i < (int)(Width * Height); i++) {
00089 Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR))
00090 << (2 * BITS_PER_PRIM_COLOR)) +
00091 ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR))
00092 << BITS_PER_PRIM_COLOR) +
00093 (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
00094 ColorArrayEntries[Index].Count++;
00095 }
00096
00097
00098
00099 for (i = 0; i < 256; i++) {
00100 NewColorSubdiv[i].QuantizedColors = NULL;
00101 NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
00102 for (j = 0; j < 3; j++) {
00103 NewColorSubdiv[i].RGBMin[j] = 0;
00104 NewColorSubdiv[i].RGBWidth[j] = 255;
00105 }
00106 }
00107
00108
00109 for (i = 0; i < COLOR_ARRAY_SIZE; i++)
00110 if (ColorArrayEntries[i].Count > 0) break;
00111 QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
00112 NumOfEntries = 1;
00113 while (++i < COLOR_ARRAY_SIZE)
00114 if (ColorArrayEntries[i].Count > 0) {
00115 QuantizedColor -> Pnext = &ColorArrayEntries[i];
00116 QuantizedColor = &ColorArrayEntries[i];
00117 NumOfEntries++;
00118 }
00119 QuantizedColor -> Pnext = NULL;
00120
00121 NewColorSubdiv[0].NumEntries = NumOfEntries;
00122 NewColorSubdiv[0].Count = ((long) Width) * Height;
00123 newsize = 1;
00124 if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &newsize) != GIF_OK) {
00125 free((char *) ColorArrayEntries);
00126 return GIF_ERROR;
00127 }
00128 NewColorMapSize = (int)newsize;
00129 if (NewColorMapSize < *ColorMapSize) {
00130
00131 for (i = NewColorMapSize; i < *ColorMapSize; i++)
00132 OutputColorMap[i].Red =
00133 OutputColorMap[i].Green =
00134 OutputColorMap[i].Blue = 0;
00135 }
00136
00137
00138
00139 for (i = 0; i < NewColorMapSize; i++) {
00140 if ((j = NewColorSubdiv[i].NumEntries) > 0) {
00141 QuantizedColor = NewColorSubdiv[i].QuantizedColors;
00142 Red = Green = Blue = 0;
00143 while (QuantizedColor) {
00144 QuantizedColor -> NewColorIndex = i;
00145 Red += QuantizedColor -> RGB[0];
00146 Green += QuantizedColor -> RGB[1];
00147 Blue += QuantizedColor -> RGB[2];
00148 QuantizedColor = QuantizedColor -> Pnext;
00149 }
00150 OutputColorMap[i].Red = (byte)((Red << (8 - BITS_PER_PRIM_COLOR)) / j);
00151 OutputColorMap[i].Green = (byte)((Green << (8 - BITS_PER_PRIM_COLOR)) / j);
00152 OutputColorMap[i].Blue= (byte)((Blue << (8 - BITS_PER_PRIM_COLOR)) / j);
00153 }
00154 else
00155 fprintf(stderr, "Null entry in quantized color map - thats weird.");
00156 }
00157
00158
00159
00160 MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
00161 for (i = 0; i < (int)(Width * Height); i++) {
00162 Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR))
00163 << (2 * BITS_PER_PRIM_COLOR)) +
00164 ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR))
00165 << BITS_PER_PRIM_COLOR) +
00166 (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
00167 Index = ColorArrayEntries[Index].NewColorIndex;
00168 OutputBuffer[i] = Index;
00169 if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
00170 MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
00171 if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
00172 MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
00173 if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
00174 MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
00175 }
00176
00177 #ifdef DEBUG
00178 fprintf(stderr,
00179 "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
00180 MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
00181 #endif
00182
00183 free((char *) ColorArrayEntries);
00184
00185 *ColorMapSize = NewColorMapSize;
00186
00187 return GIF_OK;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196 static int SubdivColorMap(NewColorMapType *NewColorSubdiv,
00197 unsigned int ColorMapSize,
00198 unsigned int *NewColorMapSize)
00199 {
00200 int MaxSize;
00201 unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor;
00202 long Sum, Count;
00203 QuantizedColorType *QuantizedColor, **SortArray;
00204
00205 while (ColorMapSize > *NewColorMapSize) {
00206
00207 MaxSize = -1;
00208 for (i = 0; i < *NewColorMapSize; i++) {
00209 for (j = 0; j < 3; j++) {
00210 if (((int) NewColorSubdiv[i].RGBWidth[j]) > MaxSize &&
00211 NewColorSubdiv[i].NumEntries > 1) {
00212 MaxSize = NewColorSubdiv[i].RGBWidth[j];
00213 Index = i;
00214 SortRGBAxis = j;
00215 }
00216 }
00217 }
00218
00219 if (MaxSize == -1)
00220 return GIF_OK;
00221
00222
00223
00224
00225
00226 if ((SortArray = (QuantizedColorType **)
00227 malloc(sizeof(QuantizedColorType *) *
00228 NewColorSubdiv[Index].NumEntries)) == NULL)
00229 return GIF_ERROR;
00230 for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
00231 j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
00232 j++, QuantizedColor = QuantizedColor -> Pnext)
00233 SortArray[j] = QuantizedColor;
00234 qsort(SortArray, NewColorSubdiv[Index].NumEntries,
00235 sizeof(QuantizedColorType *), SortCmpRtn);
00236
00237
00238 for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
00239 SortArray[j] -> Pnext = SortArray[j + 1];
00240 SortArray[NewColorSubdiv[Index].NumEntries - 1] -> Pnext = NULL;
00241 NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
00242 free((char *) SortArray);
00243
00244
00245 Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor -> Count;
00246 NumEntries = 1;
00247 Count = QuantizedColor -> Count;
00248 while ((Sum -= QuantizedColor -> Pnext -> Count) >= 0 &&
00249 QuantizedColor -> Pnext != NULL &&
00250 QuantizedColor -> Pnext -> Pnext != NULL) {
00251 QuantizedColor = QuantizedColor -> Pnext;
00252 NumEntries++;
00253 Count += QuantizedColor -> Count;
00254 }
00255
00256
00257
00258
00259 MaxColor = QuantizedColor -> RGB[SortRGBAxis];
00260 MinColor = QuantizedColor -> Pnext -> RGB[SortRGBAxis];
00261 MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
00262 MinColor <<= (8 - BITS_PER_PRIM_COLOR);
00263
00264
00265 NewColorSubdiv[*NewColorMapSize].QuantizedColors =
00266 QuantizedColor -> Pnext;
00267 QuantizedColor -> Pnext = NULL;
00268 NewColorSubdiv[*NewColorMapSize].Count = Count;
00269 NewColorSubdiv[Index].Count -= Count;
00270 NewColorSubdiv[*NewColorMapSize].NumEntries =
00271 NewColorSubdiv[Index].NumEntries - NumEntries;
00272 NewColorSubdiv[Index].NumEntries = NumEntries;
00273 for (j = 0; j < 3; j++) {
00274 NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
00275 NewColorSubdiv[Index].RGBMin[j];
00276 NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
00277 NewColorSubdiv[Index].RGBWidth[j];
00278 }
00279 NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
00280 NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
00281 NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] -
00282 MinColor;
00283 NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
00284
00285 NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
00286 MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
00287
00288 (*NewColorMapSize)++;
00289 }
00290
00291 return GIF_OK;
00292 }
00293
00294
00295
00296
00297 static int SortCmpRtn(const void *Entry1, const void *Entry2)
00298 {
00299 return (* ((QuantizedColorType **) Entry1)) -> RGB[SortRGBAxis] -
00300 (* ((QuantizedColorType **) Entry2)) -> RGB[SortRGBAxis];
00301 }