FreeRDP
Loading...
Searching...
No Matches
color.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <winpr/crt.h>
29
30#include <freerdp/log.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/primitives.h>
33
34#if defined(WITH_CAIRO)
35#include <cairo.h>
36#endif
37
38#if defined(WITH_SWSCALE)
39#include "image_ffmpeg.h"
40#endif
41
42#include "color.h"
43
44#define TAG FREERDP_TAG("color")
45
46static BOOL freerdp_image_copy_from_pointer_data_int(
47 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
48 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
49 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
50 const gdiPalette* WINPR_RESTRICT palette);
51
52#if defined(WITH_CURSOR_DUMP)
53#include <winpr/path.h>
54#include <winpr/image.h>
55
56WINPR_ATTR_MALLOC(free, 1)
57static char* get_dump_name(char* prefix, size_t len)
58{
59 static uint64_t count = 0;
60 if (_snprintf(prefix, len, "cursor_dump_%08" PRIx64, count++) < 0)
61 return nullptr;
62
63 return GetCombinedPath(CURSOR_DUMP_DIR, prefix);
64}
65
66static void dump_binary_data(FILE* fp, const uint8_t* data, size_t len)
67{
68 if (len > 0)
69 (void)fprintf(fp, "0x%02" PRIx8, data[0]);
70 for (size_t x = 1; x < len; x++)
71 {
72 (void)fprintf(fp, ", 0x%02" PRIx8, data[x]);
73 }
74}
75
76static void dump_uint_data(FILE* fp, const uint32_t* data, size_t len)
77{
78 if (len > 0)
79 (void)fprintf(fp, "0x%08" PRIx32, data[0]);
80 for (size_t x = 1; x < len; x++)
81 {
82 (void)fprintf(fp, ", 0x%08" PRIx32, data[x]);
83 }
84}
85
86static void dump_write_header(const char* path, const char* prefix)
87{
88 char* header = nullptr;
89 size_t headerlen = 0;
90 winpr_asprintf(&header, &headerlen, "%s.h", path);
91 if (!header)
92 return;
93 FILE* fp = fopen(header, "w");
94 free(header);
95
96 if (!fp)
97 return;
98
99 (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n");
100 (void)fprintf(fp, " * this file was auto generated by %s\n", __func__);
101 (void)fprintf(fp, " * do not modify manually\n");
102 (void)fprintf(fp, " */\n");
103 (void)fprintf(fp, "\n");
104 (void)fprintf(fp, "#pragma once\n");
105 (void)fprintf(fp, "\n");
106 (void)fprintf(fp, "#include <freerdp/codec/color.h>\n");
107 (void)fprintf(fp, "#include <freerdp/graphics.h>\n");
108 (void)fprintf(fp, "\n");
109 (void)fprintf(fp, "extern const gdiPalette %s_palette;\n", prefix);
110 (void)fprintf(fp, "extern const rdpPointer %s_pointer;\n", prefix);
111 (void)fprintf(fp, "extern const uint8_t %s_image_bgra32[];\n", prefix);
112 fclose(fp);
113}
114
115static void dump_write_c_file(const char* path, const char* prefix, UINT32 nXDst, UINT32 nYDst,
116 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask,
117 UINT32 xorMaskLength, const BYTE* WINPR_RESTRICT andMask,
118 UINT32 andMaskLength, UINT32 xorBpp, const gdiPalette* palette,
119 const uint8_t* bmp)
120{
121 const uint32_t format = PIXEL_FORMAT_BGRA32;
122 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
123 const uint32_t step = nWidth * bpp;
124
125 char* header = nullptr;
126 size_t headerlen = 0;
127 winpr_asprintf(&header, &headerlen, "%s.c", path);
128 if (!header)
129 return;
130 FILE* fp = fopen(header, "w");
131 free(header);
132
133 if (fp)
134 {
135 (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n");
136 (void)fprintf(fp, " * this file was auto generated by %s\n", __func__);
137 (void)fprintf(fp, " * do not modify manually\n");
138 (void)fprintf(fp, " */\n");
139 (void)fprintf(fp, "\n");
140 (void)fprintf(fp, "#include \"%s.h\"\n", prefix);
141 (void)fprintf(fp, "\n");
142
143 (void)fprintf(fp, "static const uint8_t andmask[] = {\n");
144 dump_binary_data(fp, andMask, andMaskLength);
145 (void)fprintf(fp, "};\n");
146 (void)fprintf(fp, "\n");
147
148 (void)fprintf(fp, "static const uint8_t xormask[] = {\n");
149 dump_binary_data(fp, xorMask, xorMaskLength);
150 (void)fprintf(fp, "};\n");
151 (void)fprintf(fp, "\n");
152 (void)fprintf(fp, "const gdiPalette %s_palette = {\n", prefix);
153 if (palette)
154 {
155 (void)fprintf(fp, ".format=%" PRIu32 ",", palette->format);
156 (void)fprintf(fp, ".palette={");
157 dump_uint_data(fp, palette->palette, ARRAYSIZE(palette->palette));
158 (void)fprintf(fp, "}\n");
159 }
160 else
161 (void)fprintf(fp, "0");
162
163 (void)fprintf(fp, "};\n");
164
165 (void)fprintf(fp, "\n");
166 (void)fprintf(fp, "const rdpPointer %s_pointer = {\n", prefix);
167 (void)fprintf(fp, ".size = 0,\n");
168 (void)fprintf(fp, ".New = nullptr,\n");
169 (void)fprintf(fp, ".Free = nullptr,\n");
170 (void)fprintf(fp, ".Set = nullptr,\n");
171 (void)fprintf(fp, ".SetNull = nullptr,\n");
172 (void)fprintf(fp, ".SetDefault = nullptr,\n");
173 (void)fprintf(fp, ".SetPosition = nullptr,\n");
174 (void)fprintf(fp, ".paddingA = {0},\n");
175 (void)fprintf(fp, ".xPos = %" PRIu32 ",\n", nXDst);
176 (void)fprintf(fp, ".yPos = %" PRIu32 ",\n", nYDst);
177 (void)fprintf(fp, ".width = %" PRIu32 ",\n", nWidth);
178 (void)fprintf(fp, ".height = %" PRIu32 ",\n", nHeight);
179 (void)fprintf(fp, ".xorBpp = %" PRIu32 ",\n", xorBpp);
180 (void)fprintf(fp, ".lengthAndMask = ARRAYSIZE(andmask),\n");
181 (void)fprintf(fp, ".lengthXorMask = ARRAYSIZE(xormask),\n");
182 (void)fprintf(fp, ".xorMaskData = xormask,\n");
183 (void)fprintf(fp, ".andMaskData = andmask,\n");
184 (void)fprintf(fp, ".paddingB = {0}\n");
185 (void)fprintf(fp, "};\n");
186 (void)fprintf(fp, "\n");
187 (void)fprintf(fp, "const uint8_t %s_image_bgra32[]={\n", prefix);
188 dump_binary_data(fp, bmp, step * nHeight);
189 (void)fprintf(fp, "};\n");
190 fclose(fp);
191 }
192
193 wImage* img = winpr_image_new();
194 if (img)
195 {
196 img->data = WINPR_CAST_CONST_PTR_AWAY(bmp, BYTE*);
197 img->bitsPerPixel = 32;
198 img->bytesPerPixel = 4;
199 img->height = nHeight;
200 img->width = nWidth;
201 img->scanline = step;
202 img->type = WINPR_IMAGE_PNG;
203 char* imgname = nullptr;
204 size_t imgnamesize = 0;
205 winpr_asprintf(&imgname, &imgnamesize, "%s.png", path);
206 if (imgname)
207 winpr_image_write(img, imgname);
208 free(imgname);
209 winpr_image_free(img, FALSE);
210 }
211}
212
218static void dump_pointer_data(UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
219 const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
220 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
221 UINT32 xorBpp, const gdiPalette* palette)
222{
223 const uint32_t format = PIXEL_FORMAT_BGRA32;
224 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
225 const uint32_t step = nWidth * bpp;
226 BYTE* bmp = calloc(step * 2, nHeight);
227 char prefix[64] = WINPR_C_ARRAY_INIT;
228 char* path = get_dump_name(prefix, sizeof(prefix));
229
230 if (!bmp || !path)
231 goto fail;
232
233 if (!freerdp_image_copy_from_pointer_data_int(bmp, format, step, 0, 0, nWidth, nHeight, xorMask,
234 xorMaskLength, andMask, andMaskLength, xorBpp,
235 palette))
236 goto fail;
237
238 dump_write_header(path, prefix);
239 dump_write_c_file(path, prefix, nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask,
240 andMaskLength, xorBpp, palette, bmp);
241
242fail:
243 free(bmp);
244 free(path);
245}
246#endif
247
248#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
249BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data)
250{
251 const size_t scanline = (width + 7ull) / 8ull;
252 const size_t required = scanline * height;
253 return freerdp_glyph_convert_ex(width, height, data, required);
254}
255#endif
256
257BYTE* freerdp_glyph_convert_ex(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data,
258 size_t len)
259{
260 /*
261 * converts a 1-bit-per-pixel glyph to a one-byte-per-pixel glyph:
262 * this approach uses a little more memory, but provides faster
263 * means of accessing individual pixels in blitting operations
264 */
265 const size_t scanline = (width + 7ull) / 8ull;
266 const size_t required = scanline * height;
267 if (len < required)
268 return nullptr;
269
270 if ((len == 0) || (width == 0) || (height == 0))
271 return nullptr;
272
273 WINPR_ASSERT(data);
274
275 BYTE* dstData = (BYTE*)winpr_aligned_calloc(width, height, 16);
276
277 if (!dstData)
278 return nullptr;
279
280 ZeroMemory(dstData, 1ULL * width * height);
281 BYTE* dstp = dstData;
282
283 for (UINT32 y = 0; y < height; y++)
284 {
285 const BYTE* srcp = &data[1ull * y * scanline];
286
287 for (UINT32 x = 0; x < width; x++)
288 {
289 if ((*srcp & (0x80 >> (x % 8))) != 0)
290 *dstp = 0xFF;
291
292 dstp++;
293
294 if (((x + 1) % 8 == 0) && x != 0)
295 srcp++;
296 }
297 }
298
299 return dstData;
300}
301
302BOOL freerdp_image_copy_from_monochrome(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
303 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
304 UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData,
305 UINT32 backColor, UINT32 foreColor,
306 const gdiPalette* WINPR_RESTRICT palette)
307{
308 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
309 return FALSE;
310 const UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
311
312 if (!pDstData || !pSrcData || !palette)
313 return FALSE;
314
315 if (nDstStep == 0)
316 nDstStep = dstBytesPerPixel * nWidth;
317
318 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
319 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
320
321 const UINT32 monoStep = (nWidth + 7) / 8;
322
323 for (size_t y = 0; y < nHeight; y++)
324 {
325 BYTE* pDstLine = &pDstData[((nYDst + y) * nDstStep)];
326 UINT32 monoBit = 0x80;
327 const BYTE* monoBits = &pSrcData[monoStep * y];
328
329 for (size_t x = 0; x < nWidth; x++)
330 {
331 BYTE* pDstPixel = &pDstLine[((nXDst + x) * FreeRDPGetBytesPerPixel(DstFormat))];
332 BOOL monoPixel = (*monoBits & monoBit) != 0;
333
334 if (!(monoBit >>= 1))
335 {
336 monoBits++;
337 monoBit = 0x80;
338 }
339
340 if (monoPixel)
341 {
342 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, backColor))
343 return FALSE;
344 }
345 else if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, foreColor))
346 return FALSE;
347 }
348 }
349
350 return TRUE;
351}
352
353static inline UINT32 freerdp_image_inverted_pointer_color(UINT32 x, UINT32 y, UINT32 format)
354{
364 BYTE fill = (x + y) & 1 ? 0x00 : 0xFF;
365 return FreeRDPGetColor(format, fill, fill, fill, 0xFF);
366}
367
368/*
369 * DIB color palettes are arrays of RGBQUAD structs with colors in BGRX format.
370 * They are used only by 1, 2, 4, and 8-bit bitmaps.
371 */
372static void fill_gdi_palette_for_icon(const BYTE* colorTable, UINT16 cbColorTable,
373 gdiPalette* palette)
374{
375 WINPR_ASSERT(palette);
376
377 palette->format = PIXEL_FORMAT_BGRX32;
378 ZeroMemory(palette->palette, sizeof(palette->palette));
379
380 if (!cbColorTable)
381 return;
382
383 if ((cbColorTable % 4 != 0) || (cbColorTable / 4 > 256))
384 {
385 WLog_WARN(TAG, "weird palette size: %u", cbColorTable);
386 return;
387 }
388
389 for (UINT16 i = 0; i < cbColorTable / 4; i++)
390 {
391 palette->palette[i] = FreeRDPReadColor_int(&colorTable[4ULL * i], palette->format);
392 }
393}
394
395static inline UINT32 div_ceil(UINT32 a, UINT32 b)
396{
397 return (a + (b - 1)) / b;
398}
399
400static inline UINT32 round_up(UINT32 a, UINT32 b)
401{
402 return b * div_ceil(a, b);
403}
404
405BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
406 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT16 nWidth,
407 UINT16 nHeight, const BYTE* WINPR_RESTRICT bitsColor,
408 UINT16 cbBitsColor, const BYTE* WINPR_RESTRICT bitsMask,
409 UINT16 cbBitsMask, const BYTE* WINPR_RESTRICT colorTable,
410 UINT16 cbColorTable, UINT32 bpp)
411{
412 DWORD format = 0;
413 gdiPalette palette;
414
415 if (!pDstData || !bitsColor)
416 return FALSE;
417
418 if ((nWidth == 0) || (nHeight == 0))
419 return TRUE;
420 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
421 return FALSE;
422
423 WINPR_ASSERT((nDstStep == 0) || (nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nWidth));
424
425 /*
426 * Color formats used by icons are DIB bitmap formats (2-bit format
427 * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565,
428 * and that 32-bit format uses BGRA order.
429 */
430 switch (bpp)
431 {
432 case 1:
433 case 4:
434 /*
435 * These formats are not supported by freerdp_image_copy().
436 * PIXEL_FORMAT_MONO and PIXEL_FORMAT_A4 are *not* correct
437 * color formats for this. Please fix freerdp_image_copy()
438 * if you came here to fix a broken icon of some weird app
439 * that still uses 1 or 4bpp format in the 21st century.
440 */
441 WLog_WARN(TAG, "1bpp and 4bpp icons are not supported");
442 return FALSE;
443
444 case 8:
445 format = PIXEL_FORMAT_RGB8;
446 break;
447
448 case 16:
449 format = PIXEL_FORMAT_RGB15;
450 break;
451
452 case 24:
453 format = PIXEL_FORMAT_RGB24;
454 break;
455
456 case 32:
457 format = PIXEL_FORMAT_BGRA32;
458 break;
459
460 default:
461 WLog_WARN(TAG, "invalid icon bpp: %" PRIu32, bpp);
462 return FALSE;
463 }
464
465 /* Ensure we have enough source data bytes for image copy. */
466 if ((1ul * cbBitsColor) / nHeight < (1ul * FreeRDPGetBytesPerPixel(format) * nWidth))
467 {
468 WLog_ERR(TAG,
469 "cbBitsColor{%" PRIu16 "} < nWidth{%" PRIu16 "} * nHeight{%" PRIu16
470 "} * bpp{%" PRIu32 "}",
471 cbBitsColor, nWidth, nHeight, FreeRDPGetBytesPerPixel(format));
472 return FALSE;
473 }
474
475 fill_gdi_palette_for_icon(colorTable, cbColorTable, &palette);
476 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
477 bitsColor, format, 0, 0, 0, &palette, FREERDP_FLIP_VERTICAL))
478 return FALSE;
479
480 /* apply alpha mask, skip if we already got alpha in the bitmap */
481 if (FreeRDPColorHasAlpha(DstFormat) && !FreeRDPColorHasAlpha(format) && (cbBitsMask > 0))
482 {
483 BYTE* dstBuf = pDstData;
484 UINT32 dstBpp = FreeRDPGetBytesPerPixel(DstFormat);
485
486 /*
487 * Each byte encodes 8 adjacent pixels (with LSB padding as needed).
488 * And due to hysterical raisins, stride of DIB bitmaps must be
489 * a multiple of 4 bytes.
490 */
491 const size_t stride = round_up(div_ceil(nWidth, 8), 4);
492 const size_t maskSize = stride * (nHeight - 1ULL) + div_ceil(nWidth, 8);
493 if (cbBitsMask < maskSize)
494 {
495 WLog_ERR(TAG, "cbBitsMask{%" PRIu32 "} < required mask size{%" PRIuz "}", cbBitsMask,
496 maskSize);
497 return FALSE;
498 }
499
500 for (UINT32 y = 0; y < nHeight; y++)
501 {
502 const BYTE* maskByte = &bitsMask[stride * (nHeight - 1ULL - y)];
503 BYTE nextBit = 0x80;
504
505 for (UINT32 x = 0; x < nWidth; x++)
506 {
507 BYTE r = 0;
508 BYTE g = 0;
509 BYTE b = 0;
510 BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF;
511
512 /* read color back, add alpha and write it back */
513 UINT32 color = FreeRDPReadColor_int(dstBuf, DstFormat);
514 FreeRDPSplitColor(color, DstFormat, &r, &g, &b, nullptr, &palette);
515 color = FreeRDPGetColor(DstFormat, r, g, b, alpha);
516 if (!FreeRDPWriteColor_int(dstBuf, DstFormat, color))
517 return FALSE;
518
519 nextBit >>= 1;
520 dstBuf += dstBpp;
521 if (!nextBit)
522 {
523 nextBit = 0x80;
524 maskByte++;
525 }
526 }
527 }
528 }
529
530 return TRUE;
531}
532
533static BOOL freerdp_image_copy_from_pointer_data_1bpp(
534 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
535 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
536 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp)
537{
538 BOOL vFlip = 0;
539 UINT32 xorStep = 0;
540 UINT32 andStep = 0;
541 UINT32 xorBit = 0;
542 UINT32 andBit = 0;
543 UINT32 xorPixel = 0;
544 UINT32 andPixel = 0;
545
546 vFlip = (xorBpp != 1);
547 andStep = (nWidth + 7) / 8;
548 andStep += (andStep % 2);
549
550 if (!xorMask || (xorMaskLength == 0))
551 return FALSE;
552 if (!andMask || (andMaskLength == 0))
553 return FALSE;
554
555 xorStep = (nWidth + 7) / 8;
556 xorStep += (xorStep % 2);
557
558 if (xorStep * nHeight > xorMaskLength)
559 return FALSE;
560
561 if (andStep * nHeight > andMaskLength)
562 return FALSE;
563
564 for (UINT32 y = 0; y < nHeight; y++)
565 {
566 const BYTE* andBits = nullptr;
567 const BYTE* xorBits = nullptr;
568 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
569 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
570 xorBit = andBit = 0x80;
571
572 if (!vFlip)
573 {
574 xorBits = &xorMask[1ULL * xorStep * y];
575 andBits = &andMask[1ULL * andStep * y];
576 }
577 else
578 {
579 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
580 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
581 }
582
583 for (UINT32 x = 0; x < nWidth; x++)
584 {
585 UINT32 color = 0;
586 xorPixel = (*xorBits & xorBit) ? 1 : 0;
587
588 if (!(xorBit >>= 1))
589 {
590 xorBits++;
591 xorBit = 0x80;
592 }
593
594 andPixel = (*andBits & andBit) ? 1 : 0;
595
596 if (!(andBit >>= 1))
597 {
598 andBits++;
599 andBit = 0x80;
600 }
601
602 if (!andPixel && !xorPixel)
603 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0xFF); /* black */
604 else if (!andPixel && xorPixel)
605 color = FreeRDPGetColor(DstFormat, 0xFF, 0xFF, 0xFF, 0xFF); /* white */
606 else if (andPixel && !xorPixel)
607 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0); /* transparent */
608 else if (andPixel && xorPixel)
609 color = freerdp_image_inverted_pointer_color(x, y, DstFormat); /* inverted */
610
611 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, color))
612 return FALSE;
613 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
614 }
615 }
616
617 return TRUE;
618}
619
620static BOOL freerdp_image_copy_from_pointer_data_xbpp(
621 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
622 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
623 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
624 const gdiPalette* palette)
625{
626 BOOL vFlip = 0;
627 size_t xorStep = 0;
628 size_t andStep = 0;
629 UINT32 andBit = 0;
630 UINT32 xorPixel = 0;
631 UINT32 andPixel = 0;
632 UINT32 dstBitsPerPixel = 0;
633 UINT32 xorBytesPerPixel = 0;
634 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
635
636 vFlip = (xorBpp != 1);
637 andStep = (nWidth + 7) / 8;
638 andStep += (andStep % 2);
639
640 if (!xorMask || (xorMaskLength == 0))
641 return FALSE;
642
643 xorBytesPerPixel = xorBpp >> 3;
644 xorStep = 1ULL * nWidth * xorBytesPerPixel;
645 xorStep += (xorStep % 2);
646
647 if (xorBpp == 8 && !palette)
648 {
649 WLog_ERR(TAG, "null palette in conversion from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
650 dstBitsPerPixel);
651 return FALSE;
652 }
653
654 if (xorStep * nHeight > xorMaskLength)
655 return FALSE;
656
657 if (andMask)
658 {
659 if (andStep * nHeight > andMaskLength)
660 return FALSE;
661 }
662
663 for (UINT32 y = 0; y < nHeight; y++)
664 {
665 const BYTE* xorBits = nullptr;
666 const BYTE* andBits = nullptr;
667 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
668 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
669 andBit = 0x80;
670
671 if (!vFlip)
672 {
673 if (andMask)
674 andBits = &andMask[andStep * y];
675
676 xorBits = &xorMask[xorStep * y];
677 }
678 else
679 {
680 if (andMask)
681 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
682
683 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
684 }
685
686 for (UINT32 x = 0; x < nWidth; x++)
687 {
688 UINT32 pixelFormat = 0;
689 UINT32 color = 0;
690
691 andPixel = 0;
692
693 if (andMask)
694 {
695 andPixel = (*andBits & andBit) ? 1 : 0;
696
697 if (!(andBit >>= 1))
698 {
699 andBits++;
700 andBit = 0x80;
701 }
702 }
703
704 if (xorBpp == 32)
705 {
706 pixelFormat = PIXEL_FORMAT_BGRA32;
707 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
708 }
709 else if (xorBpp == 16)
710 {
711 pixelFormat = PIXEL_FORMAT_RGB15;
712 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
713 }
714 else if (xorBpp == 8)
715 {
716 pixelFormat = palette->format;
717 xorPixel = palette->palette[xorBits[0]];
718 }
719 else
720 {
721 pixelFormat = PIXEL_FORMAT_BGR24;
722 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
723
724 if (andPixel)
725 {
726 if (xorPixel == 0x00FFFFFFUL)
727 xorPixel |= 0xFF000000UL;
728 else
729 xorPixel = 0;
730 }
731 else
732 xorPixel |= 0xFF000000UL;
733
734 // We need a transparent default alpha value, so use a different format here
735 pixelFormat = PIXEL_FORMAT_ABGR32;
736 }
737
738 xorPixel = FreeRDPConvertColor(xorPixel, pixelFormat, PIXEL_FORMAT_ARGB32, palette);
739 xorBits += xorBytesPerPixel;
740
741 if (andPixel)
742 {
743 if (xorPixel == 0xFF000000UL) /* black -> transparent */
744 xorPixel = 0x00000000;
745 else if (xorPixel == 0xFFFFFFFFUL) /* white -> inverted */
746 xorPixel = freerdp_image_inverted_pointer_color(x, y, PIXEL_FORMAT_ARGB32);
747 }
748
749 color = FreeRDPConvertColor(xorPixel, PIXEL_FORMAT_ARGB32, DstFormat, palette);
750 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, color))
751 return FALSE;
752 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
753 }
754 }
755
756 return TRUE;
757}
758
767BOOL freerdp_image_copy_from_pointer_data_int(
768 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
769 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
770 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
771 const gdiPalette* WINPR_RESTRICT palette)
772{
773 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
774 return FALSE;
775
776 UINT32 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
777 UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
778
779 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
780 if (nDstStep <= 0)
781 nDstStep = dstBytesPerPixel * (1ull * nXDst + nWidth);
782
783 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= (1ull * nXDst + nWidth));
784
785 for (UINT32 y = nYDst; y < nHeight; y++)
786 {
787 BYTE* WINPR_RESTRICT pDstLine = &pDstData[y * nDstStep + nXDst * dstBytesPerPixel];
788 memset(pDstLine, 0, 1ull * dstBytesPerPixel * (nWidth - nXDst));
789 }
790
791 switch (xorBpp)
792 {
793 case 1:
794 return freerdp_image_copy_from_pointer_data_1bpp(
795 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
796 xorMaskLength, andMask, andMaskLength, xorBpp);
797
798 case 8:
799 case 16:
800 case 24:
801 case 32:
802 return freerdp_image_copy_from_pointer_data_xbpp(
803 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
804 xorMaskLength, andMask, andMaskLength, xorBpp, palette);
805
806 default:
807 WLog_ERR(TAG, "failed to convert from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
808 dstBitsPerPixel);
809 return FALSE;
810 }
811}
812
813BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
814 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
815 UINT32 nWidth, UINT32 nHeight,
816 const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
817 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
818 UINT32 xorBpp, const gdiPalette* WINPR_RESTRICT palette)
819{
820#if defined(WITH_CURSOR_DUMP)
821 dump_pointer_data(nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask, andMaskLength,
822 xorBpp, palette);
823#endif
824 return freerdp_image_copy_from_pointer_data_int(pDstData, DstFormat, nDstStep, nXDst, nYDst,
825 nWidth, nHeight, xorMask, xorMaskLength,
826 andMask, andMaskLength, xorBpp, palette);
827}
828
829static inline BOOL overlapping(const BYTE* pDstData, UINT32 nYDst, UINT32 nDstStep,
830 const BYTE* pSrcData, UINT32 nYSrc, UINT32 nSrcStep, UINT32 nHeight)
831{
832 const uintptr_t src = (uintptr_t)pSrcData;
833 const uintptr_t srcstart = src + 1ULL * nSrcStep * nYSrc;
834 const uintptr_t srcend = srcstart + 1ULL * nSrcStep * nHeight;
835 const uintptr_t dst = (uintptr_t)pDstData;
836 const uintptr_t dststart = dst + 1ULL * nDstStep * nYDst;
837 const uintptr_t dstend = dststart + 1ULL * nDstStep * nHeight;
838
839 WINPR_ASSERT(nDstStep > 0);
840 WINPR_ASSERT(nSrcStep > 0);
841 if ((dststart >= srcstart) && (dststart < srcend))
842 return TRUE;
843
844 if ((dstend > srcstart) && (dstend <= srcend))
845 return TRUE;
846
847 return FALSE;
848}
849
850static inline BOOL freerdp_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
851 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
852 UINT32 nHeight,
853 const BYTE* WINPR_RESTRICT pSrcData,
854 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
855 int64_t srcVMultiplier, int64_t srcVOffset,
856 int64_t dstVMultiplier, int64_t dstVOffset)
857{
858
859 const int64_t srcByte = 3;
860 const int64_t dstByte = 4;
861
862 for (int64_t y = 0; y < nHeight; y++)
863 {
864 const BYTE* WINPR_RESTRICT srcLine =
865 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
866 BYTE* WINPR_RESTRICT dstLine =
867 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
868
869 for (int64_t x = 0; x < nWidth; x++)
870 {
871 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
872 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
873 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
874 }
875 }
876
877 return TRUE;
878}
879
880static inline BOOL freerdp_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
881 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
882 UINT32 nHeight,
883 const BYTE* WINPR_RESTRICT pSrcData,
884 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
885 int64_t srcVMultiplier, int64_t srcVOffset,
886 int64_t dstVMultiplier, int64_t dstVOffset)
887{
888
889 const int64_t srcByte = 4;
890 const int64_t dstByte = 4;
891
892 for (int64_t y = 0; y < nHeight; y++)
893 {
894 const BYTE* WINPR_RESTRICT srcLine =
895 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
896 BYTE* WINPR_RESTRICT dstLine =
897 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
898
899 for (int64_t x = 0; x < nWidth; x++)
900 {
901 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
902 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
903 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
904 }
905 }
906
907 return TRUE;
908}
909
910static inline BOOL freerdp_image_copy_generic(
911 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
912 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcFormat,
913 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
914 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
915{
916
917 const int64_t srcByte = 4;
918 const int64_t dstByte = 4;
919
920 for (int64_t y = 0; y < nHeight; y++)
921 {
922 const BYTE* WINPR_RESTRICT srcLine =
923 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
924 BYTE* WINPR_RESTRICT dstLine =
925 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
926
927 UINT32 color = FreeRDPReadColor_int(&srcLine[nXSrc * srcByte], SrcFormat);
928 UINT32 oldColor = color;
929 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
930 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[nXDst * dstByte], DstFormat, dstColor))
931 return FALSE;
932
933 for (int64_t x = 1; x < nWidth; x++)
934 {
935 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
936 if (color == oldColor)
937 {
938 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
939 dstColor))
940 return FALSE;
941 }
942 else
943 {
944 oldColor = color;
945 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
946 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
947 dstColor))
948 return FALSE;
949 }
950 }
951 }
952
953 return TRUE;
954}
955
956static inline BOOL freerdp_image_copy_no_overlap_dst_alpha(
957 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
958 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
959 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
960 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
961{
962 WINPR_ASSERT(pDstData);
963 WINPR_ASSERT(pSrcData);
964
965 switch (SrcFormat)
966 {
967 case PIXEL_FORMAT_BGR24:
968 switch (DstFormat)
969 {
970 case PIXEL_FORMAT_BGRX32:
971 case PIXEL_FORMAT_BGRA32:
972 return freerdp_image_copy_bgr24_bgrx32(
973 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
974 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
975 default:
976 break;
977 }
978 break;
979 case PIXEL_FORMAT_BGRX32:
980 case PIXEL_FORMAT_BGRA32:
981 switch (DstFormat)
982 {
983 case PIXEL_FORMAT_BGRX32:
984 case PIXEL_FORMAT_BGRA32:
985 return freerdp_image_copy_bgrx32_bgrx32(
986 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
987 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
988 default:
989 break;
990 }
991 break;
992 default:
993 break;
994 }
995
996 return freerdp_image_copy_generic(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
997 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
998 srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
999}
1000
1001BOOL freerdp_image_copy_overlap(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
1002 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
1003 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1004 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1005{
1006 const UINT32 dstByte = FreeRDPGetBytesPerPixel(DstFormat);
1007 const UINT32 srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
1008 const UINT32 copyDstWidth = nWidth * dstByte;
1009 const UINT32 xSrcOffset = nXSrc * srcByte;
1010 const UINT32 xDstOffset = nXDst * dstByte;
1011 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) != 0;
1012 int64_t srcVOffset = 0;
1013 int64_t srcVMultiplier = 1;
1014 int64_t dstVOffset = 0;
1015 int64_t dstVMultiplier = 1;
1016
1017 if ((nWidth == 0) || (nHeight == 0))
1018 return TRUE;
1019
1020 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1021 return FALSE;
1022 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1023 return FALSE;
1024
1025 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1026 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
1027 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1028 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
1029 WINPR_ASSERT(overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
1030
1031 if ((nWidth == 0) || (nHeight == 0))
1032 return TRUE;
1033
1034 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
1035 return FALSE;
1036
1037 if (!pDstData || !pSrcData)
1038 return FALSE;
1039
1040 if (nDstStep == 0)
1041 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1042
1043 if (nSrcStep == 0)
1044 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1045
1046 if (vSrcVFlip)
1047 {
1048 srcVOffset = (nHeight - 1ll) * nSrcStep;
1049 srcVMultiplier = -1;
1050 }
1051
1052 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
1053 {
1054 return freerdp_image_copy_no_overlap_dst_alpha(
1055 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
1056 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
1057 dstVOffset);
1058 }
1059 else if (FreeRDPAreColorFormatsEqualNoAlpha_int(SrcFormat, DstFormat))
1060 {
1061 /* Copy down */
1062 if (nYDst < nYSrc)
1063 {
1064 for (int64_t y = 0; y < nHeight; y++)
1065 {
1066 const BYTE* srcLine =
1067 &pSrcData[(y + nYSrc) * nSrcStep * srcVMultiplier + srcVOffset];
1068 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1069 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1070 }
1071 }
1072 /* Copy up */
1073 else if (nYDst > nYSrc)
1074 {
1075 for (int64_t y = nHeight - 1; y >= 0; y--)
1076 {
1077 const BYTE* srcLine =
1078 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1079 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1080 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1081 }
1082 }
1083 /* Copy left */
1084 else if (nXSrc > nXDst)
1085 {
1086 for (int64_t y = 0; y < nHeight; y++)
1087 {
1088 const BYTE* srcLine =
1089 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1090 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1091 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1092 }
1093 }
1094 /* Copy right */
1095 else if (nXSrc < nXDst)
1096 {
1097 for (int64_t y = nHeight - 1; y >= 0; y--)
1098 {
1099 const BYTE* srcLine =
1100 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1101 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1102 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1103 }
1104 }
1105 /* Source and destination are equal... */
1106 else
1107 {
1108 }
1109 }
1110 else
1111 {
1112 for (int64_t y = 0; y < nHeight; y++)
1113 {
1114 const BYTE* srcLine = &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1115 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1116
1117 UINT32 color = FreeRDPReadColor_int(&srcLine[1ULL * nXSrc * srcByte], SrcFormat);
1118 UINT32 oldColor = color;
1119 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
1120 if (!FreeRDPWriteColor_int(&dstLine[1ULL * nXDst * dstByte], DstFormat, dstColor))
1121 return FALSE;
1122
1123 for (int64_t x = 1; x < nWidth; x++)
1124 {
1125 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
1126 if (color == oldColor)
1127 {
1128 if (!FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
1129 dstColor))
1130 return FALSE;
1131 }
1132 else
1133 {
1134 oldColor = color;
1135 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
1136 if (!FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
1137 dstColor))
1138 return FALSE;
1139 }
1140 }
1141 }
1142 }
1143
1144 return TRUE;
1145}
1146
1147BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
1148 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
1149 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1150 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1151{
1152 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
1153 return FALSE;
1154
1155 if (!pDstData || !pSrcData)
1156 return FALSE;
1157
1158 if ((nWidth == 0) || (nHeight == 0))
1159 return TRUE;
1160
1161 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1162 return FALSE;
1163 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1164 return FALSE;
1165
1166 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1167 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
1168 if (nDstStep == 0)
1169 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1170
1171 if (nSrcStep == 0)
1172 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1173
1174 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1175 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
1176
1177 const BOOL ovl = overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight);
1178 if (ovl)
1179 return freerdp_image_copy_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
1180 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
1181 palette, flags);
1182 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
1183 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
1184 palette, flags);
1185}
1186
1187BOOL freerdp_image_fill(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1188 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color)
1189{
1190 if ((nWidth == 0) || (nHeight == 0))
1191 return TRUE;
1192
1193 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1194 return FALSE;
1195
1196 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
1197 BYTE* WINPR_RESTRICT pFirstDstLine = nullptr;
1198 BYTE* WINPR_RESTRICT pFirstDstLineXOffset = nullptr;
1199
1200 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1201 if (nDstStep == 0)
1202 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1203
1204 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1205 pFirstDstLine = &pDstData[1ULL * nYDst * nDstStep];
1206 pFirstDstLineXOffset = &pFirstDstLine[1ULL * nXDst * bpp];
1207
1208 for (size_t x = 0; x < nWidth; x++)
1209 {
1210 BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp];
1211 if (!FreeRDPWriteColor_int(pDst, DstFormat, color))
1212 return FALSE;
1213 }
1214
1215 for (size_t y = 1; y < nHeight; y++)
1216 {
1217 BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + 1ULL * nXDst * bpp];
1218 memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp);
1219 }
1220
1221 return TRUE;
1222}
1223
1224BOOL freerdp_image_fill_ex(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1225 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color,
1226 UINT32 flags)
1227{
1228 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1229 return FALSE;
1230
1231 WINPR_ASSERT(pDstData);
1232 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1233 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1234
1235 if (FreeRDPColorHasAlpha(DstFormat) && ((flags & FREERDP_IMAGE_FILL_IGNORE_ALPHA) != 0))
1236 {
1237 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
1238 BYTE r = 0;
1239 BYTE g = 0;
1240 BYTE b = 0;
1241 FreeRDPSplitColor(color, DstFormat, &r, &g, &b, nullptr, nullptr);
1242
1243 for (size_t y = 0; y < nHeight; y++)
1244 {
1245 BYTE* WINPR_RESTRICT line = &pDstData[(y + nYDst) * nDstStep];
1246
1247 for (size_t x = 0; x < nWidth; x++)
1248 {
1249 BYTE* WINPR_RESTRICT dst = &line[x * bpp];
1250 const UINT32 dcolor = FreeRDPReadColor_int(dst, DstFormat);
1251 BYTE a = 0;
1252 FreeRDPSplitColor(dcolor, DstFormat, nullptr, nullptr, nullptr, &a, nullptr);
1253 const UINT32 scolor = FreeRDPGetColor(DstFormat, r, g, b, a);
1254 if (!FreeRDPWriteColor_int(dst, DstFormat, scolor))
1255 return FALSE;
1256 }
1257 }
1258 return TRUE;
1259 }
1260 return freerdp_image_fill(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, color);
1261}
1262
1263#if defined(WITH_SWSCALE)
1264static enum AVPixelFormat av_format_for_buffer(UINT32 format)
1265{
1266 switch (format)
1267 {
1268 case PIXEL_FORMAT_ARGB32:
1269 return AV_PIX_FMT_BGRA;
1270
1271 case PIXEL_FORMAT_XRGB32:
1272 return AV_PIX_FMT_BGR0;
1273
1274 case PIXEL_FORMAT_BGRA32:
1275 return AV_PIX_FMT_RGBA;
1276
1277 case PIXEL_FORMAT_BGRX32:
1278 return AV_PIX_FMT_RGB0;
1279
1280 default:
1281 return AV_PIX_FMT_NONE;
1282 }
1283}
1284#endif
1285
1286BOOL freerdp_image_scaling_supported(void)
1287{
1288#if defined(WITH_SWSCALE) || defined(WITH_CAIRO)
1289 return TRUE;
1290#else
1291 return FALSE;
1292#endif
1293}
1294
1295BOOL freerdp_image_scale(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1296 UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
1297 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
1298 UINT32 nXSrc, UINT32 nYSrc, UINT32 nSrcWidth, UINT32 nSrcHeight)
1299{
1300 BOOL rc = FALSE;
1301 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1302 return FALSE;
1303 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1304 return FALSE;
1305
1306 WINPR_ASSERT(1ull * nXDst + nDstWidth <= UINT32_MAX);
1307 WINPR_ASSERT(1ull * nXSrc + nSrcWidth <= UINT32_MAX);
1308 if (nDstStep == 0)
1309 nDstStep = (nXDst + nDstWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1310
1311 if (nSrcStep == 0)
1312 nSrcStep = (nXSrc + nSrcWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1313
1314 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nDstWidth);
1315 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nSrcWidth);
1316
1317#if defined(WITH_SWSCALE) || defined(WITH_CAIRO)
1318 const BYTE* src =
1319 &pSrcData[1ULL * nXSrc * FreeRDPGetBytesPerPixel(SrcFormat) + 1ULL * nYSrc * nSrcStep];
1320 BYTE* dst =
1321 &pDstData[1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat) + 1ULL * nYDst * nDstStep];
1322#endif
1323
1324 /* direct copy is much faster than scaling, so check if we can simply copy... */
1325 if ((nDstWidth == nSrcWidth) && (nDstHeight == nSrcHeight))
1326 {
1327 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1328 nDstHeight, pSrcData, SrcFormat, nSrcStep, nXSrc,
1329 nYSrc, nullptr, FREERDP_FLIP_NONE);
1330 }
1331 else
1332#if defined(WITH_SWSCALE)
1333 {
1334 int res = 0;
1335 struct SwsContext* resize = nullptr;
1336 enum AVPixelFormat srcFormat = av_format_for_buffer(SrcFormat);
1337 enum AVPixelFormat dstFormat = av_format_for_buffer(DstFormat);
1338 const int srcStep[1] = { (int)nSrcStep };
1339 const int dstStep[1] = { (int)nDstStep };
1340
1341 if ((srcFormat == AV_PIX_FMT_NONE) || (dstFormat == AV_PIX_FMT_NONE))
1342 return FALSE;
1343
1344 if (!freerdp_swscale_available())
1345 {
1346 WLog_WARN(TAG, "swscale not available");
1347 return FALSE;
1348 }
1349
1350 /* swscale addresses lines as line * stride in int arithmetic, every byte of an image must
1351 * be addressable with a signed int (see av_image_check_size). For larger images the
1352 * offset wraps and the last lines are read or written 4GiB in front of the buffer. */
1353 if ((1ULL * nSrcStep * nSrcHeight > INT32_MAX) ||
1354 (1ULL * nDstStep * nDstHeight > INT32_MAX))
1355 {
1356 WLog_ERR(TAG,
1357 "image too large to scale: source %" PRIu32 " x %" PRIu32
1358 " bytes, destination %" PRIu32 " x %" PRIu32 " bytes",
1359 nSrcStep, nSrcHeight, nDstStep, nDstHeight);
1360 return FALSE;
1361 }
1362
1363 resize = freerdp_sws_getContext((int)nSrcWidth, (int)nSrcHeight, srcFormat, (int)nDstWidth,
1364 (int)nDstHeight, dstFormat, SWS_BILINEAR, nullptr, nullptr,
1365 nullptr);
1366
1367 if (!resize)
1368 goto fail;
1369
1370 /* sws_scale expects arrays of pointers, not pointer-to-pointer */
1371 const BYTE* srcSlice[4] = { src, nullptr, nullptr, nullptr };
1372 BYTE* dstSlice[4] = { dst, nullptr, nullptr, nullptr };
1373 const int srcSteps[4] = { srcStep[0], 0, 0, 0 };
1374 const int dstSteps[4] = { dstStep[0], 0, 0, 0 };
1375
1376 res = freerdp_sws_scale(resize, srcSlice, srcSteps, 0, (int)nSrcHeight, dstSlice, dstSteps);
1377 rc = (res == ((int)nDstHeight));
1378 fail:
1379 freerdp_sws_freeContext(resize);
1380 }
1381
1382#elif defined(WITH_CAIRO)
1383 {
1384 const double sx = (double)nDstWidth / (double)nSrcWidth;
1385 const double sy = (double)nDstHeight / (double)nSrcHeight;
1386 cairo_t* cairo_context;
1387 cairo_surface_t *csrc, *cdst;
1388
1389 if ((nSrcWidth > INT_MAX) || (nSrcHeight > INT_MAX) || (nSrcStep > INT_MAX))
1390 return FALSE;
1391
1392 if ((nDstWidth > INT_MAX) || (nDstHeight > INT_MAX) || (nDstStep > INT_MAX))
1393 return FALSE;
1394
1395 /* cairo (pixman) addresses lines as line * stride in int arithmetic as well */
1396 if ((1ULL * nSrcStep * nSrcHeight > INT_MAX) || (1ULL * nDstStep * nDstHeight > INT_MAX))
1397 return FALSE;
1398
1399 csrc = cairo_image_surface_create_for_data((void*)src, CAIRO_FORMAT_ARGB32, (int)nSrcWidth,
1400 (int)nSrcHeight, (int)nSrcStep);
1401 cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, (int)nDstWidth,
1402 (int)nDstHeight, (int)nDstStep);
1403
1404 if (!csrc || !cdst)
1405 goto fail;
1406
1407 cairo_context = cairo_create(cdst);
1408
1409 if (!cairo_context)
1410 goto fail2;
1411
1412 cairo_scale(cairo_context, sx, sy);
1413 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
1414 cairo_set_source_surface(cairo_context, csrc, 0, 0);
1415 cairo_paint(cairo_context);
1416 rc = TRUE;
1417 fail2:
1418 cairo_destroy(cairo_context);
1419 fail:
1420 cairo_surface_destroy(csrc);
1421 cairo_surface_destroy(cdst);
1422 }
1423#else
1424 {
1425 WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!");
1426 }
1427#endif
1428 return rc;
1429}
1430
1431DWORD FreeRDPAreColorFormatsEqualNoAlpha(DWORD first, DWORD second)
1432{
1433 return FreeRDPAreColorFormatsEqualNoAlpha_int(first, second);
1434}
1435
1436const char* FreeRDPGetColorFormatName(UINT32 format)
1437{
1438#define ENTRY(x) \
1439 case x: \
1440 return #x;
1441
1442 switch (format)
1443 {
1444 ENTRY(PIXEL_FORMAT_ARGB32)
1445 ENTRY(PIXEL_FORMAT_XRGB32)
1446 ENTRY(PIXEL_FORMAT_ABGR32)
1447 ENTRY(PIXEL_FORMAT_XBGR32)
1448 ENTRY(PIXEL_FORMAT_BGRA32)
1449 ENTRY(PIXEL_FORMAT_BGRX32)
1450 ENTRY(PIXEL_FORMAT_RGBA32)
1451 ENTRY(PIXEL_FORMAT_RGBX32)
1452 ENTRY(PIXEL_FORMAT_BGRX32_DEPTH30)
1453 ENTRY(PIXEL_FORMAT_RGBX32_DEPTH30)
1454 ENTRY(PIXEL_FORMAT_RGB24)
1455 ENTRY(PIXEL_FORMAT_BGR24)
1456 ENTRY(PIXEL_FORMAT_RGB16)
1457 ENTRY(PIXEL_FORMAT_BGR16)
1458 ENTRY(PIXEL_FORMAT_ARGB15)
1459 ENTRY(PIXEL_FORMAT_RGB15)
1460 ENTRY(PIXEL_FORMAT_ABGR15)
1461 ENTRY(PIXEL_FORMAT_BGR15)
1462 ENTRY(PIXEL_FORMAT_RGB8)
1463 ENTRY(PIXEL_FORMAT_A4)
1464 ENTRY(PIXEL_FORMAT_MONO)
1465
1466 default:
1467 return "UNKNOWN";
1468 }
1469#undef ENTRY
1470}
1471
1472uint32_t FreeRDPGetColorFromatFromName(const char* name)
1473{
1474#define ENTRY(x) \
1475 if (strcmp(name, #x) == 0) \
1476 return x;
1477
1478 if (!name)
1479 return 0;
1480
1481 ENTRY(PIXEL_FORMAT_ARGB32)
1482 ENTRY(PIXEL_FORMAT_XRGB32)
1483 ENTRY(PIXEL_FORMAT_ABGR32)
1484 ENTRY(PIXEL_FORMAT_XBGR32)
1485 ENTRY(PIXEL_FORMAT_BGRA32)
1486 ENTRY(PIXEL_FORMAT_BGRX32)
1487 ENTRY(PIXEL_FORMAT_RGBA32)
1488 ENTRY(PIXEL_FORMAT_RGBX32)
1489 ENTRY(PIXEL_FORMAT_BGRX32_DEPTH30)
1490 ENTRY(PIXEL_FORMAT_RGBX32_DEPTH30)
1491 ENTRY(PIXEL_FORMAT_RGB24)
1492 ENTRY(PIXEL_FORMAT_BGR24)
1493 ENTRY(PIXEL_FORMAT_RGB16)
1494 ENTRY(PIXEL_FORMAT_BGR16)
1495 ENTRY(PIXEL_FORMAT_ARGB15)
1496 ENTRY(PIXEL_FORMAT_RGB15)
1497 ENTRY(PIXEL_FORMAT_ABGR15)
1498 ENTRY(PIXEL_FORMAT_BGR15)
1499 ENTRY(PIXEL_FORMAT_RGB8)
1500 ENTRY(PIXEL_FORMAT_A4)
1501 ENTRY(PIXEL_FORMAT_MONO)
1502
1503 return 0;
1504#undef ENTRY
1505}
1506
1507void FreeRDPSplitColor(UINT32 color, UINT32 format, BYTE* _r, BYTE* _g, BYTE* _b, BYTE* _a,
1508 const gdiPalette* palette)
1509{
1510 UINT32 tmp = 0;
1511
1512 switch (format)
1513 {
1514 /* 32bpp formats */
1515 case PIXEL_FORMAT_ARGB32:
1516 if (_a)
1517 *_a = (BYTE)(color >> 24);
1518
1519 if (_r)
1520 *_r = (BYTE)(color >> 16);
1521
1522 if (_g)
1523 *_g = (BYTE)(color >> 8);
1524
1525 if (_b)
1526 *_b = (BYTE)color;
1527
1528 break;
1529
1530 case PIXEL_FORMAT_XRGB32:
1531 if (_r)
1532 *_r = (BYTE)(color >> 16);
1533
1534 if (_g)
1535 *_g = (BYTE)(color >> 8);
1536
1537 if (_b)
1538 *_b = (BYTE)color;
1539
1540 if (_a)
1541 *_a = 0xFF;
1542
1543 break;
1544
1545 case PIXEL_FORMAT_ABGR32:
1546 if (_a)
1547 *_a = (BYTE)(color >> 24);
1548
1549 if (_b)
1550 *_b = (BYTE)(color >> 16);
1551
1552 if (_g)
1553 *_g = (BYTE)(color >> 8);
1554
1555 if (_r)
1556 *_r = (BYTE)color;
1557
1558 break;
1559
1560 case PIXEL_FORMAT_XBGR32:
1561 if (_b)
1562 *_b = (BYTE)(color >> 16);
1563
1564 if (_g)
1565 *_g = (BYTE)(color >> 8);
1566
1567 if (_r)
1568 *_r = (BYTE)color;
1569
1570 if (_a)
1571 *_a = 0xFF;
1572
1573 break;
1574
1575 case PIXEL_FORMAT_RGBA32:
1576 if (_r)
1577 *_r = (BYTE)(color >> 24);
1578
1579 if (_g)
1580 *_g = (BYTE)(color >> 16);
1581
1582 if (_b)
1583 *_b = (BYTE)(color >> 8);
1584
1585 if (_a)
1586 *_a = (BYTE)color;
1587
1588 break;
1589
1590 case PIXEL_FORMAT_RGBX32:
1591 if (_r)
1592 *_r = (BYTE)(color >> 24);
1593
1594 if (_g)
1595 *_g = (BYTE)(color >> 16);
1596
1597 if (_b)
1598 *_b = (BYTE)(color >> 8);
1599
1600 if (_a)
1601 *_a = 0xFF;
1602
1603 break;
1604
1605 case PIXEL_FORMAT_BGRA32:
1606 if (_b)
1607 *_b = (BYTE)(color >> 24);
1608
1609 if (_g)
1610 *_g = (BYTE)(color >> 16);
1611
1612 if (_r)
1613 *_r = (BYTE)(color >> 8);
1614
1615 if (_a)
1616 *_a = (BYTE)color;
1617
1618 break;
1619
1620 case PIXEL_FORMAT_BGRX32:
1621 if (_b)
1622 *_b = (BYTE)(color >> 24);
1623
1624 if (_g)
1625 *_g = (BYTE)(color >> 16);
1626
1627 if (_r)
1628 *_r = (BYTE)(color >> 8);
1629
1630 if (_a)
1631 *_a = 0xFF;
1632
1633 break;
1634
1635 /* 24bpp formats */
1636 case PIXEL_FORMAT_RGB24:
1637 if (_r)
1638 *_r = (BYTE)(color >> 16);
1639
1640 if (_g)
1641 *_g = (BYTE)(color >> 8);
1642
1643 if (_b)
1644 *_b = (BYTE)color;
1645
1646 if (_a)
1647 *_a = 0xFF;
1648
1649 break;
1650
1651 case PIXEL_FORMAT_BGR24:
1652 if (_b)
1653 *_b = (BYTE)(color >> 16);
1654
1655 if (_g)
1656 *_g = (BYTE)(color >> 8);
1657
1658 if (_r)
1659 *_r = (BYTE)color;
1660
1661 if (_a)
1662 *_a = 0xFF;
1663
1664 break;
1665
1666 /* 16bpp formats */
1667 case PIXEL_FORMAT_RGB16:
1668 if (_r)
1669 {
1670 const UINT32 c = (color >> 11) & 0x1F;
1671 const UINT32 val = (c << 3) + c / 4;
1672 *_r = (BYTE)(val > 255 ? 255 : val);
1673 }
1674
1675 if (_g)
1676 {
1677 const UINT32 c = (color >> 5) & 0x3F;
1678 const UINT32 val = (c << 2) + c / 4 / 2;
1679 *_g = (BYTE)(val > 255 ? 255 : val);
1680 }
1681
1682 if (_b)
1683 {
1684 const UINT32 c = (color)&0x1F;
1685 const UINT32 val = (c << 3) + c / 4;
1686 *_b = (BYTE)(val > 255 ? 255 : val);
1687 }
1688
1689 if (_a)
1690 *_a = 0xFF;
1691
1692 break;
1693
1694 case PIXEL_FORMAT_BGR16:
1695 if (_r)
1696 {
1697 const UINT32 c = (color)&0x1F;
1698 const UINT32 val = (c << 3) + c / 4;
1699 *_r = (BYTE)(val > 255 ? 255 : val);
1700 }
1701
1702 if (_g)
1703 {
1704 const UINT32 c = (color >> 5) & 0x3F;
1705 const UINT32 val = (c << 2) + c / 4 / 2;
1706 *_g = (BYTE)(val > 255 ? 255 : val);
1707 }
1708
1709 if (_b)
1710 {
1711 const UINT32 c = (color >> 11) & 0x1F;
1712 const UINT32 val = (c << 3) + c / 4;
1713 *_b = (BYTE)(val > 255 ? 255 : val);
1714 }
1715
1716 if (_a)
1717 *_a = 0xFF;
1718
1719 break;
1720
1721 case PIXEL_FORMAT_ARGB15:
1722 if (_r)
1723 {
1724 const UINT32 c = (color >> 10) & 0x1F;
1725 const UINT32 val = (c << 3) + c / 4;
1726 *_r = (BYTE)(val > 255 ? 255 : val);
1727 }
1728
1729 if (_g)
1730 {
1731 const UINT32 c = (color >> 5) & 0x1F;
1732 const UINT32 val = (c << 3) + c / 4;
1733 *_g = (BYTE)(val > 255 ? 255 : val);
1734 }
1735
1736 if (_b)
1737 {
1738 const UINT32 c = (color)&0x1F;
1739 const UINT32 val = (c << 3) + c / 4;
1740 *_b = (BYTE)(val > 255 ? 255 : val);
1741 }
1742
1743 if (_a)
1744 *_a = color & 0x8000 ? 0xFF : 0x00;
1745
1746 break;
1747
1748 case PIXEL_FORMAT_ABGR15:
1749 if (_r)
1750 {
1751 const UINT32 c = (color)&0x1F;
1752 const UINT32 val = (c << 3) + c / 4;
1753 *_r = (BYTE)(val > 255 ? 255 : val);
1754 }
1755
1756 if (_g)
1757 {
1758 const UINT32 c = (color >> 5) & 0x1F;
1759 const UINT32 val = (c << 3) + c / 4;
1760 *_g = (BYTE)(val > 255 ? 255 : val);
1761 }
1762
1763 if (_b)
1764 {
1765 const UINT32 c = (color >> 10) & 0x1F;
1766 const UINT32 val = (c << 3) + c / 4;
1767 *_b = (BYTE)(val > 255 ? 255 : val);
1768 }
1769
1770 if (_a)
1771 *_a = color & 0x8000 ? 0xFF : 0x00;
1772
1773 break;
1774
1775 /* 15bpp formats */
1776 case PIXEL_FORMAT_RGB15:
1777 if (_r)
1778 {
1779 const UINT32 c = (color >> 10) & 0x1F;
1780 const UINT32 val = (c << 3) + c / 4;
1781 *_r = (BYTE)(val > 255 ? 255 : val);
1782 }
1783
1784 if (_g)
1785 {
1786 const UINT32 c = (color >> 5) & 0x1F;
1787 const UINT32 val = (c << 3) + c / 4;
1788 *_g = (BYTE)(val > 255 ? 255 : val);
1789 }
1790
1791 if (_b)
1792 {
1793 const UINT32 c = (color)&0x1F;
1794 const UINT32 val = (c << 3) + c / 4;
1795 *_b = (BYTE)(val > 255 ? 255 : val);
1796 }
1797
1798 if (_a)
1799 *_a = 0xFF;
1800
1801 break;
1802
1803 case PIXEL_FORMAT_BGR15:
1804 if (_r)
1805 {
1806 const UINT32 c = (color)&0x1F;
1807 const UINT32 val = (c << 3) + c / 4;
1808 *_r = (BYTE)(val > 255 ? 255 : val);
1809 }
1810
1811 if (_g)
1812 {
1813 const UINT32 c = (color >> 5) & 0x1F;
1814 const UINT32 val = (c << 3) + c / 4;
1815 *_g = (BYTE)(val > 255 ? 255 : val);
1816 }
1817
1818 if (_b)
1819 {
1820 const UINT32 c = (color >> 10) & 0x1F;
1821 const UINT32 val = (c << 3) + c / 4;
1822 *_b = (BYTE)(val > 255 ? 255 : val);
1823 }
1824
1825 if (_a)
1826 *_a = 0xFF;
1827
1828 break;
1829
1830 /* 8bpp formats */
1831 case PIXEL_FORMAT_RGB8:
1832 if (color <= 0xFF)
1833 {
1834 tmp = palette->palette[color];
1835 FreeRDPSplitColor(tmp, palette->format, _r, _g, _b, _a, nullptr);
1836 }
1837 else
1838 {
1839 if (_r)
1840 *_r = 0x00;
1841
1842 if (_g)
1843 *_g = 0x00;
1844
1845 if (_b)
1846 *_b = 0x00;
1847
1848 if (_a)
1849 *_a = 0x00;
1850 }
1851
1852 break;
1853
1854 /* 1bpp formats */
1855 case PIXEL_FORMAT_MONO:
1856 if (_r)
1857 *_r = (color) ? 0xFF : 0x00;
1858
1859 if (_g)
1860 *_g = (color) ? 0xFF : 0x00;
1861
1862 if (_b)
1863 *_b = (color) ? 0xFF : 0x00;
1864
1865 if (_a)
1866 *_a = (color) ? 0xFF : 0x00;
1867
1868 break;
1869
1870 /* 4 bpp formats */
1871 case PIXEL_FORMAT_A4:
1872 default:
1873 if (_r)
1874 *_r = 0x00;
1875
1876 if (_g)
1877 *_g = 0x00;
1878
1879 if (_b)
1880 *_b = 0x00;
1881
1882 if (_a)
1883 *_a = 0x00;
1884
1885 WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1886 break;
1887 }
1888}
1889
1890BOOL FreeRDPWriteColorIgnoreAlpha(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1891{
1892 return FreeRDPWriteColorIgnoreAlpha_int(dst, format, color);
1893}
1894
1895BOOL FreeRDPWriteColor(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1896{
1897 return FreeRDPWriteColor_int(dst, format, color);
1898}
1899
1900UINT32 FreeRDPReadColor(const BYTE* WINPR_RESTRICT src, UINT32 format)
1901{
1902 return FreeRDPReadColor_int(src, format);
1903}
1904
1905UINT32 FreeRDPGetColor(UINT32 format, BYTE r, BYTE g, BYTE b, BYTE a)
1906{
1907 UINT32 _r = r;
1908 UINT32 _g = g;
1909 UINT32 _b = b;
1910 UINT32 _a = a;
1911 UINT32 t = 0;
1912
1913 switch (format)
1914 {
1915 /* 32bpp formats */
1916 case PIXEL_FORMAT_ARGB32:
1917 return (_a << 24) | (_r << 16) | (_g << 8) | _b;
1918
1919 case PIXEL_FORMAT_XRGB32:
1920 return (_r << 16) | (_g << 8) | _b;
1921
1922 case PIXEL_FORMAT_ABGR32:
1923 return (_a << 24) | (_b << 16) | (_g << 8) | _r;
1924
1925 case PIXEL_FORMAT_XBGR32:
1926 return (_b << 16) | (_g << 8) | _r;
1927
1928 case PIXEL_FORMAT_RGBA32:
1929 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1930
1931 case PIXEL_FORMAT_RGBX32:
1932 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1933
1934 case PIXEL_FORMAT_BGRA32:
1935 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1936
1937 case PIXEL_FORMAT_BGRX32:
1938 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1939
1940 case PIXEL_FORMAT_RGBX32_DEPTH30:
1941 // TODO: Not tested
1942 t = (_r << 22) | (_g << 12) | (_b << 2);
1943 // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1944 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1945 (t >> 24);
1946
1947 case PIXEL_FORMAT_BGRX32_DEPTH30:
1948 // NOTE: Swapping b and r channel (unknown reason)
1949 t = (_r << 22) | (_g << 12) | (_b << 2);
1950 // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1951 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1952 (t >> 24);
1953
1954 /* 24bpp formats */
1955 case PIXEL_FORMAT_RGB24:
1956 return (_r << 16) | (_g << 8) | _b;
1957
1958 case PIXEL_FORMAT_BGR24:
1959 return (_b << 16) | (_g << 8) | _r;
1960
1961 /* 16bpp formats */
1962 case PIXEL_FORMAT_RGB16:
1963 return (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_b >> 3) & 0x1F);
1964
1965 case PIXEL_FORMAT_BGR16:
1966 return (((_b >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_r >> 3) & 0x1F);
1967
1968 case PIXEL_FORMAT_ARGB15:
1969 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F) |
1970 (_a ? 0x8000 : 0x0000);
1971
1972 case PIXEL_FORMAT_ABGR15:
1973 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F) |
1974 (_a ? 0x8000 : 0x0000);
1975
1976 /* 15bpp formats */
1977 case PIXEL_FORMAT_RGB15:
1978 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F);
1979
1980 case PIXEL_FORMAT_BGR15:
1981 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F);
1982
1983 /* 8bpp formats */
1984 case PIXEL_FORMAT_RGB8:
1985
1986 /* 4 bpp formats */
1987 case PIXEL_FORMAT_A4:
1988
1989 /* 1bpp formats */
1990 case PIXEL_FORMAT_MONO:
1991 default:
1992 WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1993 return 0;
1994 }
1995}
1996
1997BOOL freerdp_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1998 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
1999 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
2000 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
2001 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
2002{
2003 static primitives_t* prims = nullptr;
2004 if (!prims)
2005 prims = primitives_get();
2006
2007 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
2008 return FALSE;
2009 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
2010 return FALSE;
2011
2012 if ((nWidth == 0) || (nHeight == 0))
2013 return TRUE;
2014
2015 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
2016 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
2017 if (nDstStep == 0)
2018 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
2019 if (nSrcStep == 0)
2020 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
2021
2022 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
2023 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
2024 WINPR_ASSERT(!overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
2025 WINPR_ASSERT(prims);
2026 WINPR_ASSERT(prims->copy_no_overlap);
2027 return prims->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
2028 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
2029 flags) == PRIMITIVES_SUCCESS;
2030}
WINPR_ATTR_NODISCARD fn_copy_no_overlap_t copy_no_overlap
Definition primitives.h:304