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