xref: /haiku/src/kits/interface/ColorConversion.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2001-2006, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold (bonefish@users.sf.net)
7  *		Michael Lotz <mmlr@mlotz.ch>
8  */
9 
10 /**	This file contains colorspace conversion functions
11  *	and a palette <-> true color conversion class.
12  */
13 
14 #include "ColorConversion.h"
15 
16 #include <Locker.h>
17 #include <Point.h>
18 
19 #include <new>
20 #include <string.h>
21 
22 
23 using std::nothrow;
24 
25 
26 namespace BPrivate {
27 
28 // TODO: system palette -- hard-coded for now, when the app server is ready
29 // we should use system_colors() or BScreen::ColorMap().
30 const rgb_color kSystemPalette[] = {
31  {   0,   0,   0, 255 }, {   8,   8,   8, 255 }, {  16,  16,  16, 255 },
32  {  24,  24,  24, 255 }, {  32,  32,  32, 255 }, {  40,  40,  40, 255 },
33  {  48,  48,  48, 255 }, {  56,  56,  56, 255 }, {  64,  64,  64, 255 },
34  {  72,  72,  72, 255 }, {  80,  80,  80, 255 }, {  88,  88,  88, 255 },
35  {  96,  96,  96, 255 }, { 104, 104, 104, 255 }, { 112, 112, 112, 255 },
36  { 120, 120, 120, 255 }, { 128, 128, 128, 255 }, { 136, 136, 136, 255 },
37  { 144, 144, 144, 255 }, { 152, 152, 152, 255 }, { 160, 160, 160, 255 },
38  { 168, 168, 168, 255 }, { 176, 176, 176, 255 }, { 184, 184, 184, 255 },
39  { 192, 192, 192, 255 }, { 200, 200, 200, 255 }, { 208, 208, 208, 255 },
40  { 216, 216, 216, 255 }, { 224, 224, 224, 255 }, { 232, 232, 232, 255 },
41  { 240, 240, 240, 255 }, { 248, 248, 248, 255 }, {   0,   0, 255, 255 },
42  {   0,   0, 229, 255 }, {   0,   0, 204, 255 }, {   0,   0, 179, 255 },
43  {   0,   0, 154, 255 }, {   0,   0, 129, 255 }, {   0,   0, 105, 255 },
44  {   0,   0,  80, 255 }, {   0,   0,  55, 255 }, {   0,   0,  30, 255 },
45  { 255,   0,   0, 255 }, { 228,   0,   0, 255 }, { 203,   0,   0, 255 },
46  { 178,   0,   0, 255 }, { 153,   0,   0, 255 }, { 128,   0,   0, 255 },
47  { 105,   0,   0, 255 }, {  80,   0,   0, 255 }, {  55,   0,   0, 255 },
48  {  30,   0,   0, 255 }, {   0, 255,   0, 255 }, {   0, 228,   0, 255 },
49  {   0, 203,   0, 255 }, {   0, 178,   0, 255 }, {   0, 153,   0, 255 },
50  {   0, 128,   0, 255 }, {   0, 105,   0, 255 }, {   0,  80,   0, 255 },
51  {   0,  55,   0, 255 }, {   0,  30,   0, 255 }, {   0, 152,  51, 255 },
52  { 255, 255, 255, 255 }, { 203, 255, 255, 255 }, { 203, 255, 203, 255 },
53  { 203, 255, 152, 255 }, { 203, 255, 102, 255 }, { 203, 255,  51, 255 },
54  { 203, 255,   0, 255 }, { 152, 255, 255, 255 }, { 152, 255, 203, 255 },
55  { 152, 255, 152, 255 }, { 152, 255, 102, 255 }, { 152, 255,  51, 255 },
56  { 152, 255,   0, 255 }, { 102, 255, 255, 255 }, { 102, 255, 203, 255 },
57  { 102, 255, 152, 255 }, { 102, 255, 102, 255 }, { 102, 255,  51, 255 },
58  { 102, 255,   0, 255 }, {  51, 255, 255, 255 }, {  51, 255, 203, 255 },
59  {  51, 255, 152, 255 }, {  51, 255, 102, 255 }, {  51, 255,  51, 255 },
60  {  51, 255,   0, 255 }, { 255, 152, 255, 255 }, { 255, 152, 203, 255 },
61  { 255, 152, 152, 255 }, { 255, 152, 102, 255 }, { 255, 152,  51, 255 },
62  { 255, 152,   0, 255 }, {   0, 102, 255, 255 }, {   0, 102, 203, 255 },
63  { 203, 203, 255, 255 }, { 203, 203, 203, 255 }, { 203, 203, 152, 255 },
64  { 203, 203, 102, 255 }, { 203, 203,  51, 255 }, { 203, 203,   0, 255 },
65  { 152, 203, 255, 255 }, { 152, 203, 203, 255 }, { 152, 203, 152, 255 },
66  { 152, 203, 102, 255 }, { 152, 203,  51, 255 }, { 152, 203,   0, 255 },
67  { 102, 203, 255, 255 }, { 102, 203, 203, 255 }, { 102, 203, 152, 255 },
68  { 102, 203, 102, 255 }, { 102, 203,  51, 255 }, { 102, 203,   0, 255 },
69  {  51, 203, 255, 255 }, {  51, 203, 203, 255 }, {  51, 203, 152, 255 },
70  {  51, 203, 102, 255 }, {  51, 203,  51, 255 }, {  51, 203,   0, 255 },
71  { 255, 102, 255, 255 }, { 255, 102, 203, 255 }, { 255, 102, 152, 255 },
72  { 255, 102, 102, 255 }, { 255, 102,  51, 255 }, { 255, 102,   0, 255 },
73  {   0, 102, 152, 255 }, {   0, 102, 102, 255 }, { 203, 152, 255, 255 },
74  { 203, 152, 203, 255 }, { 203, 152, 152, 255 }, { 203, 152, 102, 255 },
75  { 203, 152,  51, 255 }, { 203, 152,   0, 255 }, { 152, 152, 255, 255 },
76  { 152, 152, 203, 255 }, { 152, 152, 152, 255 }, { 152, 152, 102, 255 },
77  { 152, 152,  51, 255 }, { 152, 152,   0, 255 }, { 102, 152, 255, 255 },
78  { 102, 152, 203, 255 }, { 102, 152, 152, 255 }, { 102, 152, 102, 255 },
79  { 102, 152,  51, 255 }, { 102, 152,   0, 255 }, {  51, 152, 255, 255 },
80  {  51, 152, 203, 255 }, {  51, 152, 152, 255 }, {  51, 152, 102, 255 },
81  {  51, 152,  51, 255 }, {  51, 152,   0, 255 }, { 230, 134,   0, 255 },
82  { 255,  51, 203, 255 }, { 255,  51, 152, 255 }, { 255,  51, 102, 255 },
83  { 255,  51,  51, 255 }, { 255,  51,   0, 255 }, {   0, 102,  51, 255 },
84  {   0, 102,   0, 255 }, { 203, 102, 255, 255 }, { 203, 102, 203, 255 },
85  { 203, 102, 152, 255 }, { 203, 102, 102, 255 }, { 203, 102,  51, 255 },
86  { 203, 102,   0, 255 }, { 152, 102, 255, 255 }, { 152, 102, 203, 255 },
87  { 152, 102, 152, 255 }, { 152, 102, 102, 255 }, { 152, 102,  51, 255 },
88  { 152, 102,   0, 255 }, { 102, 102, 255, 255 }, { 102, 102, 203, 255 },
89  { 102, 102, 152, 255 }, { 102, 102, 102, 255 }, { 102, 102,  51, 255 },
90  { 102, 102,   0, 255 }, {  51, 102, 255, 255 }, {  51, 102, 203, 255 },
91  {  51, 102, 152, 255 }, {  51, 102, 102, 255 }, {  51, 102,  51, 255 },
92  {  51, 102,   0, 255 }, { 255,   0, 255, 255 }, { 255,   0, 203, 255 },
93  { 255,   0, 152, 255 }, { 255,   0, 102, 255 }, { 255,   0,  51, 255 },
94  { 255, 175,  19, 255 }, {   0,  51, 255, 255 }, {   0,  51, 203, 255 },
95  { 203,  51, 255, 255 }, { 203,  51, 203, 255 }, { 203,  51, 152, 255 },
96  { 203,  51, 102, 255 }, { 203,  51,  51, 255 }, { 203,  51,   0, 255 },
97  { 152,  51, 255, 255 }, { 152,  51, 203, 255 }, { 152,  51, 152, 255 },
98  { 152,  51, 102, 255 }, { 152,  51,  51, 255 }, { 152,  51,   0, 255 },
99  { 102,  51, 255, 255 }, { 102,  51, 203, 255 }, { 102,  51, 152, 255 },
100  { 102,  51, 102, 255 }, { 102,  51,  51, 255 }, { 102,  51,   0, 255 },
101  {  51,  51, 255, 255 }, {  51,  51, 203, 255 }, {  51,  51, 152, 255 },
102  {  51,  51, 102, 255 }, {  51,  51,  51, 255 }, {  51,  51,   0, 255 },
103  { 255, 203, 102, 255 }, { 255, 203, 152, 255 }, { 255, 203, 203, 255 },
104  { 255, 203, 255, 255 }, {   0,  51, 152, 255 }, {   0,  51, 102, 255 },
105  {   0,  51,  51, 255 }, {   0,  51,   0, 255 }, { 203,   0, 255, 255 },
106  { 203,   0, 203, 255 }, { 203,   0, 152, 255 }, { 203,   0, 102, 255 },
107  { 203,   0,  51, 255 }, { 255, 227,  70, 255 }, { 152,   0, 255, 255 },
108  { 152,   0, 203, 255 }, { 152,   0, 152, 255 }, { 152,   0, 102, 255 },
109  { 152,   0,  51, 255 }, { 152,   0,   0, 255 }, { 102,   0, 255, 255 },
110  { 102,   0, 203, 255 }, { 102,   0, 152, 255 }, { 102,   0, 102, 255 },
111  { 102,   0,  51, 255 }, { 102,   0,   0, 255 }, {  51,   0, 255, 255 },
112  {  51,   0, 203, 255 }, {  51,   0, 152, 255 }, {  51,   0, 102, 255 },
113  {  51,   0,  51, 255 }, {  51,   0,   0, 255 }, { 255, 203,  51, 255 },
114  { 255, 203,   0, 255 }, { 255, 255,   0, 255 }, { 255, 255,  51, 255 },
115  { 255, 255, 102, 255 }, { 255, 255, 152, 255 }, { 255, 255, 203, 255 },
116  { 255, 255, 255, 0 } // B_TRANSPARENT_MAGIC_CMAP8
117 };
118 
119 
120 /*!	\brief Returns the brightness of an RGB 24 color.
121 	\param red Value of the red component.
122 	\param green Value of the green component.
123 	\param blue Value of the blue component.
124 	\return The brightness for the supplied RGB color as a value between 0
125 			and 255.
126 */
127 static inline
128 uint8
129 brightness_for(uint8 red, uint8 green, uint8 blue)
130 {
131 	// brightness = 0.301 * red + 0.586 * green + 0.113 * blue
132 	// we use for performance reasons:
133 	// brightness = (308 * red + 600 * green + 116 * blue) / 1024
134 	return uint8((308 * red + 600 * green + 116 * blue) / 1024);
135 }
136 
137 
138 /*!	\brief Returns the "distance" between two RGB colors.
139 
140 	This functions defines an metric on the RGB color space. The distance
141 	between two colors is 0, if and only if the colors are equal.
142 
143 	\param red1 Red component of the first color.
144 	\param green1 Green component of the first color.
145 	\param blue1 Blue component of the first color.
146 	\param red2 Red component of the second color.
147 	\param green2 Green component of the second color.
148 	\param blue2 Blue component of the second color.
149 	\return The distance between the given colors.
150 */
151 static inline
152 unsigned
153 color_distance(uint8 red1, uint8 green1, uint8 blue1,
154 			   uint8 red2, uint8 green2, uint8 blue2)
155 {
156 	// euklidian distance (its square actually)
157 	int rd = (int)red1 - (int)red2;
158 	int gd = (int)green1 - (int)green2;
159 	int bd = (int)blue1 - (int)blue2;
160 	//return rd * rd + gd * gd + bd * bd;
161 
162 	// distance according to psycho-visual tests
163 	int rmean = ((int)red1 + (int)red2) / 2;
164 	return (((512 + rmean) * rd * rd) >> 8)
165 		   + 4 * gd * gd
166 		   + (((767 - rmean) * bd * bd) >> 8);
167 }
168 
169 
170 /*!	\brief Creates an uninitialized PaletteConverter.
171 */
172 PaletteConverter::PaletteConverter()
173 	: fColorMap(NULL),
174 	  fOwnColorMap(NULL),
175 	  fCStatus(B_NO_INIT)
176 {
177 }
178 
179 
180 /*!	\brief Creates a PaletteConverter and initializes it to the supplied
181 		   palette.
182 	\param palette The palette being a 256 entry rgb_color array.
183 */
184 PaletteConverter::PaletteConverter(const rgb_color *palette)
185 	: fColorMap(NULL),
186 	  fOwnColorMap(NULL),
187 	  fCStatus(B_NO_INIT)
188 {
189 	SetTo(palette);
190 }
191 
192 
193 /*!	\brief Creates a PaletteConverter and initializes it to the supplied
194 		   color map.
195 	\param colorMap The completely initialized color map.
196 */
197 PaletteConverter::PaletteConverter(const color_map *colorMap)
198 	: fColorMap(NULL),
199 	  fOwnColorMap(NULL),
200 	  fCStatus(B_NO_INIT)
201 {
202 	SetTo(colorMap);
203 }
204 
205 
206 /*!	\brief Frees all resources associated with this object.
207 */
208 PaletteConverter::~PaletteConverter()
209 {
210 	delete fOwnColorMap;
211 }
212 
213 
214 /*!	\brief Initializes the converter to the supplied palette.
215 	\param palette The palette being a 256 entry rgb_color array.
216 	\return \c B_OK, if everything went fine, an error code otherwise.
217 */
218 status_t
219 PaletteConverter::SetTo(const rgb_color *palette)
220 {
221 	// cleanup
222 	SetTo((const color_map*)NULL);
223 	status_t error = (palette ? B_OK : B_BAD_VALUE);
224 	// alloc color map
225 	if (error == B_OK) {
226 		fOwnColorMap = new(nothrow) color_map;
227 		if (fOwnColorMap == NULL)
228 			error = B_NO_MEMORY;
229 	}
230 	// init color map
231 	if (error == B_OK) {
232 		fColorMap = fOwnColorMap;
233 		// init color list
234 		memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256);
235 		// init index map
236 // TODO: build this list takes about 2 seconds in qemu on my system
237 //		(because of color_distance())
238 		for (int32 color = 0; color < 32768; color++) {
239 			// get components
240 			uint8 red = (color & 0x7c00) >> 7;
241 			uint8 green = (color & 0x3e0) >> 2;
242 			uint8 blue = (color & 0x1f) << 3;
243 			red |= red >> 5;
244 			green |= green >> 5;
245 			blue |= blue >> 5;
246 			// find closest color
247 			uint8 closestIndex = 0;
248 			unsigned closestDistance = UINT_MAX;
249 			for (int32 i = 0; i < 256; i++) {
250 				const rgb_color &c = fOwnColorMap->color_list[i];
251 				unsigned distance = color_distance(red, green, blue,
252 												   c.red, c.green, c.blue);
253 				if (distance < closestDistance) {
254 					closestIndex = i;
255 					closestDistance = distance;
256 				}
257 			}
258 			fOwnColorMap->index_map[color] = closestIndex;
259 		}
260 		// no need to init inversion map
261 	}
262 	fCStatus = error;
263 	return error;
264 }
265 
266 
267 /*!	\brief Initializes the converter to the supplied color map.
268 	\param colorMap The completely initialized color map.
269 	\return \c B_OK, if everything went fine, an error code otherwise.
270 */
271 status_t
272 PaletteConverter::SetTo(const color_map *colorMap)
273 {
274 	// cleanup
275 	if (fOwnColorMap) {
276 		delete fOwnColorMap;
277 		fOwnColorMap = NULL;
278 	}
279 	// set
280 	fColorMap = colorMap;
281 	fCStatus = (fColorMap ? B_OK : B_BAD_VALUE);
282 	return fCStatus;
283 }
284 
285 
286 /*!	\brief Returns the result of the last initialization via constructor or
287 		   SetTo().
288 	\return \c B_OK, if the converter is properly initialized, an error code
289 			otherwise.
290 */
291 status_t
292 PaletteConverter::InitCheck() const
293 {
294 	return fCStatus;
295 }
296 
297 
298 /*!	\brief Returns the palette color index closest to a given RGB 15 color.
299 
300 	The object must be properly initialized.
301 
302 	\param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]).
303 	\return The palette color index for the supplied color.
304 */
305 inline
306 uint8
307 PaletteConverter::IndexForRGB15(uint16 rgb) const
308 {
309 	return fColorMap->index_map[rgb];
310 }
311 
312 
313 /*!	\brief Returns the palette color index closest to a given RGB 15 color.
314 
315 	The object must be properly initialized.
316 
317 	\param red Red component of the color (R[4:0]).
318 	\param green Green component of the color (G[4:0]).
319 	\param blue Blue component of the color (B[4:0]).
320 	\return The palette color index for the supplied color.
321 */
322 inline
323 uint8
324 PaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const
325 {
326 	// the 5 least significant bits are used
327 	return fColorMap->index_map[(red << 10) | (green << 5) | blue];
328 }
329 
330 
331 /*!	\brief Returns the palette color index closest to a given RGB 16 color.
332 
333 	The object must be properly initialized.
334 
335 	\param rgb The RGB 16 color value (R[15:11]G[10:5]B[4:0]).
336 	\return The palette color index for the supplied color.
337 */
338 inline
339 uint8
340 PaletteConverter::IndexForRGB16(uint16 rgb) const
341 {
342 	return fColorMap->index_map[(rgb >> 1) & 0x7fe0 | rgb & 0x1f];
343 }
344 
345 
346 /*!	\brief Returns the palette color index closest to a given RGB 16 color.
347 
348 	The object must be properly initialized.
349 
350 	\param red Red component of the color (R[4:0]).
351 	\param green Green component of the color (G[5:0]).
352 	\param blue Blue component of the color (B[4:0]).
353 	\return The palette color index for the supplied color.
354 */
355 inline
356 uint8
357 PaletteConverter::IndexForRGB16(uint8 red, uint8 green, uint8 blue) const
358 {
359 	// the 5 (for red, blue) / 6 (for green) least significant bits are used
360 	return fColorMap->index_map[(red << 10) | ((green & 0x3e) << 4) | blue];
361 }
362 
363 
364 /*!	\brief Returns the palette color index closest to a given RGB 32 color.
365 
366 	The object must be properly initialized.
367 
368 	\param rgb The RGB 32 color value (R[31:24]G[23:16]B[15:8]).
369 	\return The palette color index for the supplied color.
370 */
371 inline
372 uint8
373 PaletteConverter::IndexForRGB24(uint32 rgb) const
374 {
375 	return fColorMap->index_map[((rgb & 0xf8000000) >> 17)
376 								| ((rgb & 0xf80000) >> 14)
377 								| ((rgb & 0xf800) >> 11)];
378 }
379 
380 
381 /*!	\brief Returns the palette color index closest to a given RGB 24 color.
382 
383 	The object must be properly initialized.
384 
385 	\param red Red component of the color.
386 	\param green Green component of the color.
387 	\param blue Blue component of the color.
388 	\return The palette color index for the supplied color.
389 */
390 inline
391 uint8
392 PaletteConverter::IndexForRGB24(uint8 red, uint8 green, uint8 blue) const
393 {
394 	return fColorMap->index_map[((red & 0xf8) << 7)
395 								| ((green & 0xf8) << 2)
396 								| (blue >> 3)];
397 }
398 
399 
400 /*!	\brief Returns the palette color index closest to a given Gray 8 color.
401 
402 	The object must be properly initialized.
403 
404 	\param gray The Gray 8 color value.
405 	\return The palette color index for the supplied color.
406 */
407 inline
408 uint8
409 PaletteConverter::IndexForGray(uint8 gray) const
410 {
411 	return IndexForRGB24(gray, gray, gray);
412 }
413 
414 
415 /*!	\brief Returns the RGB color for a given palette color index.
416 
417 	The object must be properly initialized.
418 
419 	\param index The palette color index.
420 	\return The color for the supplied palette color index.
421 */
422 inline
423 const rgb_color &
424 PaletteConverter::RGBColorForIndex(uint8 index) const
425 {
426 	return fColorMap->color_list[index];
427 }
428 
429 
430 /*!	\brief Returns the RGB 15 color for a given palette color index.
431 
432 	The object must be properly initialized.
433 
434 	\param index The palette color index.
435 	\return The color for the supplied palette color index
436 			(R[14:10]G[9:5]B[4:0]).
437 */
438 inline
439 uint16
440 PaletteConverter::RGB15ColorForIndex(uint8 index) const
441 {
442 	const rgb_color &color = fColorMap->color_list[index];
443 	return ((color.red & 0xf8) << 7)
444 		   | ((color.green & 0xf8) << 2)
445 		   | (color.blue >> 3);
446 }
447 
448 
449 /*!	\brief Returns the RGB 16 color for a given palette color index.
450 
451 	The object must be properly initialized.
452 
453 	\param index The palette color index.
454 	\return The color for the supplied palette color index
455 			(R[15:11]G[10:5]B[4:0]).
456 */
457 inline
458 uint16
459 PaletteConverter::RGB16ColorForIndex(uint8 index) const
460 {
461 	const rgb_color &color = fColorMap->color_list[index];
462 	return ((color.red & 0xf8) << 8)
463 		   | ((color.green & 0xfc) << 3)
464 		   | (color.blue >> 3);
465 }
466 
467 
468 /*!	\brief Returns the RGBA 32 color for a given palette color index.
469 
470 	The object must be properly initialized.
471 
472 	\param index The palette color index.
473 	\return The color for the supplied palette color index
474 			(A[31:24]B[23:16]G[15:8]R[7:0]).
475 */
476 inline
477 uint32
478 PaletteConverter::RGBA32ColorForIndex(uint8 index) const
479 {
480 	const rgb_color &color = fColorMap->color_list[index];
481 	return (color.red << 16) | (color.green << 8) | color.blue
482 		| (color.alpha << 24);
483 }
484 
485 
486 /*!	\brief Returns the RGBA 32 color for a given palette color index.
487 
488 	The object must be properly initialized.
489 
490 	\param index The palette color index.
491 	\param red Reference to the variable the red component shall be stored
492 		   into.
493 	\param green Reference to the variable the green component shall be stored
494 		   into.
495 	\param blue Reference to the variable the blue component shall be stored
496 		   into.
497 	\param alpha Reference to the variable the alpha component shall be stored
498 		   into.
499 */
500 inline
501 void
502 PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green,
503 									 uint8 &blue, uint8 &alpha) const
504 {
505 	const rgb_color &color = fColorMap->color_list[index];
506 	red = color.red;
507 	green = color.green;
508 	blue = color.blue;
509 	alpha = color.alpha;
510 }
511 
512 
513 /*!	\brief Returns the Gray 8 color for a given palette color index.
514 
515 	The object must be properly initialized.
516 
517 	\param index The palette color index.
518 	\return The color for the supplied palette color index.
519 */
520 inline
521 uint8
522 PaletteConverter::GrayColorForIndex(uint8 index) const
523 {
524 	const rgb_color &color = fColorMap->color_list[index];
525 	return brightness_for(color.red, color.green, color.blue);
526 }
527 
528 
529 // TODO: Remove these and palette_converter() when BScreen is available.
530 static BLocker			gPaletteConverterLock("PalConvLock");
531 static PaletteConverter	gPaletteConverter;
532 
533 
534 /*!	\brief Returns a PaletteConverter using the system color palette.
535 	\return A PaletteConverter.
536 */
537 static
538 const PaletteConverter*
539 palette_converter()
540 {
541 	if (gPaletteConverterLock.Lock()) {
542 		if (gPaletteConverter.InitCheck() != B_OK)
543 			gPaletteConverter.SetTo(kSystemPalette);
544 		gPaletteConverterLock.Unlock();
545 	}
546 	return &gPaletteConverter;
547 }
548 
549 
550 typedef uint32 (readFunc)(const uint8 **source, int32 index);
551 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
552 
553 
554 void
555 WriteRGB24(uint8 **dest, uint8 *data, int32 index)
556 {
557 	(*dest)[0] = data[0];
558 	(*dest)[1] = data[1];
559 	(*dest)[2] = data[2];
560 	*dest += 3;
561 }
562 
563 
564 uint32
565 ReadRGB24(const uint8 **source, int32 index)
566 {
567 	uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16);
568 	*source += 3;
569 	return result;
570 }
571 
572 
573 void
574 WriteGray8(uint8 **dest, uint8 *data, int32 index)
575 {
576 	**dest = data[2] * 308 + data[1] * 600 + data[0] * 116 >> 10;
577 	// this would boost the speed but is less accurate:
578 	//*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10;
579 	(*dest)++;
580 }
581 
582 
583 uint32
584 ReadGray8(const uint8 **source, int32 index)
585 {
586 	uint32 result = **source;
587 	(*source)++;
588 	return result;
589 }
590 
591 
592 void
593 WriteGray1(uint8 **dest, uint8 *data, int32 index)
594 {
595 	int32 shift = 7 - (index % 8);
596 	**dest &= ~(0x01 << shift);
597 	**dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift);
598 	if (shift == 0)
599 		(*dest)++;
600 }
601 
602 
603 uint32
604 ReadGray1(const uint8 **source, int32 index)
605 {
606 	int32 shift = 7 - (index % 8);
607 	uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00;
608 	if (shift == 0)
609 		(*source)++;
610 	return result;
611 }
612 
613 
614 void
615 WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
616 {
617 	**dest = gPaletteConverter.IndexForRGB15(*(uint16 *)data);
618 	(*dest)++;
619 }
620 
621 
622 uint32
623 ReadCMAP8(const uint8 **source, int32 index)
624 {
625 	uint32 result = gPaletteConverter.RGBA32ColorForIndex(**source);
626 	(*source)++;
627 	return result;
628 }
629 
630 
631 template<typename srcByte, typename dstByte>
632 status_t
633 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
634 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
635 	int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
636 	uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
637 	int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
638 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
639 	BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
640 	readFunc *srcFunc, writeFunc *dstFunc)
641 {
642 	uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
643 	uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
644 
645 	int32 srcBitsPerRow = srcBytesPerRow << 3;
646 	int32 dstBitsPerRow = dstBytesPerRow << 3;
647 
648 	// Advance the buffers to reach their offsets
649 	int32 srcOffsetX = (int32)srcOffset.x;
650 	int32 dstOffsetX = (int32)dstOffset.x;
651 	int32 srcOffsetY = (int32)srcOffset.y;
652 	int32 dstOffsetY = (int32)dstOffset.y;
653 	if (srcOffsetX < 0) {
654 		dstOffsetX -= srcOffsetX;
655 		srcOffsetX = 0;
656 	}
657 	if (srcOffsetY < 0) {
658 		dstOffsetY -= srcOffsetY;
659 		height += srcOffsetY;
660 		srcOffsetY = 0;
661 	}
662 	if (dstOffsetX < 0) {
663 		srcOffsetX -= dstOffsetX;
664 		dstOffsetX = 0;
665 	}
666 	if (dstOffsetY < 0) {
667 		srcOffsetY -= dstOffsetY;
668 		height += dstOffsetY;
669 		dstOffsetY = 0;
670 	}
671 
672 	srcBits = (srcByte*)((uint8*)srcBits + (srcOffsetY * srcBitsPerRow + srcOffsetX
673 		* srcBitsPerPixel >> 3));
674 	dstBits = (dstByte*)((uint8*)dstBits + (dstOffsetY * dstBitsPerRow + dstOffsetX
675 		* dstBitsPerPixel >> 3));
676 
677 	// Ensure that the width fits
678 	int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
679 		/ srcBitsPerPixel;
680 	if (srcWidth < width)
681 		width = srcWidth;
682 
683 	int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
684 		/ dstBitsPerPixel;
685 	if (dstWidth < width)
686 		width = dstWidth;
687 
688 	if (width < 0)
689 		return B_OK;
690 
691 	// Catch the copy case
692 	if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) {
693 		int32 copyCount = (width * srcBitsPerPixel) >> 3;
694 		for (int32 i = 0; i < height; i++) {
695 			// make sure we don't write beyond the bits size
696 			if (copyCount > srcBitsLength)
697 				copyCount = srcBitsLength;
698 			if (copyCount > dstBitsLength)
699 				copyCount = dstBitsLength;
700 			if (copyCount == 0)
701 				break;
702 
703 			memcpy(dstBits, srcBits, copyCount);
704 
705 			srcBitsLength -= copyCount;
706 			dstBitsLength -= copyCount;
707 			srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow);
708 			dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow);
709 
710 			if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd)
711 				return B_OK;
712 		}
713 
714 		return B_OK;
715 	}
716 
717 	int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3;
718 	int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3;
719 	uint32 result;
720 	uint32 source;
721 
722 	for (int32 i = 0; i < height; i++) {
723 		for (int32 j = 0; j < width; j++) {
724 			if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
725 				|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
726 				return B_OK;
727 
728 			if (srcFunc)
729 				source = srcFunc((const uint8 **)&srcBits, srcOffsetX++);
730 			else {
731 				source = *srcBits;
732 				srcBits++;
733 			}
734 
735 			// This is valid, as only 16 bit modes will need to swap
736 			if (srcSwap)
737 				source = (source << 8) | (source >> 8);
738 
739 			if (redShift > 0)
740 				result = ((source >> redShift) & redMask);
741 			else if (redShift < 0)
742 				result = ((source << -redShift) & redMask);
743 			else
744 				result = source & redMask;
745 
746 			if (greenShift > 0)
747 				result |= ((source >> greenShift) & greenMask);
748 			else if (greenShift < 0)
749 				result |= ((source << -greenShift) & greenMask);
750 			else
751 				result |= source & greenMask;
752 
753 			if (blueShift > 0)
754 				result |= ((source >> blueShift) & blueMask);
755 			else if (blueShift < 0)
756 				result |= ((source << -blueShift) & blueMask);
757 			else
758 				result |= source & blueMask;
759 
760 			if (alphaBits > 0) {
761 				if (alphaShift > 0)
762 					result |= ((source >> alphaShift) & alphaMask);
763 				else if (alphaShift < 0)
764 					result |= ((source << -alphaShift) & alphaMask);
765 				else
766 					result |= source & alphaMask;
767 
768 				// if we only had one alpha bit we want it to be 0/255
769 				if (alphaBits == 1 && result & alphaMask)
770 					result |= alphaMask;
771 			} else
772 				result |= alphaMask;
773 
774 			// This is valid, as only 16 bit modes will need to swap
775 			if (dstSwap)
776 				result = (result << 8) | (result >> 8);
777 
778 			if (dstFunc)
779 				dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
780 			else {
781 				*dstBits = result;
782 				dstBits++;
783 			}
784 		}
785 
786 		srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
787 		dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
788 		dstOffsetX -= width;
789 		srcOffsetX -= width;
790 	}
791 
792 	return B_OK;
793 }
794 
795 
796 template<typename srcByte>
797 status_t
798 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
799 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
800 	int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
801 	int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
802 	color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
803 	int32 height, bool srcSwap,	readFunc *srcFunc)
804 {
805 	switch (dstColorSpace) {
806 		case B_RGBA32:
807 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
808 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
809 				alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
810 				0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
811 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
812 				height, srcSwap, false, srcFunc, NULL);
813 			break;
814 
815 		case B_RGBA32_BIG:
816 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
817 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
818 				alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
819 				0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
820 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
821 				height, srcSwap, false, srcFunc, NULL);
822 			break;
823 
824 		/* Note:	we set the unused alpha to 255 here. This is because BeOS
825 					uses the unused alpha for B_OP_ALPHA even though it should
826 					not care about it. */
827 		case B_RGB32:
828 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
829 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
830 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
831 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
832 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
833 				height, srcSwap, false, srcFunc, NULL);
834 			break;
835 
836 		case B_RGB32_BIG:
837 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
838 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
839 				0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
840 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
841 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
842 				height, srcSwap, false, srcFunc, NULL);
843 			break;
844 
845 		case B_RGB24:
846 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
847 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
848 				0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow,
849 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
850 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
851 				false, srcFunc, WriteRGB24);
852 			break;
853 
854 		case B_RGB24_BIG:
855 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
856 				dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24,
857 				0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow,
858 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
859 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
860 				false, srcFunc, WriteRGB24);
861 			break;
862 
863 		case B_RGB16:
864 		case B_RGB16_BIG:
865 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
866 				dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5,
867 				0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow,
868 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
869 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
870 				dstColorSpace == B_RGB16_BIG, srcFunc, NULL);
871 			break;
872 
873 		case B_RGBA15:
874 		case B_RGBA15_BIG:
875 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
876 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
877 				alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000,
878 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16,
879 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
880 				height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL);
881 			break;
882 
883 		case B_RGB15:
884 		case B_RGB15_BIG:
885 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
886 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
887 				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
888 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
889 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
890 				dstColorSpace == B_RGB15_BIG, srcFunc, NULL);
891 			break;
892 
893 		case B_GRAY8:
894 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
895 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
896 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
897 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
898 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
899 				height, srcSwap, false, srcFunc, WriteGray8);
900 			break;
901 
902 		case B_GRAY1:
903 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
904 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
905 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
906 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1,
907 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
908 				height, srcSwap, false, srcFunc, WriteGray1);
909 			break;
910 
911 		case B_CMAP8:
912 			BPrivate::palette_converter();
913 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
914 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
915 				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
916 				dstBytesPerRow, srcBitsPerPixel, 8, srcColorSpace,
917 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
918 				false, srcFunc, WriteCMAP8);
919 			break;
920 
921 		default:
922 			return B_BAD_VALUE;
923 			break;
924 	}
925 
926 	return B_OK;
927 }
928 
929 
930 /*!	\brief Converts a source buffer in one colorspace into a destination
931 		   buffer of another colorspace.
932 
933 	\param srcBits The raw source buffer.
934 	\param dstBits The raw destination buffer.
935 	\param srcBytesPerRow How many bytes per row the source buffer has got.
936 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
937 	\param srcColorSpace The colorspace the source buffer is in.
938 	\param dstColorSpace The colorspace the buffer shall be converted to.
939 	\param width The width (in pixels) of each row.
940 	\param height The height (in pixels) of the buffers.
941 	\return
942 	- \c B_OK: Indicates success.
943 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
944 */
945 status_t
946 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
947 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
948 	color_space srcColorSpace, color_space dstColorSpace, int32 width,
949 	int32 height)
950 {
951 	return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength,
952 		srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace,
953 		BPoint(0, 0), BPoint(0, 0), width, height);
954 }
955 
956 
957 /*!	\brief Converts a source buffer in one colorspace into a destination
958 		   buffer of another colorspace.
959 
960 	\param srcBits The raw source buffer.
961 	\param dstBits The raw destination buffer.
962 	\param srcBytesPerRow How many bytes per row the source buffer has got.
963 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
964 	\param srcColorSpace The colorspace the source buffer is in.
965 	\param dstColorSpace The colorspace the buffer shall be converted to.
966 	\param srcOffset The offset at which to start reading in the source.
967 	\param srcOffset The offset at which to start writing in the destination.
968 	\param width The width (in pixels) to convert.
969 	\param height The height (in pixels) to convert.
970 	\return
971 	- \c B_OK: Indicates success.
972 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
973 */
974 status_t
975 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
976 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
977 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
978 	BPoint dstOffset, int32 width, int32 height)
979 {
980 	if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0
981 		|| width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0)
982 		return B_BAD_VALUE;
983 
984 	switch (srcColorSpace) {
985 		case B_RGBA32:
986 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
987 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
988 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
989 				dstOffset, width, height, false, NULL);
990 			break;
991 
992 		case B_RGBA32_BIG:
993 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
994 				dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow,
995 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
996 				dstOffset, width, height, false, NULL);
997 			break;
998 
999 		case B_RGB32:
1000 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1001 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1002 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1003 				height, false, NULL);
1004 			break;
1005 
1006 		case B_RGB32_BIG:
1007 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1008 				dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow,
1009 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
1010 				dstOffset, width, height, false, NULL);
1011 			break;
1012 
1013 		case B_RGB24:
1014 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1015 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1016 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1017 				height, false, ReadRGB24);
1018 			break;
1019 
1020 		case B_RGB24_BIG:
1021 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1022 				dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow,
1023 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1024 				height, false, ReadRGB24);
1025 			break;
1026 
1027 		case B_RGB16:
1028 		case B_RGB16_BIG:
1029 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1030 				dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
1031 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1032 				height, srcColorSpace == B_RGB16_BIG, NULL);
1033 			break;
1034 
1035 		case B_RGBA15:
1036 		case B_RGBA15_BIG:
1037 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1038 				dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow,
1039 				dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset,
1040 				dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL);
1041 			break;
1042 
1043 		case B_RGB15:
1044 		case B_RGB15_BIG:
1045 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1046 				dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
1047 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1048 				height, srcColorSpace == B_RGB15_BIG, NULL);
1049 			break;
1050 
1051 		case B_GRAY8:
1052 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1053 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1054 				8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1055 				height, false, ReadGray8);
1056 			break;
1057 
1058 		case B_GRAY1:
1059 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1060 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1061 				1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1062 				height, false, ReadGray1);
1063 			break;
1064 
1065 		case B_CMAP8:
1066 			palette_converter();
1067 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1068 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
1069 				dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset,
1070 				dstOffset, width, height, false, ReadCMAP8);
1071 			break;
1072 
1073 		default:
1074 			return B_BAD_VALUE;
1075 			break;
1076 	}
1077 
1078 	return B_OK;
1079 }
1080 
1081 } // namespace BPrivate
1082