xref: /haiku/src/kits/interface/ColorConversion.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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 RGBA 32 color.
312 
313 	The object must be properly initialized.
314 
315 	\param rgb The RGB 32A color value (R[31:24]G[23:16]B[15:8]A[7:0]).
316 	\return The palette color index for the supplied color.
317 */
318 inline
319 uint8
320 PaletteConverter::IndexForRGBA32(uint32 rgba) const
321 {
322 	if ((rgba & 0x000000ff) < 128)
323 		return B_TRANSPARENT_MAGIC_CMAP8;
324 	return IndexForRGB24(rgba);
325 }
326 
327 
328 /*!	\brief Returns the palette color index closest to a given Gray 8 color.
329 
330 	The object must be properly initialized.
331 
332 	\param gray The Gray 8 color value.
333 	\return The palette color index for the supplied color.
334 */
335 inline
336 uint8
337 PaletteConverter::IndexForGray(uint8 gray) const
338 {
339 	return IndexForRGB24(gray, gray, gray);
340 }
341 
342 
343 /*!	\brief Returns the RGB color for a given palette color index.
344 
345 	The object must be properly initialized.
346 
347 	\param index The palette color index.
348 	\return The color for the supplied palette color index.
349 */
350 inline
351 const rgb_color &
352 PaletteConverter::RGBColorForIndex(uint8 index) const
353 {
354 	return fColorMap->color_list[index];
355 }
356 
357 
358 /*!	\brief Returns the RGB 15 color for a given palette color index.
359 
360 	The object must be properly initialized.
361 
362 	\param index The palette color index.
363 	\return The color for the supplied palette color index
364 			(R[14:10]G[9:5]B[4:0]).
365 */
366 inline
367 uint16
368 PaletteConverter::RGB15ColorForIndex(uint8 index) const
369 {
370 	const rgb_color &color = fColorMap->color_list[index];
371 	return ((color.red & 0xf8) << 7)
372 		   | ((color.green & 0xf8) << 2)
373 		   | (color.blue >> 3);
374 }
375 
376 
377 /*!	\brief Returns the RGB 16 color for a given palette color index.
378 
379 	The object must be properly initialized.
380 
381 	\param index The palette color index.
382 	\return The color for the supplied palette color index
383 			(R[15:11]G[10:5]B[4:0]).
384 */
385 inline
386 uint16
387 PaletteConverter::RGB16ColorForIndex(uint8 index) const
388 {
389 	const rgb_color &color = fColorMap->color_list[index];
390 	return ((color.red & 0xf8) << 8)
391 		   | ((color.green & 0xfc) << 3)
392 		   | (color.blue >> 3);
393 }
394 
395 
396 /*!	\brief Returns the RGBA 32 color for a given palette color index.
397 
398 	The object must be properly initialized.
399 
400 	\param index The palette color index.
401 	\return The color for the supplied palette color index
402 			(A[31:24]B[23:16]G[15:8]R[7:0]).
403 */
404 inline
405 uint32
406 PaletteConverter::RGBA32ColorForIndex(uint8 index) const
407 {
408 	const rgb_color &color = fColorMap->color_list[index];
409 	return (color.red << 16) | (color.green << 8) | color.blue
410 		| (color.alpha << 24);
411 }
412 
413 
414 /*!	\brief Returns the RGBA 32 color for a given palette color index.
415 
416 	The object must be properly initialized.
417 
418 	\param index The palette color index.
419 	\param red Reference to the variable the red component shall be stored
420 		   into.
421 	\param green Reference to the variable the green component shall be stored
422 		   into.
423 	\param blue Reference to the variable the blue component shall be stored
424 		   into.
425 	\param alpha Reference to the variable the alpha component shall be stored
426 		   into.
427 */
428 inline
429 void
430 PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green,
431 									 uint8 &blue, uint8 &alpha) const
432 {
433 	const rgb_color &color = fColorMap->color_list[index];
434 	red = color.red;
435 	green = color.green;
436 	blue = color.blue;
437 	alpha = color.alpha;
438 }
439 
440 
441 /*!	\brief Returns the Gray 8 color for a given palette color index.
442 
443 	The object must be properly initialized.
444 
445 	\param index The palette color index.
446 	\return The color for the supplied palette color index.
447 */
448 inline
449 uint8
450 PaletteConverter::GrayColorForIndex(uint8 index) const
451 {
452 	const rgb_color &color = fColorMap->color_list[index];
453 	return brightness_for(color.red, color.green, color.blue);
454 }
455 
456 
457 static pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT;
458 static PaletteConverter	sPaletteConverter;
459 
460 
461 /*!	\brief Initialize the global instance of PaletteConverter using the system color palette.
462 	\return B_OK.
463 */
464 /*static*/ status_t
465 PaletteConverter::InitializeDefault(bool useServer)
466 {
467 	if (sPaletteConverter.InitCheck() != B_OK) {
468 		pthread_once(&sPaletteConverterInitOnce,
469 			useServer
470 				? &_InitializeDefaultAppServer
471 				: &_InitializeDefaultNoAppServer);
472 	}
473 
474 	return sPaletteConverter.InitCheck();
475 }
476 
477 
478 /*static*/ void
479 PaletteConverter::_InitializeDefaultAppServer()
480 {
481 	sPaletteConverter.SetTo(system_colors());
482 }
483 
484 
485 /*static*/ void
486 PaletteConverter::_InitializeDefaultNoAppServer()
487 {
488 	sPaletteConverter.SetTo(kSystemPalette);
489 }
490 
491 
492 typedef uint32 (readFunc)(const uint8 **source, int32 index);
493 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
494 
495 
496 void
497 WriteRGB24(uint8 **dest, uint8 *data, int32 index)
498 {
499 	(*dest)[0] = data[0];
500 	(*dest)[1] = data[1];
501 	(*dest)[2] = data[2];
502 	*dest += 3;
503 }
504 
505 
506 uint32
507 ReadRGB24(const uint8 **source, int32 index)
508 {
509 	uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16);
510 	*source += 3;
511 	return result;
512 }
513 
514 
515 void
516 WriteGray8(uint8 **dest, uint8 *data, int32 index)
517 {
518 	**dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10;
519 	// this would boost the speed but is less accurate:
520 	//*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10;
521 	(*dest)++;
522 }
523 
524 
525 uint32
526 ReadGray8(const uint8 **source, int32 index)
527 {
528 	uint32 result = **source;
529 	(*source)++;
530 	return result;
531 }
532 
533 
534 void
535 WriteGray1(uint8 **dest, uint8 *data, int32 index)
536 {
537 	int32 shift = 7 - (index % 8);
538 	**dest &= ~(0x01 << shift);
539 	**dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift);
540 	if (shift == 0)
541 		(*dest)++;
542 }
543 
544 
545 uint32
546 ReadGray1(const uint8 **source, int32 index)
547 {
548 	int32 shift = 7 - (index % 8);
549 	uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00;
550 	if (shift == 0)
551 		(*source)++;
552 	return result;
553 }
554 
555 
556 void
557 WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
558 {
559 	**dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data);
560 	(*dest)++;
561 }
562 
563 
564 uint32
565 ReadCMAP8(const uint8 **source, int32 index)
566 {
567 	uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source);
568 	(*source)++;
569 	return result;
570 }
571 
572 
573 template<typename srcByte, typename dstByte>
574 status_t
575 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
576 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
577 	int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
578 	uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
579 	int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
580 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
581 	BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
582 	readFunc *srcFunc, writeFunc *dstFunc)
583 {
584 	uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
585 	uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
586 
587 	int32 srcBitsPerRow = srcBytesPerRow << 3;
588 	int32 dstBitsPerRow = dstBytesPerRow << 3;
589 
590 	// Advance the buffers to reach their offsets
591 	int32 srcOffsetX = (int32)srcOffset.x;
592 	int32 dstOffsetX = (int32)dstOffset.x;
593 	int32 srcOffsetY = (int32)srcOffset.y;
594 	int32 dstOffsetY = (int32)dstOffset.y;
595 	if (srcOffsetX < 0) {
596 		dstOffsetX -= srcOffsetX;
597 		srcOffsetX = 0;
598 	}
599 	if (srcOffsetY < 0) {
600 		dstOffsetY -= srcOffsetY;
601 		height += srcOffsetY;
602 		srcOffsetY = 0;
603 	}
604 	if (dstOffsetX < 0) {
605 		srcOffsetX -= dstOffsetX;
606 		dstOffsetX = 0;
607 	}
608 	if (dstOffsetY < 0) {
609 		srcOffsetY -= dstOffsetY;
610 		height += dstOffsetY;
611 		dstOffsetY = 0;
612 	}
613 
614 	srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX
615 		* srcBitsPerPixel) >> 3));
616 	dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX
617 		* dstBitsPerPixel) >> 3));
618 
619 	// Ensure that the width fits
620 	int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
621 		/ srcBitsPerPixel;
622 	if (srcWidth < width)
623 		width = srcWidth;
624 
625 	int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
626 		/ dstBitsPerPixel;
627 	if (dstWidth < width)
628 		width = dstWidth;
629 
630 	if (width < 0)
631 		return B_OK;
632 
633 	// Catch the copy case
634 	if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) {
635 		int32 copyCount = (width * srcBitsPerPixel) >> 3;
636 		for (int32 i = 0; i < height; i++) {
637 			// make sure we don't write beyond the bits size
638 			if (copyCount > srcBitsLength)
639 				copyCount = srcBitsLength;
640 			if (copyCount > dstBitsLength)
641 				copyCount = dstBitsLength;
642 			if (copyCount == 0)
643 				break;
644 
645 			memcpy(dstBits, srcBits, copyCount);
646 
647 			srcBitsLength -= copyCount;
648 			dstBitsLength -= copyCount;
649 			srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow);
650 			dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow);
651 
652 			if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd)
653 				return B_OK;
654 		}
655 
656 		return B_OK;
657 	}
658 
659 	int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3;
660 	int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3;
661 	uint32 result;
662 	uint32 source;
663 
664 	for (int32 i = 0; i < height; i++) {
665 		for (int32 j = 0; j < width; j++) {
666 			if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
667 				|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
668 				return B_OK;
669 
670 			if (srcFunc)
671 				source = srcFunc((const uint8 **)&srcBits, srcOffsetX++);
672 			else {
673 				source = *srcBits;
674 				srcBits++;
675 			}
676 
677 			// This is valid, as only 16 bit modes will need to swap
678 			if (srcSwap)
679 				source = (source << 8) | (source >> 8);
680 
681 			if (redShift > 0)
682 				result = ((source >> redShift) & redMask);
683 			else if (redShift < 0)
684 				result = ((source << -redShift) & redMask);
685 			else
686 				result = source & redMask;
687 
688 			if (greenShift > 0)
689 				result |= ((source >> greenShift) & greenMask);
690 			else if (greenShift < 0)
691 				result |= ((source << -greenShift) & greenMask);
692 			else
693 				result |= source & greenMask;
694 
695 			if (blueShift > 0)
696 				result |= ((source >> blueShift) & blueMask);
697 			else if (blueShift < 0)
698 				result |= ((source << -blueShift) & blueMask);
699 			else
700 				result |= source & blueMask;
701 
702 			if (alphaBits > 0) {
703 				if (alphaShift > 0)
704 					result |= ((source >> alphaShift) & alphaMask);
705 				else if (alphaShift < 0)
706 					result |= ((source << -alphaShift) & alphaMask);
707 				else
708 					result |= source & alphaMask;
709 
710 				// if we only had one alpha bit we want it to be 0/255
711 				if (alphaBits == 1 && result & alphaMask)
712 					result |= alphaMask;
713 			} else
714 				result |= alphaMask;
715 
716 			// This is valid, as only 16 bit modes will need to swap
717 			if (dstSwap)
718 				result = (result << 8) | (result >> 8);
719 
720 			if (dstFunc)
721 				dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
722 			else {
723 				*dstBits = result;
724 				dstBits++;
725 			}
726 		}
727 
728 		srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
729 		dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
730 		dstOffsetX -= width;
731 		srcOffsetX -= width;
732 	}
733 
734 	return B_OK;
735 }
736 
737 
738 template<typename srcByte>
739 status_t
740 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
741 	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
742 	int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
743 	int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
744 	color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
745 	int32 height, bool srcSwap,	readFunc *srcFunc)
746 {
747 	switch (dstColorSpace) {
748 		case B_RGBA32:
749 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
750 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
751 				alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
752 				0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
753 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
754 				height, srcSwap, false, srcFunc, NULL);
755 			break;
756 
757 		case B_RGBA32_BIG:
758 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
759 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
760 				alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
761 				0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
762 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
763 				height, srcSwap, false, srcFunc, NULL);
764 			break;
765 
766 		/* Note:	we set the unused alpha to 255 here. This is because BeOS
767 					uses the unused alpha for B_OP_ALPHA even though it should
768 					not care about it. */
769 		case B_RGB32:
770 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
771 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
772 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
773 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
774 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
775 				height, srcSwap, false, srcFunc, NULL);
776 			break;
777 
778 		case B_RGB32_BIG:
779 			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
780 				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
781 				0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
782 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
783 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
784 				height, srcSwap, false, srcFunc, NULL);
785 			break;
786 
787 		case B_RGB24:
788 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
789 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
790 				0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow,
791 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
792 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
793 				false, srcFunc, WriteRGB24);
794 			break;
795 
796 		case B_RGB24_BIG:
797 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
798 				dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24,
799 				0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow,
800 				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
801 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
802 				false, srcFunc, WriteRGB24);
803 			break;
804 
805 		case B_RGB16:
806 		case B_RGB16_BIG:
807 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
808 				dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5,
809 				0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow,
810 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
811 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
812 				dstColorSpace == B_RGB16_BIG, srcFunc, NULL);
813 			break;
814 
815 		case B_RGBA15:
816 		case B_RGBA15_BIG:
817 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
818 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
819 				alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000,
820 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16,
821 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
822 				height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL);
823 			break;
824 
825 		case B_RGB15:
826 		case B_RGB15_BIG:
827 			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
828 				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
829 				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
830 				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
831 				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
832 				dstColorSpace == B_RGB15_BIG, srcFunc, NULL);
833 			break;
834 
835 		case B_GRAY8:
836 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
837 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
838 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
839 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
840 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
841 				height, srcSwap, false, srcFunc, WriteGray8);
842 			break;
843 
844 		case B_GRAY1:
845 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
846 				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
847 				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
848 				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1,
849 				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
850 				height, srcSwap, false, srcFunc, WriteGray1);
851 			break;
852 
853 		case B_CMAP8:
854 			PaletteConverter::InitializeDefault();
855 			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
856 				dstBitsLength, redShift - 32, greenShift - 24, blueShift - 16,
857 				alphaShift - 8, alphaBits, 0xff000000, 0x00ff0000, 0x0000ff00,
858 				0x000000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
859 				srcColorSpace, dstColorSpace, srcOffset, dstOffset,
860 				width, height, srcSwap, false, srcFunc, WriteCMAP8);
861 			break;
862 
863 		default:
864 			return B_BAD_VALUE;
865 			break;
866 	}
867 
868 	return B_OK;
869 }
870 
871 
872 /*!	\brief Converts a source buffer in one colorspace into a destination
873 		   buffer of another colorspace.
874 
875 	\param srcBits The raw source buffer.
876 	\param dstBits The raw destination buffer.
877 	\param srcBytesPerRow How many bytes per row the source buffer has got.
878 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
879 	\param srcColorSpace The colorspace the source buffer is in.
880 	\param dstColorSpace The colorspace the buffer shall be converted to.
881 	\param width The width (in pixels) of each row.
882 	\param height The height (in pixels) of the buffers.
883 	\return
884 	- \c B_OK: Indicates success.
885 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
886 */
887 status_t
888 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
889 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
890 	color_space srcColorSpace, color_space dstColorSpace, int32 width,
891 	int32 height)
892 {
893 	return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength,
894 		srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace,
895 		BPoint(0, 0), BPoint(0, 0), width, height);
896 }
897 
898 
899 /*!	\brief Converts a source buffer in one colorspace into a destination
900 		   buffer of another colorspace.
901 
902 	\param srcBits The raw source buffer.
903 	\param dstBits The raw destination buffer.
904 	\param srcBytesPerRow How many bytes per row the source buffer has got.
905 	\param dstBytesPerRow How many bytes per row the destination buffer has got.
906 	\param srcColorSpace The colorspace the source buffer is in.
907 	\param dstColorSpace The colorspace the buffer shall be converted to.
908 	\param srcOffset The offset at which to start reading in the source.
909 	\param srcOffset The offset at which to start writing in the destination.
910 	\param width The width (in pixels) to convert.
911 	\param height The height (in pixels) to convert.
912 	\return
913 	- \c B_OK: Indicates success.
914 	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
915 */
916 status_t
917 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
918 	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
919 	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
920 	BPoint dstOffset, int32 width, int32 height)
921 {
922 	if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0
923 		|| width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0)
924 		return B_BAD_VALUE;
925 
926 	switch (srcColorSpace) {
927 		case B_RGBA32:
928 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
929 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
930 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
931 				dstOffset, width, height, false, NULL);
932 			break;
933 
934 		case B_RGBA32_BIG:
935 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
936 				dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow,
937 				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
938 				dstOffset, width, height, false, NULL);
939 			break;
940 
941 		case B_RGB32:
942 			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
943 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
944 				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
945 				height, false, NULL);
946 			break;
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 			break;
954 
955 		case B_RGB24:
956 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
957 				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
958 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
959 				height, false, ReadRGB24);
960 			break;
961 
962 		case B_RGB24_BIG:
963 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
964 				dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow,
965 				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
966 				height, false, ReadRGB24);
967 			break;
968 
969 		case B_RGB16:
970 		case B_RGB16_BIG:
971 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
972 				dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
973 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
974 				height, srcColorSpace == B_RGB16_BIG, NULL);
975 			break;
976 
977 		case B_RGBA15:
978 		case B_RGBA15_BIG:
979 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
980 				dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow,
981 				dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset,
982 				dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL);
983 			break;
984 
985 		case B_RGB15:
986 		case B_RGB15_BIG:
987 			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
988 				dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
989 				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
990 				height, srcColorSpace == B_RGB15_BIG, NULL);
991 			break;
992 
993 		case B_GRAY8:
994 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
995 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
996 				8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
997 				height, false, ReadGray8);
998 			break;
999 
1000 		case B_GRAY1:
1001 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1002 				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1003 				1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1004 				height, false, ReadGray1);
1005 			break;
1006 
1007 		case B_CMAP8:
1008 			PaletteConverter::InitializeDefault();
1009 			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1010 				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
1011 				dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset,
1012 				dstOffset, width, height, false, ReadCMAP8);
1013 			break;
1014 
1015 		default:
1016 			return B_BAD_VALUE;
1017 			break;
1018 	}
1019 
1020 	return B_OK;
1021 }
1022 
1023 } // namespace BPrivate
1024