xref: /haiku/src/kits/interface/ColorConversion.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT;
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*/ status_t
448 PaletteConverter::InitializeDefault(bool useServer)
449 {
450 	if (sPaletteConverter.InitCheck() != B_OK) {
451 		pthread_once(&sPaletteConverterInitOnce,
452 			useServer
453 				? &_InitializeDefaultAppServer
454 				: &_InitializeDefaultNoAppServer);
455 	}
456 
457 	return sPaletteConverter.InitCheck();
458 }
459 
460 
461 /*static*/ void
462 PaletteConverter::_InitializeDefaultAppServer()
463 {
464 	sPaletteConverter.SetTo(system_colors());
465 }
466 
467 
468 /*static*/ void
469 PaletteConverter::_InitializeDefaultNoAppServer()
470 {
471 	sPaletteConverter.SetTo(kSystemPalette);
472 }
473 
474 
475 typedef uint32 (readFunc)(const uint8 **source, int32 index);
476 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
477 
478 
479 void
480 WriteRGB24(uint8 **dest, uint8 *data, int32 index)
481 {
482 	(*dest)[0] = data[0];
483 	(*dest)[1] = data[1];
484 	(*dest)[2] = data[2];
485 	*dest += 3;
486 }
487 
488 
489 uint32
490 ReadRGB24(const uint8 **source, int32 index)
491 {
492 	uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16);
493 	*source += 3;
494 	return result;
495 }
496 
497 
498 void
499 WriteGray8(uint8 **dest, uint8 *data, int32 index)
500 {
501 	**dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10;
502 	// this would boost the speed but is less accurate:
503 	//*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10;
504 	(*dest)++;
505 }
506 
507 
508 uint32
509 ReadGray8(const uint8 **source, int32 index)
510 {
511 	uint32 result = **source;
512 	(*source)++;
513 	return result;
514 }
515 
516 
517 void
518 WriteGray1(uint8 **dest, uint8 *data, int32 index)
519 {
520 	int32 shift = 7 - (index % 8);
521 	**dest &= ~(0x01 << shift);
522 	**dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift);
523 	if (shift == 0)
524 		(*dest)++;
525 }
526 
527 
528 uint32
529 ReadGray1(const uint8 **source, int32 index)
530 {
531 	int32 shift = 7 - (index % 8);
532 	uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00;
533 	if (shift == 0)
534 		(*source)++;
535 	return result;
536 }
537 
538 
539 void
540 WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
541 {
542 	**dest = sPaletteConverter.IndexForRGB15(*(uint16 *)data);
543 	(*dest)++;
544 }
545 
546 
547 uint32
548 ReadCMAP8(const uint8 **source, int32 index)
549 {
550 	uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source);
551 	(*source)++;
552 	return result;
553 }
554 
555 
556 template<typename srcByte, typename dstByte>
557 status_t
558 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
559 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
560 	int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
561 	uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
562 	int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
563 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
564 	BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
565 	readFunc *srcFunc, writeFunc *dstFunc)
566 {
567 	uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
568 	uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
569 
570 	int32 srcBitsPerRow = srcBytesPerRow << 3;
571 	int32 dstBitsPerRow = dstBytesPerRow << 3;
572 
573 	// Advance the buffers to reach their offsets
574 	int32 srcOffsetX = (int32)srcOffset.x;
575 	int32 dstOffsetX = (int32)dstOffset.x;
576 	int32 srcOffsetY = (int32)srcOffset.y;
577 	int32 dstOffsetY = (int32)dstOffset.y;
578 	if (srcOffsetX < 0) {
579 		dstOffsetX -= srcOffsetX;
580 		srcOffsetX = 0;
581 	}
582 	if (srcOffsetY < 0) {
583 		dstOffsetY -= srcOffsetY;
584 		height += srcOffsetY;
585 		srcOffsetY = 0;
586 	}
587 	if (dstOffsetX < 0) {
588 		srcOffsetX -= dstOffsetX;
589 		dstOffsetX = 0;
590 	}
591 	if (dstOffsetY < 0) {
592 		srcOffsetY -= dstOffsetY;
593 		height += dstOffsetY;
594 		dstOffsetY = 0;
595 	}
596 
597 	srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX
598 		* srcBitsPerPixel) >> 3));
599 	dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX
600 		* dstBitsPerPixel) >> 3));
601 
602 	// Ensure that the width fits
603 	int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
604 		/ srcBitsPerPixel;
605 	if (srcWidth < width)
606 		width = srcWidth;
607 
608 	int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
609 		/ dstBitsPerPixel;
610 	if (dstWidth < width)
611 		width = dstWidth;
612 
613 	if (width < 0)
614 		return B_OK;
615 
616 	// Catch the copy case
617 	if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) {
618 		int32 copyCount = (width * srcBitsPerPixel) >> 3;
619 		for (int32 i = 0; i < height; i++) {
620 			// make sure we don't write beyond the bits size
621 			if (copyCount > srcBitsLength)
622 				copyCount = srcBitsLength;
623 			if (copyCount > dstBitsLength)
624 				copyCount = dstBitsLength;
625 			if (copyCount == 0)
626 				break;
627 
628 			memcpy(dstBits, srcBits, copyCount);
629 
630 			srcBitsLength -= copyCount;
631 			dstBitsLength -= copyCount;
632 			srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow);
633 			dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow);
634 
635 			if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd)
636 				return B_OK;
637 		}
638 
639 		return B_OK;
640 	}
641 
642 	int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3;
643 	int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3;
644 	uint32 result;
645 	uint32 source;
646 
647 	for (int32 i = 0; i < height; i++) {
648 		for (int32 j = 0; j < width; j++) {
649 			if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
650 				|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
651 				return B_OK;
652 
653 			if (srcFunc)
654 				source = srcFunc((const uint8 **)&srcBits, srcOffsetX++);
655 			else {
656 				source = *srcBits;
657 				srcBits++;
658 			}
659 
660 			// This is valid, as only 16 bit modes will need to swap
661 			if (srcSwap)
662 				source = (source << 8) | (source >> 8);
663 
664 			if (redShift > 0)
665 				result = ((source >> redShift) & redMask);
666 			else if (redShift < 0)
667 				result = ((source << -redShift) & redMask);
668 			else
669 				result = source & redMask;
670 
671 			if (greenShift > 0)
672 				result |= ((source >> greenShift) & greenMask);
673 			else if (greenShift < 0)
674 				result |= ((source << -greenShift) & greenMask);
675 			else
676 				result |= source & greenMask;
677 
678 			if (blueShift > 0)
679 				result |= ((source >> blueShift) & blueMask);
680 			else if (blueShift < 0)
681 				result |= ((source << -blueShift) & blueMask);
682 			else
683 				result |= source & blueMask;
684 
685 			if (alphaBits > 0) {
686 				if (alphaShift > 0)
687 					result |= ((source >> alphaShift) & alphaMask);
688 				else if (alphaShift < 0)
689 					result |= ((source << -alphaShift) & alphaMask);
690 				else
691 					result |= source & alphaMask;
692 
693 				// if we only had one alpha bit we want it to be 0/255
694 				if (alphaBits == 1 && result & alphaMask)
695 					result |= alphaMask;
696 			} else
697 				result |= alphaMask;
698 
699 			// This is valid, as only 16 bit modes will need to swap
700 			if (dstSwap)
701 				result = (result << 8) | (result >> 8);
702 
703 			if (dstFunc)
704 				dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
705 			else {
706 				*dstBits = result;
707 				dstBits++;
708 			}
709 		}
710 
711 		srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
712 		dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
713 		dstOffsetX -= width;
714 		srcOffsetX -= width;
715 	}
716 
717 	return B_OK;
718 }
719 
720 
721 template<typename srcByte>
722 status_t
723 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
724 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
725 	int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
726 	int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
727 	color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
728 	int32 height, bool srcSwap,	readFunc *srcFunc)
729 {
730 	switch (dstColorSpace) {
731 		case B_RGBA32:
732 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
733 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
734 				alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
735 				0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
736 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
737 				height, srcSwap, false, srcFunc, NULL);
738 			break;
739 
740 		case B_RGBA32_BIG:
741 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
742 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
743 				alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
744 				0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
745 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
746 				height, srcSwap, false, srcFunc, NULL);
747 			break;
748 
749 		/* Note:	we set the unused alpha to 255 here. This is because BeOS
750 					uses the unused alpha for B_OP_ALPHA even though it should
751 					not care about it. */
752 		case B_RGB32:
753 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
754 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
755 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
756 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
757 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
758 				height, srcSwap, false, srcFunc, NULL);
759 			break;
760 
761 		case B_RGB32_BIG:
762 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
763 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
764 				0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
765 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
766 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
767 				height, srcSwap, false, srcFunc, NULL);
768 			break;
769 
770 		case B_RGB24:
771 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
772 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
773 				0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow,
774 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
775 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
776 				false, srcFunc, WriteRGB24);
777 			break;
778 
779 		case B_RGB24_BIG:
780 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
781 				dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24,
782 				0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow,
783 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
784 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
785 				false, srcFunc, WriteRGB24);
786 			break;
787 
788 		case B_RGB16:
789 		case B_RGB16_BIG:
790 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
791 				dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5,
792 				0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow,
793 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
794 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
795 				dstColorSpace == B_RGB16_BIG, srcFunc, NULL);
796 			break;
797 
798 		case B_RGBA15:
799 		case B_RGBA15_BIG:
800 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
801 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
802 				alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000,
803 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16,
804 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
805 				height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL);
806 			break;
807 
808 		case B_RGB15:
809 		case B_RGB15_BIG:
810 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
811 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
812 				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
813 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
814 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
815 				dstColorSpace == B_RGB15_BIG, srcFunc, NULL);
816 			break;
817 
818 		case B_GRAY8:
819 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
820 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
821 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
822 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
823 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
824 				height, srcSwap, false, srcFunc, WriteGray8);
825 			break;
826 
827 		case B_GRAY1:
828 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
829 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
830 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
831 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1,
832 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
833 				height, srcSwap, false, srcFunc, WriteGray1);
834 			break;
835 
836 		case B_CMAP8:
837 			PaletteConverter::InitializeDefault();
838 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
839 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
840 				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
841 				dstBytesPerRow, srcBitsPerPixel, 8, srcColorSpace,
842 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
843 				false, srcFunc, WriteCMAP8);
844 			break;
845 
846 		default:
847 			return B_BAD_VALUE;
848 			break;
849 	}
850 
851 	return B_OK;
852 }
853 
854 
855 /*!	\brief Converts a source buffer in one colorspace into a destination
856 		   buffer of another colorspace.
857 
858 	\param srcBits The raw source buffer.
859 	\param dstBits The raw destination buffer.
860 	\param srcBytesPerRow How many bytes per row the source buffer has got.
861 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
862 	\param srcColorSpace The colorspace the source buffer is in.
863 	\param dstColorSpace The colorspace the buffer shall be converted to.
864 	\param width The width (in pixels) of each row.
865 	\param height The height (in pixels) of the buffers.
866 	\return
867 	- \c B_OK: Indicates success.
868 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
869 */
870 status_t
871 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
872 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
873 	color_space srcColorSpace, color_space dstColorSpace, int32 width,
874 	int32 height)
875 {
876 	return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength,
877 		srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace,
878 		BPoint(0, 0), BPoint(0, 0), width, height);
879 }
880 
881 
882 /*!	\brief Converts a source buffer in one colorspace into a destination
883 		   buffer of another colorspace.
884 
885 	\param srcBits The raw source buffer.
886 	\param dstBits The raw destination buffer.
887 	\param srcBytesPerRow How many bytes per row the source buffer has got.
888 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
889 	\param srcColorSpace The colorspace the source buffer is in.
890 	\param dstColorSpace The colorspace the buffer shall be converted to.
891 	\param srcOffset The offset at which to start reading in the source.
892 	\param srcOffset The offset at which to start writing in the destination.
893 	\param width The width (in pixels) to convert.
894 	\param height The height (in pixels) to convert.
895 	\return
896 	- \c B_OK: Indicates success.
897 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
898 */
899 status_t
900 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
901 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
902 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
903 	BPoint dstOffset, int32 width, int32 height)
904 {
905 	if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0
906 		|| width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0)
907 		return B_BAD_VALUE;
908 
909 	switch (srcColorSpace) {
910 		case B_RGBA32:
911 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
912 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
913 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
914 				dstOffset, width, height, false, NULL);
915 			break;
916 
917 		case B_RGBA32_BIG:
918 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
919 				dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow,
920 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
921 				dstOffset, width, height, false, NULL);
922 			break;
923 
924 		case B_RGB32:
925 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
926 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
927 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
928 				height, false, NULL);
929 			break;
930 
931 		case B_RGB32_BIG:
932 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
933 				dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow,
934 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
935 				dstOffset, width, height, false, NULL);
936 			break;
937 
938 		case B_RGB24:
939 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
940 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
941 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
942 				height, false, ReadRGB24);
943 			break;
944 
945 		case B_RGB24_BIG:
946 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
947 				dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow,
948 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
949 				height, false, ReadRGB24);
950 			break;
951 
952 		case B_RGB16:
953 		case B_RGB16_BIG:
954 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
955 				dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
956 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
957 				height, srcColorSpace == B_RGB16_BIG, NULL);
958 			break;
959 
960 		case B_RGBA15:
961 		case B_RGBA15_BIG:
962 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
963 				dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow,
964 				dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset,
965 				dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL);
966 			break;
967 
968 		case B_RGB15:
969 		case B_RGB15_BIG:
970 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
971 				dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
972 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
973 				height, srcColorSpace == B_RGB15_BIG, NULL);
974 			break;
975 
976 		case B_GRAY8:
977 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
978 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
979 				8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
980 				height, false, ReadGray8);
981 			break;
982 
983 		case B_GRAY1:
984 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
985 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
986 				1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
987 				height, false, ReadGray1);
988 			break;
989 
990 		case B_CMAP8:
991 			PaletteConverter::InitializeDefault();
992 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
993 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
994 				dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset,
995 				dstOffset, width, height, false, ReadCMAP8);
996 			break;
997 
998 		default:
999 			return B_BAD_VALUE;
1000 			break;
1001 	}
1002 
1003 	return B_OK;
1004 }
1005 
1006 } // namespace BPrivate
1007