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