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