22 #include <freerdp/config.h>
28 #include <winpr/crt.h>
30 #include <freerdp/log.h>
31 #include <freerdp/freerdp.h>
32 #include <freerdp/primitives.h>
34 #if defined(WITH_CAIRO)
38 #if defined(WITH_SWSCALE)
39 #include <libswscale/swscale.h>
44 #define TAG FREERDP_TAG("color")
46 BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height,
const BYTE* WINPR_RESTRICT data)
53 const UINT32 scanline = (width + 7) / 8;
54 BYTE* dstData = (BYTE*)winpr_aligned_malloc(1ull * width * height, 16);
59 ZeroMemory(dstData, 1ULL * width * height);
62 for (UINT32 y = 0; y < height; y++)
64 const BYTE* srcp = &data[1ull * y * scanline];
66 for (UINT32 x = 0; x < width; x++)
68 if ((*srcp & (0x80 >> (x % 8))) != 0)
73 if (((x + 1) % 8 == 0) && x != 0)
81 BOOL freerdp_image_copy_from_monochrome(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
82 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
83 UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData,
84 UINT32 backColor, UINT32 foreColor,
85 const gdiPalette* WINPR_RESTRICT palette)
87 const UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
89 if (!pDstData || !pSrcData || !palette)
93 nDstStep = dstBytesPerPixel * nWidth;
95 const UINT32 monoStep = (nWidth + 7) / 8;
97 for (
size_t y = 0; y < nHeight; y++)
99 BYTE* pDstLine = &pDstData[((nYDst + y) * nDstStep)];
100 UINT32 monoBit = 0x80;
101 const BYTE* monoBits = &pSrcData[monoStep * y];
103 for (
size_t x = 0; x < nWidth; x++)
105 BYTE* pDstPixel = &pDstLine[((nXDst + x) * FreeRDPGetBytesPerPixel(DstFormat))];
106 BOOL monoPixel = (*monoBits & monoBit) ? TRUE : FALSE;
108 if (!(monoBit >>= 1))
115 FreeRDPWriteColor_int(pDstPixel, DstFormat, backColor);
117 FreeRDPWriteColor_int(pDstPixel, DstFormat, foreColor);
124 static INLINE UINT32 freerdp_image_inverted_pointer_color(UINT32 x, UINT32 y, UINT32 format)
136 BYTE fill = (x + y) & 1 ? 0x00 : 0xFF;
140 return FreeRDPGetColor(format, fill, fill, fill, 0xFF);
147 static void fill_gdi_palette_for_icon(
const BYTE* colorTable, UINT16 cbColorTable,
150 WINPR_ASSERT(palette);
152 palette->format = PIXEL_FORMAT_BGRX32;
153 ZeroMemory(palette->palette,
sizeof(palette->palette));
158 if ((cbColorTable % 4 != 0) || (cbColorTable / 4 > 256))
160 WLog_WARN(TAG,
"weird palette size: %u", cbColorTable);
164 for (UINT16 i = 0; i < cbColorTable / 4; i++)
166 palette->palette[i] = FreeRDPReadColor_int(&colorTable[4ULL * i], palette->format);
170 static INLINE UINT32 div_ceil(UINT32 a, UINT32 b)
172 return (a + (b - 1)) / b;
175 static INLINE UINT32 round_up(UINT32 a, UINT32 b)
177 return b * div_ceil(a, b);
180 BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
181 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT16 nWidth,
182 UINT16 nHeight,
const BYTE* WINPR_RESTRICT bitsColor,
183 UINT16 cbBitsColor,
const BYTE* WINPR_RESTRICT bitsMask,
184 UINT16 cbBitsMask,
const BYTE* WINPR_RESTRICT colorTable,
185 UINT16 cbColorTable, UINT32 bpp)
190 if (!pDstData || !bitsColor)
209 WLog_WARN(TAG,
"1bpp and 4bpp icons are not supported");
213 format = PIXEL_FORMAT_RGB8;
217 format = PIXEL_FORMAT_RGB15;
221 format = PIXEL_FORMAT_RGB24;
225 format = PIXEL_FORMAT_BGRA32;
229 WLog_WARN(TAG,
"invalid icon bpp: %" PRIu32, bpp);
234 if (cbBitsColor < nWidth * nHeight * FreeRDPGetBytesPerPixel(format))
237 fill_gdi_palette_for_icon(colorTable, cbColorTable, &palette);
238 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
239 bitsColor, format, 0, 0, 0, &palette, FREERDP_FLIP_VERTICAL))
243 if (FreeRDPColorHasAlpha(DstFormat) && cbBitsMask)
246 const BYTE* maskByte = NULL;
251 BYTE* dstBuf = pDstData;
252 UINT32 dstBpp = FreeRDPGetBytesPerPixel(DstFormat);
259 stride = round_up(div_ceil(nWidth, 8), 4);
261 for (UINT32 y = 0; y < nHeight; y++)
263 maskByte = &bitsMask[1ULL * stride * (nHeight - 1 - y)];
266 for (UINT32 x = 0; x < nWidth; x++)
269 BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF;
272 color = FreeRDPReadColor_int(dstBuf, DstFormat);
273 FreeRDPSplitColor(color, DstFormat, &r, &g, &b, NULL, &palette);
274 color = FreeRDPGetColor(DstFormat, r, g, b, alpha);
275 FreeRDPWriteColor_int(dstBuf, DstFormat, color);
291 static BOOL freerdp_image_copy_from_pointer_data_1bpp(
292 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
293 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
294 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp)
304 vFlip = (xorBpp == 1) ? FALSE : TRUE;
305 andStep = (nWidth + 7) / 8;
306 andStep += (andStep % 2);
308 if (!xorMask || (xorMaskLength == 0))
310 if (!andMask || (andMaskLength == 0))
313 xorStep = (nWidth + 7) / 8;
314 xorStep += (xorStep % 2);
316 if (xorStep * nHeight > xorMaskLength)
319 if (andStep * nHeight > andMaskLength)
322 for (UINT32 y = 0; y < nHeight; y++)
324 const BYTE* andBits = NULL;
325 const BYTE* xorBits = NULL;
326 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
327 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
328 xorBit = andBit = 0x80;
332 xorBits = &xorMask[1ULL * xorStep * y];
333 andBits = &andMask[1ULL * andStep * y];
337 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
338 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
341 for (UINT32 x = 0; x < nWidth; x++)
344 xorPixel = (*xorBits & xorBit) ? 1 : 0;
352 andPixel = (*andBits & andBit) ? 1 : 0;
360 if (!andPixel && !xorPixel)
361 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0xFF);
362 else if (!andPixel && xorPixel)
363 color = FreeRDPGetColor(DstFormat, 0xFF, 0xFF, 0xFF, 0xFF);
364 else if (andPixel && !xorPixel)
365 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0);
366 else if (andPixel && xorPixel)
367 color = freerdp_image_inverted_pointer_color(x, y, DstFormat);
369 FreeRDPWriteColor_int(pDstPixel, DstFormat, color);
370 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
377 static BOOL freerdp_image_copy_from_pointer_data_xbpp(
378 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
379 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
380 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
381 const gdiPalette* palette)
389 UINT32 dstBitsPerPixel = 0;
390 UINT32 xorBytesPerPixel = 0;
391 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
393 vFlip = (xorBpp == 1) ? FALSE : TRUE;
394 andStep = (nWidth + 7) / 8;
395 andStep += (andStep % 2);
397 if (!xorMask || (xorMaskLength == 0))
400 xorBytesPerPixel = xorBpp >> 3;
401 xorStep = 1ULL * nWidth * xorBytesPerPixel;
402 xorStep += (xorStep % 2);
404 if (xorBpp == 8 && !palette)
406 WLog_ERR(TAG,
"null palette in conversion from %" PRIu32
" bpp to %" PRIu32
" bpp", xorBpp,
411 if (xorStep * nHeight > xorMaskLength)
416 if (andStep * nHeight > andMaskLength)
420 for (UINT32 y = 0; y < nHeight; y++)
422 const BYTE* xorBits = NULL;
423 const BYTE* andBits = NULL;
424 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
425 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
431 andBits = &andMask[andStep * y];
433 xorBits = &xorMask[xorStep * y];
438 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
440 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
443 for (UINT32 x = 0; x < nWidth; x++)
445 UINT32 pixelFormat = 0;
450 pixelFormat = PIXEL_FORMAT_BGRA32;
451 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
453 else if (xorBpp == 16)
455 pixelFormat = PIXEL_FORMAT_RGB15;
456 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
458 else if (xorBpp == 8)
460 pixelFormat = palette->format;
461 xorPixel = palette->palette[xorBits[0]];
465 pixelFormat = PIXEL_FORMAT_BGR24;
466 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
469 xorPixel = FreeRDPConvertColor(xorPixel, pixelFormat, PIXEL_FORMAT_ARGB32, palette);
470 xorBits += xorBytesPerPixel;
475 andPixel = (*andBits & andBit) ? 1 : 0;
486 if (xorPixel == 0xFF000000)
487 xorPixel = 0x00000000;
488 else if (xorPixel == 0xFFFFFFFF)
489 xorPixel = freerdp_image_inverted_pointer_color(x, y, PIXEL_FORMAT_ARGB32);
492 color = FreeRDPConvertColor(xorPixel, PIXEL_FORMAT_ARGB32, DstFormat, palette);
493 FreeRDPWriteColor_int(pDstPixel, DstFormat, color);
494 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
509 BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
510 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
511 UINT32 nWidth, UINT32 nHeight,
512 const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
513 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
514 UINT32 xorBpp,
const gdiPalette* WINPR_RESTRICT palette)
516 UINT32 dstBitsPerPixel = 0;
517 UINT32 dstBytesPerPixel = 0;
518 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
519 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
522 nDstStep = dstBytesPerPixel * nWidth;
524 for (UINT32 y = nYDst; y < nHeight; y++)
526 BYTE* WINPR_RESTRICT pDstLine = &pDstData[y * nDstStep + nXDst * dstBytesPerPixel];
527 memset(pDstLine, 0, 1ull * dstBytesPerPixel * (nWidth - nXDst));
533 return freerdp_image_copy_from_pointer_data_1bpp(
534 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
535 xorMaskLength, andMask, andMaskLength, xorBpp);
541 return freerdp_image_copy_from_pointer_data_xbpp(
542 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
543 xorMaskLength, andMask, andMaskLength, xorBpp, palette);
546 WLog_ERR(TAG,
"failed to convert from %" PRIu32
" bpp to %" PRIu32
" bpp", xorBpp,
552 static INLINE BOOL overlapping(
const BYTE* pDstData, UINT32 nYDst, UINT32 nDstStep,
553 const BYTE* pSrcData, UINT32 nYSrc, UINT32 nSrcStep, UINT32 nHeight)
555 const uintptr_t src = (uintptr_t)pSrcData;
556 const uintptr_t srcstart = src + 1ULL * nSrcStep * nYSrc;
557 const uintptr_t srcend = srcstart + 1ULL * nSrcStep * nHeight;
558 const uintptr_t dst = (uintptr_t)pDstData;
559 const uintptr_t dststart = dst + 1ULL * nDstStep * nYDst;
560 const uintptr_t dstend = dststart + 1ULL * nDstStep * nHeight;
562 if ((dststart >= srcstart) && (dststart <= srcend))
565 if ((dstend >= srcstart) && (dstend <= srcend))
571 static INLINE BOOL freerdp_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
572 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
574 const BYTE* WINPR_RESTRICT pSrcData,
575 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
576 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
577 SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
580 const SSIZE_T srcByte = 3;
581 const SSIZE_T dstByte = 4;
583 for (SSIZE_T y = 0; y < nHeight; y++)
585 const BYTE* WINPR_RESTRICT srcLine =
586 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
587 BYTE* WINPR_RESTRICT dstLine =
588 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
590 for (SSIZE_T x = 0; x < nWidth; x++)
592 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
593 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
594 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
601 static INLINE BOOL freerdp_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
602 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
604 const BYTE* WINPR_RESTRICT pSrcData,
605 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
606 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
607 SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
610 const SSIZE_T srcByte = 4;
611 const SSIZE_T dstByte = 4;
613 for (SSIZE_T y = 0; y < nHeight; y++)
615 const BYTE* WINPR_RESTRICT srcLine =
616 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
617 BYTE* WINPR_RESTRICT dstLine =
618 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
620 for (SSIZE_T x = 0; x < nWidth; x++)
622 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
623 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
624 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
631 static INLINE BOOL freerdp_image_copy_generic(
632 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
633 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcFormat,
634 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
635 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
638 const SSIZE_T srcByte = 4;
639 const SSIZE_T dstByte = 4;
641 for (SSIZE_T y = 0; y < nHeight; y++)
643 const BYTE* WINPR_RESTRICT srcLine =
644 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
645 BYTE* WINPR_RESTRICT dstLine =
646 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
648 UINT32 color = FreeRDPReadColor_int(&srcLine[nXSrc * srcByte], SrcFormat);
649 UINT32 oldColor = color;
650 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
651 FreeRDPWriteColorIgnoreAlpha_int(&dstLine[nXDst * dstByte], DstFormat, dstColor);
652 for (SSIZE_T x = 1; x < nWidth; x++)
654 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
655 if (color == oldColor)
657 FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
663 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
664 FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
673 static INLINE BOOL freerdp_image_copy_no_overlap_dst_alpha(
674 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
675 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
676 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
677 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
679 WINPR_ASSERT(pDstData);
680 WINPR_ASSERT(pSrcData);
684 case PIXEL_FORMAT_BGR24:
687 case PIXEL_FORMAT_BGRX32:
688 case PIXEL_FORMAT_BGRA32:
689 return freerdp_image_copy_bgr24_bgrx32(
690 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
691 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
696 case PIXEL_FORMAT_BGRX32:
697 case PIXEL_FORMAT_BGRA32:
700 case PIXEL_FORMAT_BGRX32:
701 case PIXEL_FORMAT_BGRA32:
702 return freerdp_image_copy_bgrx32_bgrx32(
703 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
704 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
713 return freerdp_image_copy_generic(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
714 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
715 srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
718 BOOL freerdp_image_copy_overlap(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
719 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
const BYTE* pSrcData,
720 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
721 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
723 const UINT32 dstByte = FreeRDPGetBytesPerPixel(DstFormat);
724 const UINT32 srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
725 const UINT32 copyDstWidth = nWidth * dstByte;
726 const UINT32 xSrcOffset = nXSrc * srcByte;
727 const UINT32 xDstOffset = nXDst * dstByte;
728 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) ? TRUE : FALSE;
729 SSIZE_T srcVOffset = 0;
730 SSIZE_T srcVMultiplier = 1;
731 SSIZE_T dstVOffset = 0;
732 SSIZE_T dstVMultiplier = 1;
734 WINPR_ASSERT(overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
736 if ((nWidth == 0) || (nHeight == 0))
739 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
742 if (!pDstData || !pSrcData)
746 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
749 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
753 srcVOffset = (nHeight - 1ll) * nSrcStep;
757 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
759 return freerdp_image_copy_no_overlap_dst_alpha(
760 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
761 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
764 else if (FreeRDPAreColorFormatsEqualNoAlpha_int(SrcFormat, DstFormat))
769 for (SSIZE_T y = 0; y < nHeight; y++)
771 const BYTE* srcLine =
772 &pSrcData[(y + nYSrc) * nSrcStep * srcVMultiplier + srcVOffset];
773 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
774 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
778 else if (nYDst > nYSrc)
780 for (SSIZE_T y = nHeight - 1; y >= 0; y--)
782 const BYTE* srcLine =
783 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
784 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
785 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
789 else if (nXSrc > nXDst)
791 for (SSIZE_T y = 0; y < nHeight; y++)
793 const BYTE* srcLine =
794 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
795 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
796 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
800 else if (nXSrc < nXDst)
802 for (SSIZE_T y = nHeight - 1; y >= 0; y--)
804 const BYTE* srcLine =
805 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
806 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
807 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
817 for (SSIZE_T y = 0; y < nHeight; y++)
819 const BYTE* srcLine = &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
820 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
822 UINT32 color = FreeRDPReadColor_int(&srcLine[1ULL * nXSrc * srcByte], SrcFormat);
823 UINT32 oldColor = color;
824 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
825 FreeRDPWriteColor_int(&dstLine[1ULL * nXDst * dstByte], DstFormat, dstColor);
826 for (SSIZE_T x = 1; x < nWidth; x++)
828 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
829 if (color == oldColor)
831 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
836 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
837 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
846 BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
847 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
const BYTE* pSrcData,
848 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
849 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
851 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
854 if (!pDstData || !pSrcData)
857 if ((nWidth == 0) || (nHeight == 0))
861 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
864 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
866 const BOOL ovl = overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight);
868 return freerdp_image_copy_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
869 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
871 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
872 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
876 BOOL freerdp_image_fill(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
877 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color)
879 if ((nWidth == 0) || (nHeight == 0))
881 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
882 BYTE* WINPR_RESTRICT pFirstDstLine = NULL;
883 BYTE* WINPR_RESTRICT pFirstDstLineXOffset = NULL;
886 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
888 pFirstDstLine = &pDstData[1ULL * nYDst * nDstStep];
889 pFirstDstLineXOffset = &pFirstDstLine[1ULL * nXDst * bpp];
891 for (
size_t x = 0; x < nWidth; x++)
893 BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp];
894 FreeRDPWriteColor_int(pDst, DstFormat, color);
897 for (
size_t y = 1; y < nHeight; y++)
899 BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + 1ULL * nXDst * bpp];
900 memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp);
906 #if defined(WITH_SWSCALE)
907 static int av_format_for_buffer(UINT32 format)
911 case PIXEL_FORMAT_ARGB32:
912 return AV_PIX_FMT_BGRA;
914 case PIXEL_FORMAT_XRGB32:
915 return AV_PIX_FMT_BGR0;
917 case PIXEL_FORMAT_BGRA32:
918 return AV_PIX_FMT_RGBA;
920 case PIXEL_FORMAT_BGRX32:
921 return AV_PIX_FMT_RGB0;
924 return AV_PIX_FMT_NONE;
929 BOOL freerdp_image_scale(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
930 UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
931 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
932 UINT32 nXSrc, UINT32 nYSrc, UINT32 nSrcWidth, UINT32 nSrcHeight)
937 nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat);
940 nSrcStep = nSrcWidth * FreeRDPGetBytesPerPixel(SrcFormat);
942 #if defined(WITH_SWSCALE) || defined(WITH_CAIRO)
943 const BYTE* src = &pSrcData[nXSrc * FreeRDPGetBytesPerPixel(SrcFormat) + nYSrc * nSrcStep];
944 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
948 if ((nDstWidth == nSrcWidth) && (nDstHeight == nSrcHeight))
950 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
951 nDstHeight, pSrcData, SrcFormat, nSrcStep, nXSrc,
952 nYSrc, NULL, FREERDP_FLIP_NONE);
955 #if defined(WITH_SWSCALE)
958 struct SwsContext* resize = NULL;
959 int srcFormat = av_format_for_buffer(SrcFormat);
960 int dstFormat = av_format_for_buffer(DstFormat);
961 const int srcStep[1] = { (int)nSrcStep };
962 const int dstStep[1] = { (int)nDstStep };
964 if ((srcFormat == AV_PIX_FMT_NONE) || (dstFormat == AV_PIX_FMT_NONE))
967 resize = sws_getContext((
int)nSrcWidth, (
int)nSrcHeight, srcFormat, (
int)nDstWidth,
968 (
int)nDstHeight, dstFormat, SWS_BILINEAR, NULL, NULL, NULL);
973 res = sws_scale(resize, &src, srcStep, 0, (
int)nSrcHeight, &dst, dstStep);
974 rc = (res == ((int)nDstHeight));
976 sws_freeContext(resize);
979 #elif defined(WITH_CAIRO)
981 const double sx = (double)nDstWidth / (
double)nSrcWidth;
982 const double sy = (double)nDstHeight / (
double)nSrcHeight;
983 cairo_t* cairo_context;
984 cairo_surface_t *csrc, *cdst;
986 if ((nSrcWidth > INT_MAX) || (nSrcHeight > INT_MAX) || (nSrcStep > INT_MAX))
989 if ((nDstWidth > INT_MAX) || (nDstHeight > INT_MAX) || (nDstStep > INT_MAX))
992 csrc = cairo_image_surface_create_for_data((
void*)src, CAIRO_FORMAT_ARGB32, (
int)nSrcWidth,
993 (
int)nSrcHeight, (
int)nSrcStep);
994 cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, (
int)nDstWidth,
995 (
int)nDstHeight, (
int)nDstStep);
1000 cairo_context = cairo_create(cdst);
1005 cairo_scale(cairo_context, sx, sy);
1006 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
1007 cairo_set_source_surface(cairo_context, csrc, 0, 0);
1008 cairo_paint(cairo_context);
1011 cairo_destroy(cairo_context);
1013 cairo_surface_destroy(csrc);
1014 cairo_surface_destroy(cdst);
1018 WLog_WARN(TAG,
"SmartScaling requested but compiled without libcairo support!");
1024 DWORD FreeRDPAreColorFormatsEqualNoAlpha(DWORD first, DWORD second)
1026 return FreeRDPAreColorFormatsEqualNoAlpha_int(first, second);
1029 const char* FreeRDPGetColorFormatName(UINT32 format)
1034 case PIXEL_FORMAT_ARGB32:
1035 return "PIXEL_FORMAT_ARGB32";
1037 case PIXEL_FORMAT_XRGB32:
1038 return "PIXEL_FORMAT_XRGB32";
1040 case PIXEL_FORMAT_ABGR32:
1041 return "PIXEL_FORMAT_ABGR32";
1043 case PIXEL_FORMAT_XBGR32:
1044 return "PIXEL_FORMAT_XBGR32";
1046 case PIXEL_FORMAT_BGRA32:
1047 return "PIXEL_FORMAT_BGRA32";
1049 case PIXEL_FORMAT_BGRX32:
1050 return "PIXEL_FORMAT_BGRX32";
1052 case PIXEL_FORMAT_RGBA32:
1053 return "PIXEL_FORMAT_RGBA32";
1055 case PIXEL_FORMAT_RGBX32:
1056 return "PIXEL_FORMAT_RGBX32";
1058 case PIXEL_FORMAT_BGRX32_DEPTH30:
1059 return "PIXEL_FORMAT_BGRX32_DEPTH30";
1061 case PIXEL_FORMAT_RGBX32_DEPTH30:
1062 return "PIXEL_FORMAT_RGBX32_DEPTH30";
1065 case PIXEL_FORMAT_RGB24:
1066 return "PIXEL_FORMAT_RGB24";
1068 case PIXEL_FORMAT_BGR24:
1069 return "PIXEL_FORMAT_BGR24";
1072 case PIXEL_FORMAT_RGB16:
1073 return "PIXEL_FORMAT_RGB16";
1075 case PIXEL_FORMAT_BGR16:
1076 return "PIXEL_FORMAT_BGR16";
1078 case PIXEL_FORMAT_ARGB15:
1079 return "PIXEL_FORMAT_ARGB15";
1081 case PIXEL_FORMAT_RGB15:
1082 return "PIXEL_FORMAT_RGB15";
1084 case PIXEL_FORMAT_ABGR15:
1085 return "PIXEL_FORMAT_ABGR15";
1087 case PIXEL_FORMAT_BGR15:
1088 return "PIXEL_FORMAT_BGR15";
1091 case PIXEL_FORMAT_RGB8:
1092 return "PIXEL_FORMAT_RGB8";
1095 case PIXEL_FORMAT_A4:
1096 return "PIXEL_FORMAT_A4";
1099 case PIXEL_FORMAT_MONO:
1100 return "PIXEL_FORMAT_MONO";
1107 void FreeRDPSplitColor(UINT32 color, UINT32 format, BYTE* _r, BYTE* _g, BYTE* _b, BYTE* _a,
1108 const gdiPalette* palette)
1115 case PIXEL_FORMAT_ARGB32:
1117 *_a = (BYTE)(color >> 24);
1120 *_r = (BYTE)(color >> 16);
1123 *_g = (BYTE)(color >> 8);
1130 case PIXEL_FORMAT_XRGB32:
1132 *_r = (BYTE)(color >> 16);
1135 *_g = (BYTE)(color >> 8);
1145 case PIXEL_FORMAT_ABGR32:
1147 *_a = (BYTE)(color >> 24);
1150 *_b = (BYTE)(color >> 16);
1153 *_g = (BYTE)(color >> 8);
1160 case PIXEL_FORMAT_XBGR32:
1162 *_b = (BYTE)(color >> 16);
1165 *_g = (BYTE)(color >> 8);
1175 case PIXEL_FORMAT_RGBA32:
1177 *_r = (BYTE)(color >> 24);
1180 *_g = (BYTE)(color >> 16);
1183 *_b = (BYTE)(color >> 8);
1190 case PIXEL_FORMAT_RGBX32:
1192 *_r = (BYTE)(color >> 24);
1195 *_g = (BYTE)(color >> 16);
1198 *_b = (BYTE)(color >> 8);
1205 case PIXEL_FORMAT_BGRA32:
1207 *_b = (BYTE)(color >> 24);
1210 *_g = (BYTE)(color >> 16);
1213 *_r = (BYTE)(color >> 8);
1220 case PIXEL_FORMAT_BGRX32:
1222 *_b = (BYTE)(color >> 24);
1225 *_g = (BYTE)(color >> 16);
1228 *_r = (BYTE)(color >> 8);
1236 case PIXEL_FORMAT_RGB24:
1238 *_r = (BYTE)(color >> 16);
1241 *_g = (BYTE)(color >> 8);
1251 case PIXEL_FORMAT_BGR24:
1253 *_b = (BYTE)(color >> 16);
1256 *_g = (BYTE)(color >> 8);
1267 case PIXEL_FORMAT_RGB16:
1270 const UINT32 c = (color >> 11) & 0x1F;
1271 const UINT32 val = (c << 3) + c / 4;
1272 *_r = (BYTE)(val > 255 ? 255 : val);
1277 const UINT32 c = (color >> 5) & 0x3F;
1278 const UINT32 val = (c << 2) + c / 4 / 2;
1279 *_g = (BYTE)(val > 255 ? 255 : val);
1284 const UINT32 c = (color)&0x1F;
1285 const UINT32 val = (c << 3) + c / 4;
1286 *_b = (BYTE)(val > 255 ? 255 : val);
1294 case PIXEL_FORMAT_BGR16:
1297 const UINT32 c = (color)&0x1F;
1298 const UINT32 val = (c << 3) + c / 4;
1299 *_r = (BYTE)(val > 255 ? 255 : val);
1304 const UINT32 c = (color >> 5) & 0x3F;
1305 const UINT32 val = (c << 2) + c / 4 / 2;
1306 *_g = (BYTE)(val > 255 ? 255 : val);
1311 const UINT32 c = (color >> 11) & 0x1F;
1312 const UINT32 val = (c << 3) + c / 4;
1313 *_b = (BYTE)(val > 255 ? 255 : val);
1321 case PIXEL_FORMAT_ARGB15:
1324 const UINT32 c = (color >> 10) & 0x1F;
1325 const UINT32 val = (c << 3) + c / 4;
1326 *_r = (BYTE)(val > 255 ? 255 : val);
1331 const UINT32 c = (color >> 5) & 0x1F;
1332 const UINT32 val = (c << 3) + c / 4;
1333 *_g = (BYTE)(val > 255 ? 255 : val);
1338 const UINT32 c = (color)&0x1F;
1339 const UINT32 val = (c << 3) + c / 4;
1340 *_b = (BYTE)(val > 255 ? 255 : val);
1344 *_a = color & 0x8000 ? 0xFF : 0x00;
1348 case PIXEL_FORMAT_ABGR15:
1351 const UINT32 c = (color)&0x1F;
1352 const UINT32 val = (c << 3) + c / 4;
1353 *_r = (BYTE)(val > 255 ? 255 : val);
1358 const UINT32 c = (color >> 5) & 0x1F;
1359 const UINT32 val = (c << 3) + c / 4;
1360 *_g = (BYTE)(val > 255 ? 255 : val);
1365 const UINT32 c = (color >> 10) & 0x1F;
1366 const UINT32 val = (c << 3) + c / 4;
1367 *_b = (BYTE)(val > 255 ? 255 : val);
1371 *_a = color & 0x8000 ? 0xFF : 0x00;
1376 case PIXEL_FORMAT_RGB15:
1379 const UINT32 c = (color >> 10) & 0x1F;
1380 const UINT32 val = (c << 3) + c / 4;
1381 *_r = (BYTE)(val > 255 ? 255 : val);
1386 const UINT32 c = (color >> 5) & 0x1F;
1387 const UINT32 val = (c << 3) + c / 4;
1388 *_g = (BYTE)(val > 255 ? 255 : val);
1393 const UINT32 c = (color)&0x1F;
1394 const UINT32 val = (c << 3) + c / 4;
1395 *_b = (BYTE)(val > 255 ? 255 : val);
1403 case PIXEL_FORMAT_BGR15:
1406 const UINT32 c = (color)&0x1F;
1407 const UINT32 val = (c << 3) + c / 4;
1408 *_r = (BYTE)(val > 255 ? 255 : val);
1413 const UINT32 c = (color >> 5) & 0x1F;
1414 const UINT32 val = (c << 3) + c / 4;
1415 *_g = (BYTE)(val > 255 ? 255 : val);
1420 const UINT32 c = (color >> 10) & 0x1F;
1421 const UINT32 val = (c << 3) + c / 4;
1422 *_b = (BYTE)(val > 255 ? 255 : val);
1431 case PIXEL_FORMAT_RGB8:
1434 tmp = palette->palette[color];
1435 FreeRDPSplitColor(tmp, palette->format, _r, _g, _b, _a, NULL);
1455 case PIXEL_FORMAT_MONO:
1457 *_r = (color) ? 0xFF : 0x00;
1460 *_g = (color) ? 0xFF : 0x00;
1463 *_b = (color) ? 0xFF : 0x00;
1466 *_a = (color) ? 0xFF : 0x00;
1471 case PIXEL_FORMAT_A4:
1485 WLog_ERR(TAG,
"Unsupported format %s", FreeRDPGetColorFormatName(format));
1490 BOOL FreeRDPWriteColorIgnoreAlpha(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1492 return FreeRDPWriteColorIgnoreAlpha_int(dst, format, color);
1495 BOOL FreeRDPWriteColor(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1497 return FreeRDPWriteColor_int(dst, format, color);
1500 UINT32 FreeRDPReadColor(
const BYTE* WINPR_RESTRICT src, UINT32 format)
1502 return FreeRDPReadColor_int(src, format);
1505 UINT32 FreeRDPGetColor(UINT32 format, BYTE r, BYTE g, BYTE b, BYTE a)
1516 case PIXEL_FORMAT_ARGB32:
1517 return (_a << 24) | (_r << 16) | (_g << 8) | _b;
1519 case PIXEL_FORMAT_XRGB32:
1520 return (_r << 16) | (_g << 8) | _b;
1522 case PIXEL_FORMAT_ABGR32:
1523 return (_a << 24) | (_b << 16) | (_g << 8) | _r;
1525 case PIXEL_FORMAT_XBGR32:
1526 return (_b << 16) | (_g << 8) | _r;
1528 case PIXEL_FORMAT_RGBA32:
1529 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1531 case PIXEL_FORMAT_RGBX32:
1532 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1534 case PIXEL_FORMAT_BGRA32:
1535 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1537 case PIXEL_FORMAT_BGRX32:
1538 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1540 case PIXEL_FORMAT_RGBX32_DEPTH30:
1542 t = (_r << 22) | (_g << 12) | (_b << 2);
1544 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1547 case PIXEL_FORMAT_BGRX32_DEPTH30:
1549 t = (_r << 22) | (_g << 12) | (_b << 2);
1551 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1555 case PIXEL_FORMAT_RGB24:
1556 return (_r << 16) | (_g << 8) | _b;
1558 case PIXEL_FORMAT_BGR24:
1559 return (_b << 16) | (_g << 8) | _r;
1562 case PIXEL_FORMAT_RGB16:
1563 return (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_b >> 3) & 0x1F);
1565 case PIXEL_FORMAT_BGR16:
1566 return (((_b >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_r >> 3) & 0x1F);
1568 case PIXEL_FORMAT_ARGB15:
1569 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F) |
1570 (_a ? 0x8000 : 0x0000);
1572 case PIXEL_FORMAT_ABGR15:
1573 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F) |
1574 (_a ? 0x8000 : 0x0000);
1577 case PIXEL_FORMAT_RGB15:
1578 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F);
1580 case PIXEL_FORMAT_BGR15:
1581 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F);
1584 case PIXEL_FORMAT_RGB8:
1587 case PIXEL_FORMAT_A4:
1590 case PIXEL_FORMAT_MONO:
1592 WLog_ERR(TAG,
"Unsupported format %s", FreeRDPGetColorFormatName(format));
1597 BOOL freerdp_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1598 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
1599 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
1600 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1601 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1605 prims = primitives_get();
1607 WINPR_ASSERT(!overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
1608 WINPR_ASSERT(prims);
1610 return prims->
copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
1611 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
1612 flags) == PRIMITIVES_SUCCESS;
__copy_no_overlap_t copy_no_overlap