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