vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / ColorConversion.cpp
blob34044836ce3698cdbb46d83062c5f9d23037b994
1 /*
2 * Copyright 2001-2006, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold (bonefish@users.sf.net)
7 * Michael Lotz <mmlr@mlotz.ch>
8 */
10 /** This file contains colorspace conversion functions
11 * and a palette <-> true color conversion class.
14 #include "ColorConversion.h"
16 #include <InterfaceDefs.h>
17 #include <Locker.h>
18 #include <Point.h>
20 #include <Palette.h>
22 #include <new>
23 #include <string.h>
26 using std::nothrow;
29 namespace BPrivate {
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.
38 static inline
39 uint8
40 brightness_for(uint8 red, uint8 green, uint8 blue)
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);
49 /*! \brief Returns the "distance" between two RGB colors.
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.
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.
62 static inline
63 unsigned
64 color_distance(uint8 red1, uint8 green1, uint8 blue1,
65 uint8 red2, uint8 green2, uint8 blue2)
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;
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);
81 /*! \brief Creates an uninitialized PaletteConverter.
83 PaletteConverter::PaletteConverter()
84 : fColorMap(NULL),
85 fOwnColorMap(NULL),
86 fCStatus(B_NO_INIT)
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.
95 PaletteConverter::PaletteConverter(const rgb_color *palette)
96 : fColorMap(NULL),
97 fOwnColorMap(NULL),
98 fCStatus(B_NO_INIT)
100 SetTo(palette);
104 /*! \brief Creates a PaletteConverter and initializes it to the supplied
105 color map.
106 \param colorMap The completely initialized color map.
108 PaletteConverter::PaletteConverter(const color_map *colorMap)
109 : fColorMap(NULL),
110 fOwnColorMap(NULL),
111 fCStatus(B_NO_INIT)
113 SetTo(colorMap);
117 /*! \brief Frees all resources associated with this object.
119 PaletteConverter::~PaletteConverter()
121 delete fOwnColorMap;
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.
129 status_t
130 PaletteConverter::SetTo(const rgb_color *palette)
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;
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;
169 fOwnColorMap->index_map[color] = closestIndex;
171 // no need to init inversion map
173 fCStatus = error;
174 return error;
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.
182 status_t
183 PaletteConverter::SetTo(const color_map *colorMap)
185 // cleanup
186 if (fOwnColorMap) {
187 delete fOwnColorMap;
188 fOwnColorMap = NULL;
190 // set
191 fColorMap = colorMap;
192 fCStatus = (fColorMap ? B_OK : B_BAD_VALUE);
193 return fCStatus;
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.
202 status_t
203 PaletteConverter::InitCheck() const
205 return fCStatus;
209 /*! \brief Returns the palette color index closest to a given RGB 15 color.
211 The object must be properly initialized.
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.
216 inline
217 uint8
218 PaletteConverter::IndexForRGB15(uint16 rgb) const
220 return fColorMap->index_map[rgb];
224 /*! \brief Returns the palette color index closest to a given RGB 15 color.
226 The object must be properly initialized.
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.
233 inline
234 uint8
235 PaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const
237 // the 5 least significant bits are used
238 return fColorMap->index_map[(red << 10) | (green << 5) | blue];
242 /*! \brief Returns the palette color index closest to a given RGB 16 color.
244 The object must be properly initialized.
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.
249 inline
250 uint8
251 PaletteConverter::IndexForRGB16(uint16 rgb) const
253 return fColorMap->index_map[((rgb >> 1) & 0x7fe0) | (rgb & 0x1f)];
257 /*! \brief Returns the palette color index closest to a given RGB 16 color.
259 The object must be properly initialized.
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.
266 inline
267 uint8
268 PaletteConverter::IndexForRGB16(uint8 red, uint8 green, uint8 blue) const
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];
275 /*! \brief Returns the palette color index closest to a given RGB 32 color.
277 The object must be properly initialized.
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.
282 inline
283 uint8
284 PaletteConverter::IndexForRGB24(uint32 rgb) const
286 return fColorMap->index_map[((rgb & 0xf8000000) >> 17)
287 | ((rgb & 0xf80000) >> 14)
288 | ((rgb & 0xf800) >> 11)];
292 /*! \brief Returns the palette color index closest to a given RGB 24 color.
294 The object must be properly initialized.
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.
301 inline
302 uint8
303 PaletteConverter::IndexForRGB24(uint8 red, uint8 green, uint8 blue) const
305 return fColorMap->index_map[((red & 0xf8) << 7)
306 | ((green & 0xf8) << 2)
307 | (blue >> 3)];
311 /*! \brief Returns the palette color index closest to a given RGBA 32 color.
313 The object must be properly initialized.
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.
318 inline
319 uint8
320 PaletteConverter::IndexForRGBA32(uint32 rgba) const
322 if ((rgba & 0x000000ff) < 128)
323 return B_TRANSPARENT_MAGIC_CMAP8;
324 return IndexForRGB24(rgba);
328 /*! \brief Returns the palette color index closest to a given Gray 8 color.
330 The object must be properly initialized.
332 \param gray The Gray 8 color value.
333 \return The palette color index for the supplied color.
335 inline
336 uint8
337 PaletteConverter::IndexForGray(uint8 gray) const
339 return IndexForRGB24(gray, gray, gray);
343 /*! \brief Returns the RGB color for a given palette color index.
345 The object must be properly initialized.
347 \param index The palette color index.
348 \return The color for the supplied palette color index.
350 inline
351 const rgb_color &
352 PaletteConverter::RGBColorForIndex(uint8 index) const
354 return fColorMap->color_list[index];
358 /*! \brief Returns the RGB 15 color for a given palette color index.
360 The object must be properly initialized.
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]).
366 inline
367 uint16
368 PaletteConverter::RGB15ColorForIndex(uint8 index) const
370 const rgb_color &color = fColorMap->color_list[index];
371 return ((color.red & 0xf8) << 7)
372 | ((color.green & 0xf8) << 2)
373 | (color.blue >> 3);
377 /*! \brief Returns the RGB 16 color for a given palette color index.
379 The object must be properly initialized.
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]).
385 inline
386 uint16
387 PaletteConverter::RGB16ColorForIndex(uint8 index) const
389 const rgb_color &color = fColorMap->color_list[index];
390 return ((color.red & 0xf8) << 8)
391 | ((color.green & 0xfc) << 3)
392 | (color.blue >> 3);
396 /*! \brief Returns the RGBA 32 color for a given palette color index.
398 The object must be properly initialized.
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]).
404 inline
405 uint32
406 PaletteConverter::RGBA32ColorForIndex(uint8 index) const
408 const rgb_color &color = fColorMap->color_list[index];
409 return (color.red << 16) | (color.green << 8) | color.blue
410 | (color.alpha << 24);
414 /*! \brief Returns the RGBA 32 color for a given palette color index.
416 The object must be properly initialized.
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.
428 inline
429 void
430 PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green,
431 uint8 &blue, uint8 &alpha) const
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;
441 /*! \brief Returns the Gray 8 color for a given palette color index.
443 The object must be properly initialized.
445 \param index The palette color index.
446 \return The color for the supplied palette color index.
448 inline
449 uint8
450 PaletteConverter::GrayColorForIndex(uint8 index) const
452 const rgb_color &color = fColorMap->color_list[index];
453 return brightness_for(color.red, color.green, color.blue);
457 static pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT;
458 static PaletteConverter sPaletteConverter;
461 /*! \brief Initialize the global instance of PaletteConverter using the system color palette.
462 \return B_OK.
464 /*static*/ status_t
465 PaletteConverter::InitializeDefault(bool useServer)
467 if (sPaletteConverter.InitCheck() != B_OK) {
468 pthread_once(&sPaletteConverterInitOnce,
469 useServer
470 ? &_InitializeDefaultAppServer
471 : &_InitializeDefaultNoAppServer);
474 return sPaletteConverter.InitCheck();
478 /*static*/ void
479 PaletteConverter::_InitializeDefaultAppServer()
481 sPaletteConverter.SetTo(system_colors());
485 /*static*/ void
486 PaletteConverter::_InitializeDefaultNoAppServer()
488 sPaletteConverter.SetTo(kSystemPalette);
492 typedef uint32 (readFunc)(const uint8 **source, int32 index);
493 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
496 void
497 WriteRGB24(uint8 **dest, uint8 *data, int32 index)
499 (*dest)[0] = data[0];
500 (*dest)[1] = data[1];
501 (*dest)[2] = data[2];
502 *dest += 3;
506 uint32
507 ReadRGB24(const uint8 **source, int32 index)
509 uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16);
510 *source += 3;
511 return result;
515 void
516 WriteGray8(uint8 **dest, uint8 *data, int32 index)
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)++;
525 uint32
526 ReadGray8(const uint8 **source, int32 index)
528 uint32 result = **source;
529 (*source)++;
530 return result;
534 void
535 WriteGray1(uint8 **dest, uint8 *data, int32 index)
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)++;
545 uint32
546 ReadGray1(const uint8 **source, int32 index)
548 int32 shift = 7 - (index % 8);
549 uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00;
550 if (shift == 0)
551 (*source)++;
552 return result;
556 void
557 WriteCMAP8(uint8 **dest, uint8 *data, int32 index)
559 **dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data);
560 (*dest)++;
564 uint32
565 ReadCMAP8(const uint8 **source, int32 index)
567 uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source);
568 (*source)++;
569 return result;
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)
584 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
585 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
587 int32 srcBitsPerRow = srcBytesPerRow << 3;
588 int32 dstBitsPerRow = dstBytesPerRow << 3;
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;
599 if (srcOffsetY < 0) {
600 dstOffsetY -= srcOffsetY;
601 height += srcOffsetY;
602 srcOffsetY = 0;
604 if (dstOffsetX < 0) {
605 srcOffsetX -= dstOffsetX;
606 dstOffsetX = 0;
608 if (dstOffsetY < 0) {
609 srcOffsetY -= dstOffsetY;
610 height += dstOffsetY;
611 dstOffsetY = 0;
614 srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX
615 * srcBitsPerPixel) >> 3));
616 dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX
617 * dstBitsPerPixel) >> 3));
619 // Ensure that the width fits
620 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
621 / srcBitsPerPixel;
622 if (srcWidth < width)
623 width = srcWidth;
625 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
626 / dstBitsPerPixel;
627 if (dstWidth < width)
628 width = dstWidth;
630 if (width < 0)
631 return B_OK;
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;
645 memcpy(dstBits, srcBits, copyCount);
647 srcBitsLength -= copyCount;
648 dstBitsLength -= copyCount;
649 srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow);
650 dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow);
652 if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd)
653 return B_OK;
656 return B_OK;
659 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3;
660 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3;
661 uint32 result;
662 uint32 source;
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;
670 if (srcFunc)
671 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++);
672 else {
673 source = *srcBits;
674 srcBits++;
677 // This is valid, as only 16 bit modes will need to swap
678 if (srcSwap)
679 source = (source << 8) | (source >> 8);
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;
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;
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;
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;
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;
716 // This is valid, as only 16 bit modes will need to swap
717 if (dstSwap)
718 result = (result << 8) | (result >> 8);
720 if (dstFunc)
721 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
722 else {
723 *dstBits = result;
724 dstBits++;
728 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
729 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
730 dstOffsetX -= width;
731 srcOffsetX -= width;
734 return B_OK;
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)
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
863 default:
864 return B_BAD_VALUE;
865 break;
868 return B_OK;
872 /*! \brief Converts a source buffer in one colorspace into a destination
873 buffer of another colorspace.
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.
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)
893 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength,
894 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace,
895 BPoint(0, 0), BPoint(0, 0), width, height);
899 /*! \brief Converts a source buffer in one colorspace into a destination
900 buffer of another colorspace.
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.
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)
922 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0
923 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0)
924 return B_BAD_VALUE;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1015 default:
1016 return B_BAD_VALUE;
1017 break;
1020 return B_OK;
1023 } // namespace BPrivate