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