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