2 * FreeRDP: A Remote Desktop Protocol Client
3 * Color Conversion Routines
5 * Copyright 2010 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
23 #include <freerdp/api.h>
24 #include <freerdp/freerdp.h>
25 #include <freerdp/codec/color.h>
26 #include <freerdp/utils/memory.h>
28 int freerdp_get_pixel(uint8 * data, int x, int y, int width, int height, int bpp)
39 width = (width + 7) / 8;
40 start = (y * width) + x / 8;
42 return (data[start] & (0x80 >> shift)) != 0;
44 return data[y * width + x];
47 src16 = (uint16*) data;
48 return src16[y * width + x];
50 data += y * width * 3;
55 return RGB24(red, green, blue);
57 src32 = (uint32*) data;
58 return src32[y * width + x];
66 void freerdp_set_pixel(uint8* data, int x, int y, int width, int height, int bpp, int pixel)
74 width = (width + 7) / 8;
75 start = (y * width) + x / 8;
78 data[start] = data[start] | (0x80 >> shift);
80 data[start] = data[start] & ~(0x80 >> shift);
85 dst32[y * width + x] = pixel;
89 INLINE void freerdp_color_split_rgb(uint32* color, int bpp, uint8* red, uint8* green, uint8* blue, uint8* alpha, HCLRCONV clrconv)
91 *red = *green = *blue = 0;
92 *alpha = (clrconv->alpha) ? 0xFF : 0x00;
99 GetARGB32(*alpha, *red, *green, *blue, *color);
103 GetRGB32(*red, *green, *blue, *color);
108 GetRGB24(*red, *green, *blue, *color);
112 GetRGB16(*red, *green, *blue, *color);
116 GetRGB15(*red, *green, *blue, *color);
121 *red = clrconv->palette->entries[*color].red;
122 *green = clrconv->palette->entries[*color].green;
123 *blue = clrconv->palette->entries[*color].blue;
140 INLINE void freerdp_color_split_bgr(uint32* color, int bpp, uint8* red, uint8* green, uint8* blue, uint8* alpha, HCLRCONV clrconv)
142 *red = *green = *blue = 0;
143 *alpha = (clrconv->alpha) ? 0xFF : 0x00;
150 GetABGR32(*alpha, *red, *green, *blue, *color);
154 GetBGR32(*red, *green, *blue, *color);
159 GetBGR24(*red, *green, *blue, *color);
163 GetBGR16(*red, *green, *blue, *color);
167 GetBGR15(*red, *green, *blue, *color);
172 *red = clrconv->palette->entries[*color].red;
173 *green = clrconv->palette->entries[*color].green;
174 *blue = clrconv->palette->entries[*color].blue;
191 INLINE void freerdp_color_make_rgb(uint32* color, int bpp, uint8* red, uint8* green, uint8* blue, uint8* alpha, HCLRCONV clrconv)
196 *color = ARGB32(*alpha, *red, *green, *blue);
200 *color = RGB24(*red, *green, *blue);
206 *color = RGB15(*red, *green, *blue);
210 *color = RGB16(*red, *green, *blue);
215 *color = RGB15(*red, *green, *blue);
219 *color = RGB24(*red, *green, *blue);
223 if ((*red != 0) || (*green != 0) || (*blue != 0))
232 INLINE void freerdp_color_make_bgr(uint32* color, int bpp, uint8* red, uint8* green, uint8* blue, uint8* alpha, HCLRCONV clrconv)
237 *color = ABGR32(*alpha, *red, *green, *blue);
241 *color = BGR24(*red, *green, *blue);
247 *color = BGR15(*red, *green, *blue);
251 *color = BGR16(*red, *green, *blue);
256 *color = BGR15(*red, *green, *blue);
260 *color = BGR24(*red, *green, *blue);
264 if ((*red != 0) || (*green != 0) || (*blue != 0))
273 uint32 freerdp_color_convert_rgb(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
281 freerdp_color_split_rgb(&srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
282 freerdp_color_make_rgb(&dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
287 uint32 freerdp_color_convert_bgr(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
295 freerdp_color_split_bgr(&srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
296 freerdp_color_make_bgr(&dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
301 uint32 freerdp_color_convert_rgb_bgr(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
309 freerdp_color_split_rgb(&srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
310 freerdp_color_make_bgr(&dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
315 uint32 freerdp_color_convert_bgr_rgb(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
323 freerdp_color_split_bgr(&srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv);
324 freerdp_color_make_rgb(&dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv);
329 uint32 freerdp_color_convert_var(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
332 return freerdp_color_convert_var_bgr(srcColor, srcBpp, dstBpp, clrconv);
334 return freerdp_color_convert_var_rgb(srcColor, srcBpp, dstBpp, clrconv);
337 uint32 freerdp_color_convert_var_rgb(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
340 return freerdp_color_convert_bgr_rgb(srcColor, srcBpp, 32, clrconv);
342 return freerdp_color_convert_rgb(srcColor, srcBpp, 32, clrconv);
345 uint32 freerdp_color_convert_var_bgr(uint32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
348 return freerdp_color_convert_bgr(srcColor, srcBpp, 32, clrconv);
350 return freerdp_color_convert_rgb_bgr(srcColor, srcBpp, 32, clrconv);
353 uint8* freerdp_image_convert_8bpp(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
367 dstData = (uint8*) malloc(width * height);
369 memcpy(dstData, srcData, width * height);
372 else if (dstBpp == 15 || (dstBpp == 16 && clrconv->rgb555))
375 dstData = (uint8*) malloc(width * height * 2);
377 dst16 = (uint16 *) dstData;
378 for (i = width * height; i > 0; i--)
382 red = clrconv->palette->entries[pixel].red;
383 green = clrconv->palette->entries[pixel].green;
384 blue = clrconv->palette->entries[pixel].blue;
385 pixel = (clrconv->invert) ? BGR15(red, green, blue) : RGB15(red, green, blue);
391 else if (dstBpp == 16)
394 dstData = (uint8*) malloc(width * height * 2);
396 dst16 = (uint16 *) dstData;
397 for (i = width * height; i > 0; i--)
401 red = clrconv->palette->entries[pixel].red;
402 green = clrconv->palette->entries[pixel].green;
403 blue = clrconv->palette->entries[pixel].blue;
404 pixel = (clrconv->invert) ? BGR16(red, green, blue) : RGB16(red, green, blue);
410 else if (dstBpp == 32)
413 dstData = (uint8*) malloc(width * height * 4);
415 src8 = (uint8*) srcData;
416 dst32 = (uint32*) dstData;
417 for (i = width * height; i > 0; i--)
421 red = clrconv->palette->entries[pixel].red;
422 green = clrconv->palette->entries[pixel].green;
423 blue = clrconv->palette->entries[pixel].blue;
424 pixel = (clrconv->invert) ? RGB32(red, green, blue) : BGR32(red, green, blue);
434 uint8* freerdp_image_convert_15bpp(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
445 if (dstBpp == 15 || (dstBpp == 16 && clrconv->rgb555))
448 dstData = (uint8*) malloc(width * height * 2);
450 memcpy(dstData, srcData, width * height * 2);
454 else if (dstBpp == 32)
457 dstData = (uint8*) malloc(width * height * 4);
459 src16 = (uint16 *) srcData;
460 dst32 = (uint32 *) dstData;
461 for (i = width * height; i > 0; i--)
465 GetBGR15(red, green, blue, pixel);
466 pixel = (clrconv->invert) ? RGB32(red, green, blue) : BGR32(red, green, blue);
472 else if (dstBpp == 16)
475 dstData = (uint8*) malloc(width * height * 2);
477 src16 = (uint16 *) srcData;
478 dst16 = (uint16 *) dstData;
479 for (i = width * height; i > 0; i--)
483 GetRGB_555(red, green, blue, pixel);
484 RGB_555_565(red, green, blue);
485 pixel = (clrconv->invert) ? BGR565(red, green, blue) : RGB565(red, green, blue);
495 uint8* freerdp_image_convert_16bpp(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
498 return freerdp_image_convert_15bpp(srcData, dstData, width, height, srcBpp, dstBpp, clrconv);
503 dstData = (uint8*) malloc(width * height * 2);
508 uint8 red, green, blue;
509 uint16* src16 = (uint16 *) srcData;
510 uint16* dst16 = (uint16 *) dstData;
512 for (i = width * height; i > 0; i--)
514 GetRGB_565(red, green, blue, (*src16));
515 RGB_565_555(red, green, blue);
516 (*dst16) = (clrconv->invert) ? BGR555(red, green, blue) : RGB555(red, green, blue);
523 memcpy(dstData, srcData, width * height * 2);
528 else if (dstBpp == 24)
533 uint8 red, green, blue;
536 dstData = (uint8*) malloc(width * height * 3);
538 dst8 = (uint8*) dstData;
539 src16 = (uint16*) srcData;
541 for (i = width * height; i > 0; i--)
543 GetBGR16(red, green, blue, *src16);
561 else if (dstBpp == 32)
567 uint8 red, green, blue;
570 dstData = (uint8*) malloc(width * height * 4);
572 src16 = (uint16*) srcData;
573 dst32 = (uint32*) dstData;
575 for (i = width * height; i > 0; i--)
579 GetBGR16(red, green, blue, pixel);
580 pixel = (clrconv->invert) ? RGB32(red, green, blue) : BGR32(red, green, blue);
590 uint8* freerdp_image_convert_24bpp(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
598 dstData = (uint8*) malloc(width * height * 4);
601 for (i = width * height; i > 0; i--)
603 *(dstp++) = *(srcData++);
604 *(dstp++) = *(srcData++);
605 *(dstp++) = *(srcData++);
614 uint8* freerdp_image_convert_32bpp(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
621 uint8 red, green, blue;
624 dstData = (uint8*) malloc(width * height * 2);
626 dst16 = (uint16*) dstData;
627 src32 = (uint32*) srcData;
629 for (index = 0; index < width * height; index++)
631 GetBGR32(blue, green, red, *src32);
632 *dst16 = (clrconv->invert) ? BGR16(red, green, blue) : RGB16(red, green, blue);
638 else if (dstBpp == 24)
642 uint8 red, green, blue;
645 dstData = (uint8*) malloc(width * height * 3);
648 for (index = 0; index < width * height; index++)
651 green = *(srcData++);
671 else if (dstBpp == 32)
679 dstData = (uint8*) malloc(width * height * 4);
681 memcpy(dstData, srcData, width * height * 4);
684 for (y = 0; y < height; y++)
686 for (x = 0; x < width * 4; x += 4)
697 dstData = (uint8*) malloc(width * height * 4);
699 memcpy(dstData, srcData, width * height * 4);
708 p_freerdp_image_convert freerdp_image_convert_[5] =
711 freerdp_image_convert_8bpp,
712 freerdp_image_convert_16bpp,
713 freerdp_image_convert_24bpp,
714 freerdp_image_convert_32bpp
717 uint8* freerdp_image_convert(uint8* srcData, uint8* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
719 p_freerdp_image_convert _p_freerdp_image_convert = freerdp_image_convert_[IBPP(srcBpp)];
721 if (_p_freerdp_image_convert != NULL)
722 return _p_freerdp_image_convert(srcData, dstData, width, height, srcBpp, dstBpp, clrconv);
727 void freerdp_bitmap_flip(uint8 * src, uint8 * dst, int scanLineSz, int height)
731 uint8 * bottomLine = dst + (scanLineSz * (height - 1));
732 uint8 * topLine = src;
734 /* Special processing if called for flip-in-place. */
737 /* Allocate a scanline buffer.
738 * (FIXME: xmalloc / xfree below should be replaced by "get/put
739 * scanline buffer from a pool/Q of fixed buffers" to reuse
740 * fixed size buffers (of max scanline size (or adaptative?) )
741 * -- would be much faster).
743 uint8 * tmpBfr = xmalloc(scanLineSz);
744 int half = height / 2;
745 /* Flip buffer in place by line permutations through the temp
747 * Not that if height has an odd number of line, we don't need
748 * to move the center scanline anyway.
749 * Also note that in place flipping takes three memcpy() calls
750 * to process two scanlines while src to distinct dest would
751 * only requires two memcpy() calls for two scanlines.
754 for (i = 0; i < half ; i++)
756 memcpy(tmpBfr, topLine, scanLineSz);
757 memcpy(topLine, bottomLine, scanLineSz);
758 memcpy(bottomLine, tmpBfr, scanLineSz);
759 topLine += scanLineSz;
760 bottomLine -= scanLineSz;
765 /* Flip from source buffer to destination buffer. */
769 for (i = 0; i < height; i++)
771 memcpy(bottomLine, topLine, scanLineSz);
772 topLine += scanLineSz;
773 bottomLine -= scanLineSz;
779 uint8* freerdp_image_flip(uint8* srcData, uint8* dstData, int width, int height, int bpp)
783 scanline = width * (bpp / 8);
786 dstData = (uint8*) xmalloc(width * height * (bpp / 8));
788 freerdp_bitmap_flip(srcData, dstData, scanline, height);
792 uint8* freerdp_icon_convert(uint8* srcData, uint8* dstData, uint8* mask, int width, int height, int bpp, HCLRCONV clrconv)
802 data = freerdp_image_flip(srcData, dstData, width, height, bpp);
803 dstData = freerdp_image_convert(data, NULL, width, height, bpp, 32, clrconv);
807 icon = (uint32*) dstData;
811 for (y = 0; y < height; y++)
813 for (x = 0; x < width; x++)
816 bmask = mask[pixel / 8];
820 pmask = (bmask & 0x80) ? 0x00000000 : 0xFF000000;
834 uint8* freerdp_glyph_convert(int width, int height, uint8* data)
843 * converts a 1-bit-per-pixel glyph to a one-byte-per-pixel glyph:
844 * this approach uses a little more memory, but provides faster
845 * means of accessing individual pixels in blitting operations
848 scanline = (width + 7) / 8;
849 dstData = (uint8*) malloc(width * height);
850 memset(dstData, 0, width * height);
853 for (y = 0; y < height; y++)
855 srcp = data + (y * scanline);
857 for (x = 0; x < width; x++)
859 if ((*srcp & (0x80 >> (x % 8))) != 0)
863 if (((x + 1) % 8 == 0) && x != 0)
871 uint8* freerdp_mono_image_convert(uint8* srcData, int width, int height, int srcBpp, int dstBpp, uint32 bgcolor, uint32 fgcolor, HCLRCONV clrconv)
879 uint8 redBg, greenBg, blueBg;
880 uint8 redFg, greenFg, blueFg;
886 redBg = clrconv->palette->entries[bgcolor].red;
887 greenBg = clrconv->palette->entries[bgcolor].green;
888 blueBg = clrconv->palette->entries[bgcolor].blue;
891 redFg = clrconv->palette->entries[fgcolor].red;
892 greenFg = clrconv->palette->entries[fgcolor].green;
893 blueFg = clrconv->palette->entries[fgcolor].blue;
897 GetRGB16(redBg, greenBg, blueBg, bgcolor);
898 GetRGB16(redFg, greenFg, blueFg, fgcolor);
902 GetRGB15(redBg, greenBg, blueBg, bgcolor);
903 GetRGB15(redFg, greenFg, blueFg, fgcolor);
907 GetRGB32(redBg, greenBg, blueBg, bgcolor);
908 GetRGB32(redFg, greenFg, blueFg, fgcolor);
918 /* convert 15-bit colors to 16-bit colors */
919 RGB16_RGB15(redBg, greenBg, blueBg, bgcolor);
920 RGB16_RGB15(redFg, greenFg, blueFg, fgcolor);
927 /* convert 15-bit colors to 16-bit colors */
928 RGB15_RGB16(redBg, greenBg, blueBg, bgcolor);
929 RGB15_RGB16(redFg, greenFg, blueFg, fgcolor);
933 dstData = (uint8*) malloc(width * height * 2);
934 dst16 = (uint16*) dstData;
936 for (index = height; index > 0; index--)
938 /* each bit encodes a pixel */
940 for (bitIndex = 7; bitIndex >= 0; bitIndex--)
942 if ((bitMask >> bitIndex) & 0x01)
956 else if (dstBpp == 32)
958 dstData = (uint8*) malloc(width * height * 4);
959 dst32 = (uint32*) dstData;
961 for (index = height; index > 0; index--)
963 /* each bit encodes a pixel */
966 for (bitIndex = 7; bitIndex >= 0; bitIndex--)
968 if ((bitMask >> bitIndex) & 0x01)
970 *dst32 = (clrconv->invert) ? BGR32(redBg, greenBg, blueBg) : RGB32(redBg, greenBg, blueBg);
974 *dst32 = (clrconv->invert) ? BGR32(redFg, greenFg, blueFg) : RGB32(redFg, greenFg, blueFg);
986 void freerdp_alpha_cursor_convert(uint8* alphaData, uint8* xorMask, uint8* andMask, int width, int height, int bpp, HCLRCONV clrconv)
992 for (j = 0; j < height; j++)
994 jj = (bpp == 1) ? j : (height - 1) - j;
995 for (i = 0; i < width; i++)
997 xpixel = freerdp_get_pixel(xorMask, i, jj, width, height, bpp);
998 xpixel = freerdp_color_convert_rgb(xpixel, bpp, 32, clrconv);
999 apixel = freerdp_get_pixel(andMask, i, jj, width, height, 1);
1003 if ((xpixel & 0xffffff) == 0xffffff)
1005 /* use pattern (not solid black) for xor area */
1006 xpixel = (i & 1) == (j & 1);
1007 xpixel = xpixel ? 0xFFFFFF : 0;
1008 xpixel |= 0xFF000000;
1010 else if (xpixel == 0xFF000000)
1016 freerdp_set_pixel(alphaData, i, j, width, height, 32, xpixel);
1021 void freerdp_image_swap_color_order(uint8* data, int width, int height)
1027 pixel = (uint32*) data;
1029 for (y = 0; y < height; y++)
1031 for (x = 0; x < width; x++)
1033 GetARGB32(a, r, g, b, *pixel);
1034 *pixel = ABGR32(a, r, g, b);
1040 HCLRCONV freerdp_clrconv_new(uint32 flags)
1042 HCLRCONV clrconv = xnew(CLRCONV);
1044 clrconv->alpha = (flags & CLRCONV_ALPHA) ? true : false;
1045 clrconv->invert = (flags & CLRCONV_INVERT) ? true : false;
1046 clrconv->rgb555 = (flags & CLRCONV_RGB555) ? true : false;
1047 clrconv->palette = xnew(rdpPalette);
1052 void freerdp_clrconv_free(HCLRCONV clrconv)
1054 if (clrconv != NULL)
1056 if (clrconv->palette != NULL)
1057 xfree(clrconv->palette);