1 /* === C R E D I T S & D I S C L A I M E R S ==============
2 * Permission is given by the author to freely redistribute and include
3 * this code in any program as long as this credit is given where due.
5 * CQuantizer (c) 1996-1997 Jeff Prosise
7 * 31/08/2003 Davide Pizzolato - www.xdp.it
8 * - fixed minor bug in ProcessImage when bpp<=8
9 * - better color reduction to less than 16 colors
11 * COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT
12 * WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
13 * LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS,
14 * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE
15 * RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU.
16 * SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL
17 * DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
18 * SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
19 * ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED
20 * HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
22 * Use at your own risk!
23 * ==========================================================
25 * Modified for use with Haiku by David Powell & Stephan Aßmus.
27 #include "ColorQuantizer.h"
37 if (component
> 255.0)
40 return (uint8
)(component
+ 0.5f
);
43 struct BColorQuantizer::Node
{
44 bool isLeaf
; // TRUE if node has no children
45 uint32 pixelCount
; // Number of pixels represented by this leaf
46 uint32 sumR
; // Sum of red components
47 uint32 sumG
; // Sum of green components
48 uint32 sumB
; // Sum of blue components
49 uint32 sumA
; // Sum of alpha components
50 Node
* child
[8]; // Pointers to child nodes
51 Node
* next
; // Pointer to next reducible node
55 BColorQuantizer::BColorQuantizer(uint32 maxColors
, uint32 bitsPerColor
)
58 fMaxColors(maxColors
),
59 fOutputMaxColors(maxColors
),
60 fBitsPerColor(bitsPerColor
)
62 // override parameters if out of range
63 if (fBitsPerColor
> 8)
69 for (int i
= 0; i
<= (int)fBitsPerColor
; i
++)
70 fReducibleNodes
[i
] = NULL
;
74 BColorQuantizer::~BColorQuantizer()
82 BColorQuantizer::ProcessImage(const uint8
* const * rowPtrs
, int width
,
85 for (int y
= 0; y
< height
; y
++) {
86 for (int x
= 0; x
< width
; x
+= 3) {
87 uint8 b
= rowPtrs
[y
][x
];
88 uint8 g
= rowPtrs
[y
][x
+ 1];
89 uint8 r
= rowPtrs
[y
][x
+ 2];
90 _AddColor(&fTree
, r
, g
, b
, 0, fBitsPerColor
, 0, &fLeafCount
,
93 while (fLeafCount
> fMaxColors
)
94 _ReduceTree(fBitsPerColor
, &fLeafCount
, fReducibleNodes
);
103 BColorQuantizer::GetColorCount() const
110 BColorQuantizer::GetColorTable(RGBA
* table
) const
113 if (fOutputMaxColors
< 16) {
116 _GetPaletteColors(fTree
, tmpPalette
, &index
, sums
);
117 if (fLeafCount
> fOutputMaxColors
) {
118 for (uint32 j
= 0; j
< fOutputMaxColors
; j
++) {
119 uint32 a
= (j
* fLeafCount
) / fOutputMaxColors
;
120 uint32 b
= ((j
+ 1) * fLeafCount
) / fOutputMaxColors
;
126 for (uint32 k
= a
; k
< b
; k
++){
127 nr
+= tmpPalette
[k
].r
* sums
[k
];
128 ng
+= tmpPalette
[k
].g
* sums
[k
];
129 nb
+= tmpPalette
[k
].b
* sums
[k
];
130 na
+= tmpPalette
[k
].a
* sums
[k
];
133 table
[j
].r
= clip((float)nr
/ ns
);
134 table
[j
].g
= clip((float)ng
/ ns
);
135 table
[j
].b
= clip((float)nb
/ ns
);
136 table
[j
].a
= clip((float)na
/ ns
);
139 memcpy(table
, tmpPalette
, fLeafCount
* sizeof(RGBA
));
142 _GetPaletteColors(fTree
, table
, &index
, NULL
);
147 // #pragma mark - private
151 BColorQuantizer::_AddColor(Node
** _node
, uint8 r
, uint8 g
, uint8 b
, uint8 a
,
152 uint32 bitsPerColor
, uint32 level
, uint32
* _leafCount
,
153 Node
** reducibleNodes
)
155 static const uint8 kMask
[8]
156 = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
158 // If the node doesn't exist, create it.
160 *_node
= _CreateNode(level
, bitsPerColor
, _leafCount
, reducibleNodes
);
162 // Update color information if it's a leaf node.
163 if ((*_node
)->isLeaf
) {
164 (*_node
)->pixelCount
++;
170 // Recurse a level deeper if the node is not a leaf.
171 int shift
= 7 - level
;
172 int index
= (((r
& kMask
[level
]) >> shift
) << 2) |
173 (((g
& kMask
[level
]) >> shift
) << 1) |
174 (( b
& kMask
[level
]) >> shift
);
175 _AddColor(&((*_node
)->child
[index
]), r
, g
, b
, a
, bitsPerColor
,
176 level
+ 1, _leafCount
, reducibleNodes
);
181 BColorQuantizer::Node
*
182 BColorQuantizer::_CreateNode(uint32 level
, uint32 bitsPerColor
,
183 uint32
* _leafCount
, Node
** reducibleNodes
)
185 Node
* node
= (Node
*)calloc(1, sizeof(Node
));
190 node
->isLeaf
= (level
== bitsPerColor
) ? true : false;
194 node
->next
= reducibleNodes
[level
];
195 reducibleNodes
[level
] = node
;
202 BColorQuantizer::_ReduceTree(uint32 bitsPerColor
, uint32
* _leafCount
,
203 Node
** reducibleNodes
)
205 int i
= bitsPerColor
- 1;
206 // Find the deepest level containing at least one reducible node.
207 for (; i
> 0 && reducibleNodes
[i
] == NULL
; i
--)
210 // Reduce the node most recently added to the list at level i.
211 Node
* node
= reducibleNodes
[i
];
212 reducibleNodes
[i
] = node
->next
;
218 uint32 childCount
= 0;
220 for (i
= 0; i
< 8; i
++) {
221 if (node
->child
[i
] != NULL
) {
222 sumR
+= node
->child
[i
]->sumR
;
223 sumG
+= node
->child
[i
]->sumG
;
224 sumB
+= node
->child
[i
]->sumB
;
225 sumA
+= node
->child
[i
]->sumA
;
226 node
->pixelCount
+= node
->child
[i
]->pixelCount
;
228 free(node
->child
[i
]);
229 node
->child
[i
] = NULL
;
241 *_leafCount
-= (childCount
- 1);
246 BColorQuantizer::_DeleteTree(Node
** _node
)
248 for (int i
= 0; i
< 8; i
++) {
249 if ((*_node
)->child
[i
] != NULL
)
250 _DeleteTree(&((*_node
)->child
[i
]));
258 BColorQuantizer::_GetPaletteColors(Node
* node
, RGBA
* table
, uint32
* _index
,
265 table
[*_index
].r
= clip((float)node
->sumR
/ node
->pixelCount
);
266 table
[*_index
].g
= clip((float)node
->sumG
/ node
->pixelCount
);
267 table
[*_index
].b
= clip((float)node
->sumB
/ node
->pixelCount
);
268 table
[*_index
].a
= clip((float)node
->sumA
/ node
->pixelCount
);
270 sums
[*_index
] = node
->pixelCount
;
273 for (int i
= 0; i
< 8; i
++) {
274 if (node
->child
[i
] != NULL
)
275 _GetPaletteColors(node
->child
[i
], table
, _index
, sums
);