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
27using std::nothrow;
28
29
30namespace 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*/
39static inline
40uint8
41brightness_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*/
63static inline
64unsigned
65color_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*/
84PaletteConverter::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*/
96PaletteConverter::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*/
109PaletteConverter::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*/
120PaletteConverter::~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*/
130status_t
131PaletteConverter::SetTo(const rgb_color *palette)
132{
133	// cleanup
134	SetTo((const color_map*)NULL);
135	status_t error = (palette ? B_OK : B_BAD_VALUE);
136	// alloc color map
137	if (error == B_OK) {
138		fOwnColorMap = new(nothrow) color_map;
139		if (fOwnColorMap == NULL)
140			error = B_NO_MEMORY;
141	}
142	// init color map
143	if (error == B_OK) {
144		fColorMap = fOwnColorMap;
145		// init color list
146		memcpy((void*)fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256);
147		// init index map
148// TODO: build this list takes about 2 seconds in qemu on my system
149//		(because of color_distance())
150		for (int32 color = 0; color < 32768; color++) {
151			// get components
152			uint8 red = (color & 0x7c00) >> 7;
153			uint8 green = (color & 0x3e0) >> 2;
154			uint8 blue = (color & 0x1f) << 3;
155			red |= red >> 5;
156			green |= green >> 5;
157			blue |= blue >> 5;
158			// find closest color
159			uint8 closestIndex = 0;
160			unsigned closestDistance = UINT_MAX;
161			for (int32 i = 0; i < 256; i++) {
162				const rgb_color &c = fOwnColorMap->color_list[i];
163				unsigned distance = color_distance(red, green, blue,
164												   c.red, c.green, c.blue);
165				if (distance < closestDistance) {
166					closestIndex = i;
167					closestDistance = distance;
168				}
169			}
170			fOwnColorMap->index_map[color] = closestIndex;
171		}
172		// no need to init inversion map
173	}
174	fCStatus = error;
175	return error;
176}
177
178
179/*!	\brief Initializes the converter to the supplied color map.
180	\param colorMap The completely initialized color map.
181	\return \c B_OK, if everything went fine, an error code otherwise.
182*/
183status_t
184PaletteConverter::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*/
203status_t
204PaletteConverter::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*/
217inline
218uint8
219PaletteConverter::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*/
234inline
235uint8
236PaletteConverter::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*/
250inline
251uint8
252PaletteConverter::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*/
267inline
268uint8
269PaletteConverter::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*/
283inline
284uint8
285PaletteConverter::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*/
302inline
303uint8
304PaletteConverter::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*/
319inline
320uint8
321PaletteConverter::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*/
336inline
337uint8
338PaletteConverter::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*/
351inline
352const rgb_color &
353PaletteConverter::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*/
367inline
368uint16
369PaletteConverter::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*/
386inline
387uint16
388PaletteConverter::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*/
405inline
406uint32
407PaletteConverter::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*/
429inline
430void
431PaletteConverter::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*/
449inline
450uint8
451PaletteConverter::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
458static pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT;
459static 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
466PaletteConverter::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
480PaletteConverter::_InitializeDefaultAppServer()
481{
482	sPaletteConverter.SetTo(system_colors());
483}
484
485
486/*static*/ void
487PaletteConverter::_InitializeDefaultNoAppServer()
488{
489	sPaletteConverter.SetTo(kSystemPalette);
490}
491
492
493typedef uint32 (readFunc)(const uint8 **source, int32 index);
494typedef uint64 (read64Func)(const uint16 **source, int32 index);
495typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
496
497
498uint64
499ReadRGB48(const uint16 **source, int32 index)
500{
501	uint64 result = (*source)[0] | ((uint64)((*source)[1]) << 16)
502		| ((uint64)((*source)[2]) << 32);
503	*source += 3;
504	return result;
505}
506
507
508void
509WriteRGB24(uint8 **dest, uint8 *data, int32 index)
510{
511	(*dest)[0] = data[0];
512	(*dest)[1] = data[1];
513	(*dest)[2] = data[2];
514	*dest += 3;
515}
516
517
518uint32
519ReadRGB24(const uint8 **source, int32 index)
520{
521	uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16);
522	*source += 3;
523	return result;
524}
525
526
527void
528WriteGray8(uint8 **dest, uint8 *data, int32 index)
529{
530	**dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10;
531	// this would boost the speed but is less accurate:
532	//*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10;
533	(*dest)++;
534}
535
536
537uint32
538ReadGray8(const uint8 **source, int32 index)
539{
540	uint32 result = **source;
541	(*source)++;
542	return result;
543}
544
545
546void
547WriteGray1(uint8 **dest, uint8 *data, int32 index)
548{
549	int32 shift = 7 - (index % 8);
550	**dest &= ~(0x01 << shift);
551	**dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift);
552	if (shift == 0)
553		(*dest)++;
554}
555
556
557uint32
558ReadGray1(const uint8 **source, int32 index)
559{
560	int32 shift = 7 - (index % 8);
561	// In B_GRAY1, a set bit means black (highcolor), a clear bit means white
562	// (low/view color). So we map them to 00 and 0xFF, respectively.
563	uint32 result = ((**source >> shift) & 0x01) ? 0x00 : 0xFF;
564	if (shift == 0)
565		(*source)++;
566	return result;
567}
568
569
570void
571WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
572{
573	**dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data);
574	(*dest)++;
575}
576
577
578uint32
579ReadCMAP8(const uint8 **source, int32 index)
580{
581	uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source);
582	(*source)++;
583	return result;
584}
585
586
587template<typename srcByte, typename dstByte>
588status_t
589ConvertBits64To32(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
590	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
591	int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
592	uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
593	int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
594	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
595	BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
596	read64Func *srcFunc, writeFunc *dstFunc)
597{
598	uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
599	uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
600
601	int32 srcBitsPerRow = srcBytesPerRow << 3;
602	int32 dstBitsPerRow = dstBytesPerRow << 3;
603
604	// Advance the buffers to reach their offsets
605	int32 srcOffsetX = (int32)srcOffset.x;
606	int32 dstOffsetX = (int32)dstOffset.x;
607	int32 srcOffsetY = (int32)srcOffset.y;
608	int32 dstOffsetY = (int32)dstOffset.y;
609	if (srcOffsetX < 0) {
610		dstOffsetX -= srcOffsetX;
611		srcOffsetX = 0;
612	}
613	if (srcOffsetY < 0) {
614		dstOffsetY -= srcOffsetY;
615		height += srcOffsetY;
616		srcOffsetY = 0;
617	}
618	if (dstOffsetX < 0) {
619		srcOffsetX -= dstOffsetX;
620		dstOffsetX = 0;
621	}
622	if (dstOffsetY < 0) {
623		srcOffsetY -= dstOffsetY;
624		height += dstOffsetY;
625		dstOffsetY = 0;
626	}
627
628	srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow
629		+ srcOffsetX * srcBitsPerPixel) >> 3));
630	dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow
631		+ dstOffsetX * dstBitsPerPixel) >> 3));
632
633	// Ensure that the width fits
634	int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
635		/ srcBitsPerPixel;
636	if (srcWidth < width)
637		width = srcWidth;
638
639	int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
640		/ dstBitsPerPixel;
641	if (dstWidth < width)
642		width = dstWidth;
643
644	if (width < 0)
645		return B_OK;
646
647	int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel + 7) >> 3;
648	int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel + 7) >> 3;
649	uint64 result;
650	uint64 source;
651
652	// srcSwap, means the lower bits come first
653	if (srcSwap) {
654		redShift -= 8;
655		greenShift -= 8;
656		blueShift -= 8;
657		alphaShift -= 8;
658	}
659
660	for (int32 i = 0; i < height; i++) {
661		for (int32 j = 0; j < width; j++) {
662			if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
663				|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
664				return B_OK;
665
666			if (srcFunc)
667				source = srcFunc((const uint16 **)&srcBits, srcOffsetX++);
668			else {
669				source = *srcBits;
670				srcBits++;
671			}
672
673			if (redShift > 0)
674				result = ((source >> redShift) & redMask);
675			else if (redShift < 0)
676				result = ((source << -redShift) & redMask);
677			else
678				result = source & redMask;
679
680			if (greenShift > 0)
681				result |= ((source >> greenShift) & greenMask);
682			else if (greenShift < 0)
683				result |= ((source << -greenShift) & greenMask);
684			else
685				result |= source & greenMask;
686
687			if (blueShift > 0)
688				result |= ((source >> blueShift) & blueMask);
689			else if (blueShift < 0)
690				result |= ((source << -blueShift) & blueMask);
691			else
692				result |= source & blueMask;
693
694			if (alphaBits > 0) {
695				if (alphaShift > 0)
696					result |= ((source >> alphaShift) & alphaMask);
697				else if (alphaShift < 0)
698					result |= ((source << -alphaShift) & alphaMask);
699				else
700					result |= source & alphaMask;
701
702				// if we only had one alpha bit we want it to be 0/255
703				if (alphaBits == 1 && result & alphaMask)
704					result |= alphaMask;
705			} else
706				result |= alphaMask;
707
708			if (dstFunc)
709				dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
710			else {
711				*dstBits = result;
712				dstBits++;
713			}
714		}
715
716		srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
717		dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
718		dstOffsetX -= width;
719		srcOffsetX -= width;
720	}
721
722	return B_OK;
723}
724
725
726template<typename srcByte, typename dstByte>
727status_t
728ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
729	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
730	int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
731	uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
732	int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
733	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
734	BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
735	readFunc *srcFunc, writeFunc *dstFunc)
736{
737	uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
738	uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
739
740	int32 srcBitsPerRow = srcBytesPerRow << 3;
741	int32 dstBitsPerRow = dstBytesPerRow << 3;
742
743	// Advance the buffers to reach their offsets
744	int32 srcOffsetX = (int32)srcOffset.x;
745	int32 dstOffsetX = (int32)dstOffset.x;
746	int32 srcOffsetY = (int32)srcOffset.y;
747	int32 dstOffsetY = (int32)dstOffset.y;
748	if (srcOffsetX < 0) {
749		dstOffsetX -= srcOffsetX;
750		srcOffsetX = 0;
751	}
752	if (srcOffsetY < 0) {
753		dstOffsetY -= srcOffsetY;
754		height += srcOffsetY;
755		srcOffsetY = 0;
756	}
757	if (dstOffsetX < 0) {
758		srcOffsetX -= dstOffsetX;
759		dstOffsetX = 0;
760	}
761	if (dstOffsetY < 0) {
762		srcOffsetY -= dstOffsetY;
763		height += dstOffsetY;
764		dstOffsetY = 0;
765	}
766
767	srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow
768		+ srcOffsetX * srcBitsPerPixel) >> 3));
769	dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow
770		+ dstOffsetX * dstBitsPerPixel) >> 3));
771
772	// Ensure that the width fits
773	int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
774		/ srcBitsPerPixel;
775	if (srcWidth < width)
776		width = srcWidth;
777
778	int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
779		/ dstBitsPerPixel;
780	if (dstWidth < width)
781		width = dstWidth;
782
783	if (width < 0)
784		return B_OK;
785
786	// Catch the copy case
787	if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) {
788		int32 copyCount = (width * srcBitsPerPixel) >> 3;
789		for (int32 i = 0; i < height; i++) {
790			// make sure we don't write beyond the bits size
791			if (copyCount > srcBitsLength)
792				copyCount = srcBitsLength;
793			if (copyCount > dstBitsLength)
794				copyCount = dstBitsLength;
795			if (copyCount == 0)
796				break;
797
798			memcpy(dstBits, srcBits, copyCount);
799
800			srcBitsLength -= copyCount;
801			dstBitsLength -= copyCount;
802			srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow);
803			dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow);
804
805			if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd)
806				return B_OK;
807		}
808
809		return B_OK;
810	}
811
812	int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel + 7) >> 3;
813	int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel + 7) >> 3;
814	uint32 result;
815	uint32 source;
816
817	for (int32 i = 0; i < height; i++) {
818		for (int32 j = 0; j < width; j++) {
819			if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
820				|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
821				return B_OK;
822
823			if (srcFunc)
824				source = srcFunc((const uint8 **)&srcBits, srcOffsetX++);
825			else {
826				source = *srcBits;
827				srcBits++;
828			}
829
830			// This is valid, as only 16 bit modes will need to swap
831			if (srcSwap)
832				source = (source << 8) | (source >> 8);
833
834			if (redShift > 0)
835				result = ((source >> redShift) & redMask);
836			else if (redShift < 0)
837				result = ((source << -redShift) & redMask);
838			else
839				result = source & redMask;
840
841			if (greenShift > 0)
842				result |= ((source >> greenShift) & greenMask);
843			else if (greenShift < 0)
844				result |= ((source << -greenShift) & greenMask);
845			else
846				result |= source & greenMask;
847
848			if (blueShift > 0)
849				result |= ((source >> blueShift) & blueMask);
850			else if (blueShift < 0)
851				result |= ((source << -blueShift) & blueMask);
852			else
853				result |= source & blueMask;
854
855			if (alphaBits > 0) {
856				if (alphaShift > 0)
857					result |= ((source >> alphaShift) & alphaMask);
858				else if (alphaShift < 0)
859					result |= ((source << -alphaShift) & alphaMask);
860				else
861					result |= source & alphaMask;
862
863				// if we only had one alpha bit we want it to be 0/255
864				if (alphaBits == 1 && result & alphaMask)
865					result |= alphaMask;
866			} else
867				result |= alphaMask;
868
869			// This is valid, as only 16 bit modes will need to swap
870			if (dstSwap)
871				result = (result << 8) | (result >> 8);
872
873			if (dstFunc)
874				dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
875			else {
876				*dstBits = result;
877				dstBits++;
878			}
879		}
880
881		srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
882		dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
883		dstOffsetX -= width;
884		srcOffsetX -= width;
885	}
886
887	return B_OK;
888}
889
890
891template<typename srcByte>
892status_t
893ConvertBits64(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
894	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
895	int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
896	int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
897	color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
898	int32 height, bool srcSwap,	read64Func *srcFunc)
899{
900	switch (dstColorSpace) {
901		case B_RGBA32:
902			ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
903				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
904				alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
905				0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
906				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
907				height, srcSwap, false, srcFunc, NULL);
908			break;
909
910		case B_RGBA32_BIG:
911			ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
912				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
913				alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
914				0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
915				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
916				height, srcSwap, false, srcFunc, NULL);
917			break;
918
919		/* Note:	we set the unused alpha to 255 here. This is because BeOS
920					uses the unused alpha for B_OP_ALPHA even though it should
921					not care about it. */
922		case B_RGB32:
923			ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
924				dstBitsLength, redShift - 24, greenShift - 32, blueShift - 16,
925				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
926				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
927				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
928				height, srcSwap, false, srcFunc, NULL);
929			break;
930
931		case B_RGB32_BIG:
932			ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
933				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
934				0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
935				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
936				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
937				height, srcSwap, false, srcFunc, NULL);
938			break;
939
940		default:
941			return B_BAD_VALUE;
942			break;
943	}
944
945	return B_OK;
946}
947
948
949template<typename srcByte>
950status_t
951ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
952	int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
953	int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
954	int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
955	color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
956	int32 height, bool srcSwap,	readFunc *srcFunc)
957{
958	switch (dstColorSpace) {
959		case B_RGBA32:
960			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
961				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
962				alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
963				0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
964				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
965				height, srcSwap, false, srcFunc, NULL);
966			break;
967
968		case B_RGBA32_BIG:
969			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
970				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
971				alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
972				0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
973				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
974				height, srcSwap, false, srcFunc, NULL);
975			break;
976
977		/* Note:	we set the unused alpha to 255 here. This is because BeOS
978					uses the unused alpha for B_OP_ALPHA even though it should
979					not care about it. */
980		case B_RGB32:
981			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
982				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
983				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
984				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
985				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
986				height, srcSwap, false, srcFunc, NULL);
987			break;
988
989		case B_RGB32_BIG:
990			ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength,
991				dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
992				0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
993				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
994				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
995				height, srcSwap, false, srcFunc, NULL);
996			break;
997
998		case B_RGB24:
999			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
1000				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
1001				0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow,
1002				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
1003				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
1004				false, srcFunc, WriteRGB24);
1005			break;
1006
1007		case B_RGB24_BIG:
1008			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
1009				dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24,
1010				0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow,
1011				dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace,
1012				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
1013				false, srcFunc, WriteRGB24);
1014			break;
1015
1016		case B_RGB16:
1017		case B_RGB16_BIG:
1018			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
1019				dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5,
1020				0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow,
1021				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
1022				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
1023				dstColorSpace == B_RGB16_BIG, srcFunc, NULL);
1024			break;
1025
1026		case B_RGBA15:
1027		case B_RGBA15_BIG:
1028			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
1029				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
1030				alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000,
1031				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16,
1032				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1033				height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL);
1034			break;
1035
1036		case B_RGB15:
1037		case B_RGB15_BIG:
1038			ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength,
1039				dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5,
1040				0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow,
1041				dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace,
1042				dstColorSpace, srcOffset, dstOffset, width, height, srcSwap,
1043				dstColorSpace == B_RGB15_BIG, srcFunc, NULL);
1044			break;
1045
1046		case B_GRAY8:
1047			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
1048				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
1049				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
1050				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
1051				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1052				height, srcSwap, false, srcFunc, WriteGray8);
1053			break;
1054
1055		case B_GRAY1:
1056			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
1057				dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
1058				0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
1059				srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1,
1060				srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1061				height, srcSwap, false, srcFunc, WriteGray1);
1062			break;
1063
1064		case B_CMAP8:
1065			PaletteConverter::InitializeDefault();
1066			ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength,
1067				dstBitsLength, redShift - 32, greenShift - 24, blueShift - 16,
1068				alphaShift - 8, alphaBits, 0xff000000, 0x00ff0000, 0x0000ff00,
1069				0x000000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8,
1070				srcColorSpace, dstColorSpace, srcOffset, dstOffset,
1071				width, height, srcSwap, false, srcFunc, WriteCMAP8);
1072			break;
1073
1074		default:
1075			return B_BAD_VALUE;
1076			break;
1077	}
1078
1079	return B_OK;
1080}
1081
1082
1083/*!	\brief Converts a source buffer in one colorspace into a destination
1084		   buffer of another colorspace.
1085
1086	\param srcBits The raw source buffer.
1087	\param dstBits The raw destination buffer.
1088	\param srcBytesPerRow How many bytes per row the source buffer has got.
1089	\param dstBytesPerRow How many bytes per row the destination buffer has got.
1090	\param srcColorSpace The colorspace the source buffer is in.
1091	\param dstColorSpace The colorspace the buffer shall be converted to.
1092	\param width The width (in pixels) of each row.
1093	\param height The height (in pixels) of the buffers.
1094	\return
1095	- \c B_OK: Indicates success.
1096	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
1097*/
1098status_t
1099ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
1100	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
1101	color_space srcColorSpace, color_space dstColorSpace, int32 width,
1102	int32 height)
1103{
1104	return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength,
1105		srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace,
1106		BPoint(0, 0), BPoint(0, 0), width, height);
1107}
1108
1109
1110/*!	\brief Converts a source buffer in one colorspace into a destination
1111		   buffer of another colorspace.
1112
1113	\param srcBits The raw source buffer.
1114	\param dstBits The raw destination buffer.
1115	\param srcBytesPerRow How many bytes per row the source buffer has got.
1116	\param dstBytesPerRow How many bytes per row the destination buffer has got.
1117	\param srcColorSpace The colorspace the source buffer is in.
1118	\param dstColorSpace The colorspace the buffer shall be converted to.
1119	\param srcOffset The offset at which to start reading in the source.
1120	\param srcOffset The offset at which to start writing in the destination.
1121	\param width The width (in pixels) to convert.
1122	\param height The height (in pixels) to convert.
1123	\return
1124	- \c B_OK: Indicates success.
1125	- \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported.
1126*/
1127status_t
1128ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
1129	int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow,
1130	color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
1131	BPoint dstOffset, int32 width, int32 height)
1132{
1133	if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0
1134		|| width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0)
1135		return B_BAD_VALUE;
1136
1137	switch (srcColorSpace) {
1138		case B_RGBA64:
1139		case B_RGBA64_BIG:
1140			return ConvertBits64((const uint64 *)srcBits, dstBits,
1141				srcBitsLength, dstBitsLength, 16, 32, 48, 64, 16,
1142				srcBytesPerRow, dstBytesPerRow, 64, srcColorSpace,
1143				dstColorSpace, srcOffset, dstOffset, width, height,
1144				srcColorSpace == B_RGBA64_BIG, NULL);
1145
1146		case B_RGB48:
1147		case B_RGB48_BIG:
1148			return ConvertBits64((const uint16 *)srcBits, dstBits,
1149				srcBitsLength, dstBitsLength, 16, 32, 48, 0, 0, srcBytesPerRow,
1150				dstBytesPerRow, 48, srcColorSpace, dstColorSpace, srcOffset,
1151				dstOffset, width, height, srcColorSpace == B_RGB48_BIG,
1152				ReadRGB48);
1153
1154		case B_RGBA32:
1155			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1156				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
1157				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
1158				dstOffset, width, height, false, NULL);
1159
1160		case B_RGBA32_BIG:
1161			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1162				dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow,
1163				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
1164				dstOffset, width, height, false, NULL);
1165
1166		case B_RGB32:
1167			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1168				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1169				32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1170				height, false, NULL);
1171
1172		case B_RGB32_BIG:
1173			return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
1174				dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow,
1175				dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset,
1176				dstOffset, width, height, false, NULL);
1177
1178		case B_RGB24:
1179			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1180				dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1181				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1182				height, false, ReadRGB24);
1183
1184		case B_RGB24_BIG:
1185			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1186				dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow,
1187				24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1188				height, false, ReadRGB24);
1189
1190		case B_RGB16:
1191		case B_RGB16_BIG:
1192			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1193				dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
1194				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1195				height, srcColorSpace == B_RGB16_BIG, NULL);
1196
1197		case B_RGBA15:
1198		case B_RGBA15_BIG:
1199			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1200				dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow,
1201				dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset,
1202				dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL);
1203
1204		case B_RGB15:
1205		case B_RGB15_BIG:
1206			return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength,
1207				dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow,
1208				16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1209				height, srcColorSpace == B_RGB15_BIG, NULL);
1210
1211		case B_GRAY8:
1212			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1213				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1214				8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1215				height, false, ReadGray8);
1216
1217		case B_GRAY1:
1218			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1219				dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow,
1220				1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
1221				height, false, ReadGray1);
1222
1223		case B_CMAP8:
1224			PaletteConverter::InitializeDefault();
1225			return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength,
1226				dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,
1227				dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset,
1228				dstOffset, width, height, false, ReadCMAP8);
1229
1230		default:
1231			return B_BAD_VALUE;
1232	}
1233
1234	return B_OK;
1235}
1236
1237} // namespace BPrivate
1238