138032Speter/*
2261363Sgshapiro * Copyright 2001-2006, Haiku Inc.
364565Sgshapiro * Distributed under the terms of the MIT License.
438032Speter *
538032Speter * Authors:
638032Speter *		Ingo Weinhold (bonefish@users.sf.net)
738032Speter *		Michael Lotz <mmlr@mlotz.ch>
838032Speter */
938032Speter
1038032Speter/**	This file contains colorspace conversion functions
1138032Speter *	and a palette <-> true color conversion class.
1238032Speter */
13266692Sgshapiro
1438032Speter#include "ColorConversion.h"
1538032Speter
1638032Speter#include <InterfaceDefs.h>
1738032Speter#include <Locker.h>
1838032Speter#include <Point.h>
1938032Speter
2038032Speter#include <Palette.h>
2138032Speter
2238032Speter#include <new>
2364565Sgshapiro#include <string.h>
2464565Sgshapiro
2564565Sgshapiro
2638032Speterusing std::nothrow;
2738032Speter
2864565Sgshapiro
2938032Speternamespace BPrivate {
3038032Speter
3138032Speter/*!	\brief Returns the brightness of an RGB 24 color.
3238032Speter	\param red Value of the red component.
3364565Sgshapiro	\param green Value of the green component.
3438032Speter	\param blue Value of the blue component.
3564565Sgshapiro	\return The brightness for the supplied RGB color as a value between 0
3664565Sgshapiro			and 255.
3738032Speter*/
3838032Speterstatic inline
3938032Speteruint8
4038032Speterbrightness_for(uint8 red, uint8 green, uint8 blue)
4138032Speter{
4238032Speter	// brightness = 0.301 * red + 0.586 * green + 0.113 * blue
4364565Sgshapiro	// we use for performance reasons:
4438032Speter	// brightness = (308 * red + 600 * green + 116 * blue) / 1024
4564565Sgshapiro	return uint8((308 * red + 600 * green + 116 * blue) / 1024);
4664565Sgshapiro}
4764565Sgshapiro
4864565Sgshapiro
4964565Sgshapiro/*!	\brief Returns the "distance" between two RGB colors.
5064565Sgshapiro
5164565Sgshapiro	This functions defines an metric on the RGB color space. The distance
5264565Sgshapiro	between two colors is 0, if and only if the colors are equal.
5364565Sgshapiro
5464565Sgshapiro	\param red1 Red component of the first color.
5564565Sgshapiro	\param green1 Green component of the first color.
5638032Speter	\param blue1 Blue component of the first color.
5738032Speter	\param red2 Red component of the second color.
5838032Speter	\param green2 Green component of the second color.
5990795Sgshapiro	\param blue2 Blue component of the second color.
6038032Speter	\return The distance between the given colors.
6138032Speter*/
62157006Sgshapirostatic inline
63168520Sgshapirounsigned
64168520Sgshapirocolor_distance(uint8 red1, uint8 green1, uint8 blue1,
65168520Sgshapiro			   uint8 red2, uint8 green2, uint8 blue2)
66168520Sgshapiro{
67168520Sgshapiro	// euklidian distance (its square actually)
68157006Sgshapiro	int rd = (int)red1 - (int)red2;
69110563Sgshapiro	int gd = (int)green1 - (int)green2;
70157006Sgshapiro	int bd = (int)blue1 - (int)blue2;
71110563Sgshapiro	//return rd * rd + gd * gd + bd * bd;
72157006Sgshapiro
73157006Sgshapiro	// distance according to psycho-visual tests
74157006Sgshapiro	int rmean = ((int)red1 + (int)red2) / 2;
75157006Sgshapiro	return (((512 + rmean) * rd * rd) >> 8)
76157006Sgshapiro		   + 4 * gd * gd
77157006Sgshapiro		   + (((767 - rmean) * bd * bd) >> 8);
78157006Sgshapiro}
79168520Sgshapiro
80157006Sgshapiro
81157006Sgshapiro/*!	\brief Creates an uninitialized PaletteConverter.
82157006Sgshapiro*/
8390795SgshapiroPaletteConverter::PaletteConverter()
84157006Sgshapiro	: fColorMap(NULL),
85157006Sgshapiro	  fOwnColorMap(NULL),
8690795Sgshapiro	  fCStatus(B_NO_INIT)
87157006Sgshapiro{
88157006Sgshapiro}
89157006Sgshapiro
90157006Sgshapiro
91157006Sgshapiro/*!	\brief Creates a PaletteConverter and initializes it to the supplied
92157006Sgshapiro		   palette.
9390795Sgshapiro	\param palette The palette being a 256 entry rgb_color array.
94157006Sgshapiro*/
95157006SgshapiroPaletteConverter::PaletteConverter(const rgb_color *palette)
96157006Sgshapiro	: fColorMap(NULL),
97157006Sgshapiro	  fOwnColorMap(NULL),
9890795Sgshapiro	  fCStatus(B_NO_INIT)
9990795Sgshapiro{
10090795Sgshapiro	SetTo(palette);
10190795Sgshapiro}
10290795Sgshapiro
10390795Sgshapiro
10490795Sgshapiro/*!	\brief Creates a PaletteConverter and initializes it to the supplied
10590795Sgshapiro		   color map.
10664565Sgshapiro	\param colorMap The completely initialized color map.
10764565Sgshapiro*/
10864565SgshapiroPaletteConverter::PaletteConverter(const color_map *colorMap)
10964565Sgshapiro	: fColorMap(NULL),
11064565Sgshapiro	  fOwnColorMap(NULL),
11171348Sgshapiro	  fCStatus(B_NO_INIT)
11264565Sgshapiro{
11364565Sgshapiro	SetTo(colorMap);
11464565Sgshapiro}
115261363Sgshapiro
116261363Sgshapiro
117261363Sgshapiro/*!	\brief Frees all resources associated with this object.
11864565Sgshapiro*/
11964565SgshapiroPaletteConverter::~PaletteConverter()
12064565Sgshapiro{
12164565Sgshapiro	delete fOwnColorMap;
12264565Sgshapiro}
12364565Sgshapiro
12464565Sgshapiro
12590795Sgshapiro/*!	\brief Initializes the converter to the supplied palette.
12664565Sgshapiro	\param palette The palette being a 256 entry rgb_color array.
12790795Sgshapiro	\return \c B_OK, if everything went fine, an error code otherwise.
128203004Sgshapiro*/
129203004Sgshapirostatus_t
13090795SgshapiroPaletteConverter::SetTo(const rgb_color *palette)
131203004Sgshapiro{
132203004Sgshapiro	// cleanup
133203004Sgshapiro	SetTo((const color_map*)NULL);
134203004Sgshapiro	status_t error = (palette ? B_OK : B_BAD_VALUE);
135203004Sgshapiro	// alloc color map
136203004Sgshapiro	if (error == B_OK) {
137203004Sgshapiro		fOwnColorMap = new(nothrow) color_map;
138203004Sgshapiro		if (fOwnColorMap == NULL)
139203004Sgshapiro			error = B_NO_MEMORY;
14090795Sgshapiro	}
14190795Sgshapiro	// init color map
14290795Sgshapiro	if (error == B_OK) {
14390795Sgshapiro		fColorMap = fOwnColorMap;
14490795Sgshapiro		// init color list
14538032Speter		memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256);
14690795Sgshapiro		// init index map
14790795Sgshapiro// TODO: build this list takes about 2 seconds in qemu on my system
14890795Sgshapiro//		(because of color_distance())
14990795Sgshapiro		for (int32 color = 0; color < 32768; color++) {
15064565Sgshapiro			// get components
15164565Sgshapiro			uint8 red = (color & 0x7c00) >> 7;
15290795Sgshapiro			uint8 green = (color & 0x3e0) >> 2;
15364565Sgshapiro			uint8 blue = (color & 0x1f) << 3;
15490795Sgshapiro			red |= red >> 5;
15564565Sgshapiro			green |= green >> 5;
15690795Sgshapiro			blue |= blue >> 5;
15764565Sgshapiro			// find closest color
15864565Sgshapiro			uint8 closestIndex = 0;
15964565Sgshapiro			unsigned closestDistance = UINT_MAX;
16098125Sgshapiro			for (int32 i = 0; i < 256; i++) {
16198125Sgshapiro				const rgb_color &c = fOwnColorMap->color_list[i];
16298125Sgshapiro				unsigned distance = color_distance(red, green, blue,
16398125Sgshapiro												   c.red, c.green, c.blue);
16498125Sgshapiro				if (distance < closestDistance) {
16598125Sgshapiro					closestIndex = i;
16698125Sgshapiro					closestDistance = distance;
16798125Sgshapiro				}
16898125Sgshapiro			}
169132946Sgshapiro			fOwnColorMap->index_map[color] = closestIndex;
170132946Sgshapiro		}
171132946Sgshapiro		// no need to init inversion map
17298125Sgshapiro	}
173132946Sgshapiro	fCStatus = error;
174132946Sgshapiro	return error;
175132946Sgshapiro}
176132946Sgshapiro
177132946Sgshapiro
178132946Sgshapiro/*!	\brief Initializes the converter to the supplied color map.
179132946Sgshapiro	\param colorMap The completely initialized color map.
18038032Speter	\return \c B_OK, if everything went fine, an error code otherwise.
18138032Speter*/
18238032Speterstatus_t
18338032SpeterPaletteConverter::SetTo(const color_map *colorMap)
18438032Speter{
18538032Speter	// cleanup
18638032Speter	if (fOwnColorMap) {
18764565Sgshapiro		delete fOwnColorMap;
18864565Sgshapiro		fOwnColorMap = NULL;
18964565Sgshapiro	}
19038032Speter	// set
19164565Sgshapiro	fColorMap = colorMap;
19264565Sgshapiro	fCStatus = (fColorMap ? B_OK : B_BAD_VALUE);
19364565Sgshapiro	return fCStatus;
19438032Speter}
19564565Sgshapiro
19664565Sgshapiro
19764565Sgshapiro/*!	\brief Returns the result of the last initialization via constructor or
19838032Speter		   SetTo().
19964565Sgshapiro	\return \c B_OK, if the converter is properly initialized, an error code
20064565Sgshapiro			otherwise.
20164565Sgshapiro*/
20238032Speterstatus_t
20364565SgshapiroPaletteConverter::InitCheck() const
20464565Sgshapiro{
20564565Sgshapiro	return fCStatus;
20638032Speter}
20764565Sgshapiro
20864565Sgshapiro
20964565Sgshapiro/*!	\brief Returns the palette color index closest to a given RGB 15 color.
21038032Speter
21164565Sgshapiro	The object must be properly initialized.
21264565Sgshapiro
21364565Sgshapiro	\param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]).
21438032Speter	\return The palette color index for the supplied color.
21564565Sgshapiro*/
21664565Sgshapiroinline
21764565Sgshapirouint8
21838032SpeterPaletteConverter::IndexForRGB15(uint16 rgb) const
21964565Sgshapiro{
22064565Sgshapiro	return fColorMap->index_map[rgb];
22164565Sgshapiro}
22238032Speter
22364565Sgshapiro
22464565Sgshapiro/*!	\brief Returns the palette color index closest to a given RGB 15 color.
22564565Sgshapiro
22664565Sgshapiro	The object must be properly initialized.
22790795Sgshapiro
22890795Sgshapiro	\param red Red component of the color (R[4:0]).
22990795Sgshapiro	\param green Green component of the color (G[4:0]).
23090795Sgshapiro	\param blue Blue component of the color (B[4:0]).
23190795Sgshapiro	\return The palette color index for the supplied color.
23238032Speter*/
23390795Sgshapiroinline
23490795Sgshapirouint8
23590795SgshapiroPaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const
23638032Speter{
23738032Speter	// the 5 least significant bits are used
23838032Speter	return fColorMap->index_map[(red << 10) | (green << 5) | blue];
23938032Speter}
24038032Speter
24190795Sgshapiro
24238032Speter/*!	\brief Returns the palette color index closest to a given RGB 16 color.
24390795Sgshapiro
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*/
249inline
250uint8
251PaletteConverter::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*/
266inline
267uint8
268PaletteConverter::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*/
282inline
283uint8
284PaletteConverter::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*/
301inline
302uint8
303PaletteConverter::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*/
318inline
319uint8
320PaletteConverter::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*/
335inline
336uint8
337PaletteConverter::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*/
350inline
351const rgb_color &
352PaletteConverter::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*/
366inline
367uint16
368PaletteConverter::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*/
385inline
386uint16
387PaletteConverter::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*/
404inline
405uint32
406PaletteConverter::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*/
428inline
429void
430PaletteConverter::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*/
448inline
449uint8
450PaletteConverter::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
457static pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT;
458static 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
465PaletteConverter::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
479PaletteConverter::_InitializeDefaultAppServer()
480{
481	sPaletteConverter.SetTo(system_colors());
482}
483
484
485/*static*/ void
486PaletteConverter::_InitializeDefaultNoAppServer()
487{
488	sPaletteConverter.SetTo(kSystemPalette);
489}
490
491
492typedef uint32 (readFunc)(const uint8 **source, int32 index);
493typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
494
495
496void
497WriteRGB24(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
506uint32
507ReadRGB24(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
515void
516WriteGray8(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
525uint32
526ReadGray8(const uint8 **source, int32 index)
527{
528	uint32 result = **source;
529	(*source)++;
530	return result;
531}
532
533
534void
535WriteGray1(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
545uint32
546ReadGray1(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
556void
557WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
558{
559	**dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data);
560	(*dest)++;
561}
562
563
564uint32
565ReadCMAP8(const uint8 **source, int32 index)
566{
567	uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source);
568	(*source)++;
569	return result;
570}
571
572
573template<typename srcByte, typename dstByte>
574status_t
575ConvertBits(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
738template<typename srcByte>
739status_t
740ConvertBits(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*/
887status_t
888ConvertBits(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*/
916status_t
917ConvertBits(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