FreeRDP
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 
46 BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data)
47 {
48  /*
49  * converts a 1-bit-per-pixel glyph to a one-byte-per-pixel glyph:
50  * this approach uses a little more memory, but provides faster
51  * means of accessing individual pixels in blitting operations
52  */
53  const UINT32 scanline = (width + 7) / 8;
54  BYTE* dstData = (BYTE*)winpr_aligned_malloc(1ull * width * height, 16);
55 
56  if (!dstData)
57  return NULL;
58 
59  ZeroMemory(dstData, 1ULL * width * height);
60  BYTE* dstp = dstData;
61 
62  for (UINT32 y = 0; y < height; y++)
63  {
64  const BYTE* srcp = &data[1ull * y * scanline];
65 
66  for (UINT32 x = 0; x < width; x++)
67  {
68  if ((*srcp & (0x80 >> (x % 8))) != 0)
69  *dstp = 0xFF;
70 
71  dstp++;
72 
73  if (((x + 1) % 8 == 0) && x != 0)
74  srcp++;
75  }
76  }
77 
78  return dstData;
79 }
80 
81 BOOL freerdp_image_copy_from_monochrome(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
82  UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
83  UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData,
84  UINT32 backColor, UINT32 foreColor,
85  const gdiPalette* WINPR_RESTRICT palette)
86 {
87  const UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
88 
89  if (!pDstData || !pSrcData || !palette)
90  return FALSE;
91 
92  if (nDstStep == 0)
93  nDstStep = dstBytesPerPixel * nWidth;
94 
95  const UINT32 monoStep = (nWidth + 7) / 8;
96 
97  for (size_t y = 0; y < nHeight; y++)
98  {
99  BYTE* pDstLine = &pDstData[((nYDst + y) * nDstStep)];
100  UINT32 monoBit = 0x80;
101  const BYTE* monoBits = &pSrcData[monoStep * y];
102 
103  for (size_t x = 0; x < nWidth; x++)
104  {
105  BYTE* pDstPixel = &pDstLine[((nXDst + x) * FreeRDPGetBytesPerPixel(DstFormat))];
106  BOOL monoPixel = (*monoBits & monoBit) ? TRUE : FALSE;
107 
108  if (!(monoBit >>= 1))
109  {
110  monoBits++;
111  monoBit = 0x80;
112  }
113 
114  if (monoPixel)
115  FreeRDPWriteColor_int(pDstPixel, DstFormat, backColor);
116  else
117  FreeRDPWriteColor_int(pDstPixel, DstFormat, foreColor);
118  }
119  }
120 
121  return TRUE;
122 }
123 
124 static INLINE UINT32 freerdp_image_inverted_pointer_color(UINT32 x, UINT32 y, UINT32 format)
125 {
126 #if 1
136  BYTE fill = (x + y) & 1 ? 0x00 : 0xFF;
137 #else
138  BYTE fill = 0x00;
139 #endif
140  return FreeRDPGetColor(format, fill, fill, fill, 0xFF);
141 }
142 
143 /*
144  * DIB color palettes are arrays of RGBQUAD structs with colors in BGRX format.
145  * They are used only by 1, 2, 4, and 8-bit bitmaps.
146  */
147 static void fill_gdi_palette_for_icon(const BYTE* colorTable, UINT16 cbColorTable,
148  gdiPalette* palette)
149 {
150  WINPR_ASSERT(palette);
151 
152  palette->format = PIXEL_FORMAT_BGRX32;
153  ZeroMemory(palette->palette, sizeof(palette->palette));
154 
155  if (!cbColorTable)
156  return;
157 
158  if ((cbColorTable % 4 != 0) || (cbColorTable / 4 > 256))
159  {
160  WLog_WARN(TAG, "weird palette size: %u", cbColorTable);
161  return;
162  }
163 
164  for (UINT16 i = 0; i < cbColorTable / 4; i++)
165  {
166  palette->palette[i] = FreeRDPReadColor_int(&colorTable[4ULL * i], palette->format);
167  }
168 }
169 
170 static INLINE UINT32 div_ceil(UINT32 a, UINT32 b)
171 {
172  return (a + (b - 1)) / b;
173 }
174 
175 static INLINE UINT32 round_up(UINT32 a, UINT32 b)
176 {
177  return b * div_ceil(a, b);
178 }
179 
180 BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
181  UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT16 nWidth,
182  UINT16 nHeight, const BYTE* WINPR_RESTRICT bitsColor,
183  UINT16 cbBitsColor, const BYTE* WINPR_RESTRICT bitsMask,
184  UINT16 cbBitsMask, const BYTE* WINPR_RESTRICT colorTable,
185  UINT16 cbColorTable, UINT32 bpp)
186 {
187  DWORD format = 0;
188  gdiPalette palette;
189 
190  if (!pDstData || !bitsColor)
191  return FALSE;
192 
193  /*
194  * Color formats used by icons are DIB bitmap formats (2-bit format
195  * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565,
196  * and that 32-bit format uses BGRA order.
197  */
198  switch (bpp)
199  {
200  case 1:
201  case 4:
202  /*
203  * These formats are not supported by freerdp_image_copy().
204  * PIXEL_FORMAT_MONO and PIXEL_FORMAT_A4 are *not* correct
205  * color formats for this. Please fix freerdp_image_copy()
206  * if you came here to fix a broken icon of some weird app
207  * that still uses 1 or 4bpp format in the 21st century.
208  */
209  WLog_WARN(TAG, "1bpp and 4bpp icons are not supported");
210  return FALSE;
211 
212  case 8:
213  format = PIXEL_FORMAT_RGB8;
214  break;
215 
216  case 16:
217  format = PIXEL_FORMAT_RGB15;
218  break;
219 
220  case 24:
221  format = PIXEL_FORMAT_RGB24;
222  break;
223 
224  case 32:
225  format = PIXEL_FORMAT_BGRA32;
226  break;
227 
228  default:
229  WLog_WARN(TAG, "invalid icon bpp: %" PRIu32, bpp);
230  return FALSE;
231  }
232 
233  /* Ensure we have enough source data bytes for image copy. */
234  if (cbBitsColor < nWidth * nHeight * FreeRDPGetBytesPerPixel(format))
235  return FALSE;
236 
237  fill_gdi_palette_for_icon(colorTable, cbColorTable, &palette);
238  if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
239  bitsColor, format, 0, 0, 0, &palette, FREERDP_FLIP_VERTICAL))
240  return FALSE;
241 
242  /* apply alpha mask */
243  if (FreeRDPColorHasAlpha(DstFormat) && cbBitsMask)
244  {
245  BYTE nextBit = 0;
246  const BYTE* maskByte = NULL;
247  UINT32 stride = 0;
248  BYTE r = 0;
249  BYTE g = 0;
250  BYTE b = 0;
251  BYTE* dstBuf = pDstData;
252  UINT32 dstBpp = FreeRDPGetBytesPerPixel(DstFormat);
253 
254  /*
255  * Each byte encodes 8 adjacent pixels (with LSB padding as needed).
256  * And due to hysterical raisins, stride of DIB bitmaps must be
257  * a multiple of 4 bytes.
258  */
259  stride = round_up(div_ceil(nWidth, 8), 4);
260 
261  for (UINT32 y = 0; y < nHeight; y++)
262  {
263  maskByte = &bitsMask[1ULL * stride * (nHeight - 1 - y)];
264  nextBit = 0x80;
265 
266  for (UINT32 x = 0; x < nWidth; x++)
267  {
268  UINT32 color = 0;
269  BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF;
270 
271  /* read color back, add alpha and write it back */
272  color = FreeRDPReadColor_int(dstBuf, DstFormat);
273  FreeRDPSplitColor(color, DstFormat, &r, &g, &b, NULL, &palette);
274  color = FreeRDPGetColor(DstFormat, r, g, b, alpha);
275  FreeRDPWriteColor_int(dstBuf, DstFormat, color);
276 
277  nextBit >>= 1;
278  dstBuf += dstBpp;
279  if (!nextBit)
280  {
281  nextBit = 0x80;
282  maskByte++;
283  }
284  }
285  }
286  }
287 
288  return TRUE;
289 }
290 
291 static BOOL freerdp_image_copy_from_pointer_data_1bpp(
292  BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
293  UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
294  const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp)
295 {
296  BOOL vFlip = 0;
297  UINT32 xorStep = 0;
298  UINT32 andStep = 0;
299  UINT32 xorBit = 0;
300  UINT32 andBit = 0;
301  UINT32 xorPixel = 0;
302  UINT32 andPixel = 0;
303 
304  vFlip = (xorBpp == 1) ? FALSE : TRUE;
305  andStep = (nWidth + 7) / 8;
306  andStep += (andStep % 2);
307 
308  if (!xorMask || (xorMaskLength == 0))
309  return FALSE;
310  if (!andMask || (andMaskLength == 0))
311  return FALSE;
312 
313  xorStep = (nWidth + 7) / 8;
314  xorStep += (xorStep % 2);
315 
316  if (xorStep * nHeight > xorMaskLength)
317  return FALSE;
318 
319  if (andStep * nHeight > andMaskLength)
320  return FALSE;
321 
322  for (UINT32 y = 0; y < nHeight; y++)
323  {
324  const BYTE* andBits = NULL;
325  const BYTE* xorBits = NULL;
326  BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
327  (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
328  xorBit = andBit = 0x80;
329 
330  if (!vFlip)
331  {
332  xorBits = &xorMask[1ULL * xorStep * y];
333  andBits = &andMask[1ULL * andStep * y];
334  }
335  else
336  {
337  xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
338  andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
339  }
340 
341  for (UINT32 x = 0; x < nWidth; x++)
342  {
343  UINT32 color = 0;
344  xorPixel = (*xorBits & xorBit) ? 1 : 0;
345 
346  if (!(xorBit >>= 1))
347  {
348  xorBits++;
349  xorBit = 0x80;
350  }
351 
352  andPixel = (*andBits & andBit) ? 1 : 0;
353 
354  if (!(andBit >>= 1))
355  {
356  andBits++;
357  andBit = 0x80;
358  }
359 
360  if (!andPixel && !xorPixel)
361  color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0xFF); /* black */
362  else if (!andPixel && xorPixel)
363  color = FreeRDPGetColor(DstFormat, 0xFF, 0xFF, 0xFF, 0xFF); /* white */
364  else if (andPixel && !xorPixel)
365  color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0); /* transparent */
366  else if (andPixel && xorPixel)
367  color = freerdp_image_inverted_pointer_color(x, y, DstFormat); /* inverted */
368 
369  FreeRDPWriteColor_int(pDstPixel, DstFormat, color);
370  pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
371  }
372  }
373 
374  return TRUE;
375 }
376 
377 static BOOL freerdp_image_copy_from_pointer_data_xbpp(
378  BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
379  UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
380  const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
381  const gdiPalette* palette)
382 {
383  BOOL vFlip = 0;
384  size_t xorStep = 0;
385  size_t andStep = 0;
386  UINT32 andBit = 0;
387  UINT32 xorPixel = 0;
388  UINT32 andPixel = 0;
389  UINT32 dstBitsPerPixel = 0;
390  UINT32 xorBytesPerPixel = 0;
391  dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
392 
393  vFlip = (xorBpp == 1) ? FALSE : TRUE;
394  andStep = (nWidth + 7) / 8;
395  andStep += (andStep % 2);
396 
397  if (!xorMask || (xorMaskLength == 0))
398  return FALSE;
399 
400  xorBytesPerPixel = xorBpp >> 3;
401  xorStep = 1ULL * nWidth * xorBytesPerPixel;
402  xorStep += (xorStep % 2);
403 
404  if (xorBpp == 8 && !palette)
405  {
406  WLog_ERR(TAG, "null palette in conversion from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
407  dstBitsPerPixel);
408  return FALSE;
409  }
410 
411  if (xorStep * nHeight > xorMaskLength)
412  return FALSE;
413 
414  if (andMask)
415  {
416  if (andStep * nHeight > andMaskLength)
417  return FALSE;
418  }
419 
420  for (UINT32 y = 0; y < nHeight; y++)
421  {
422  const BYTE* xorBits = NULL;
423  const BYTE* andBits = NULL;
424  BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
425  (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
426  andBit = 0x80;
427 
428  if (!vFlip)
429  {
430  if (andMask)
431  andBits = &andMask[andStep * y];
432 
433  xorBits = &xorMask[xorStep * y];
434  }
435  else
436  {
437  if (andMask)
438  andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
439 
440  xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
441  }
442 
443  for (UINT32 x = 0; x < nWidth; x++)
444  {
445  UINT32 pixelFormat = 0;
446  UINT32 color = 0;
447 
448  if (xorBpp == 32)
449  {
450  pixelFormat = PIXEL_FORMAT_BGRA32;
451  xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
452  }
453  else if (xorBpp == 16)
454  {
455  pixelFormat = PIXEL_FORMAT_RGB15;
456  xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
457  }
458  else if (xorBpp == 8)
459  {
460  pixelFormat = palette->format;
461  xorPixel = palette->palette[xorBits[0]];
462  }
463  else
464  {
465  pixelFormat = PIXEL_FORMAT_BGR24;
466  xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
467  }
468 
469  xorPixel = FreeRDPConvertColor(xorPixel, pixelFormat, PIXEL_FORMAT_ARGB32, palette);
470  xorBits += xorBytesPerPixel;
471  andPixel = 0;
472 
473  if (andMask)
474  {
475  andPixel = (*andBits & andBit) ? 1 : 0;
476 
477  if (!(andBit >>= 1))
478  {
479  andBits++;
480  andBit = 0x80;
481  }
482  }
483 
484  if (andPixel)
485  {
486  if (xorPixel == 0xFF000000) /* black -> transparent */
487  xorPixel = 0x00000000;
488  else if (xorPixel == 0xFFFFFFFF) /* white -> inverted */
489  xorPixel = freerdp_image_inverted_pointer_color(x, y, PIXEL_FORMAT_ARGB32);
490  }
491 
492  color = FreeRDPConvertColor(xorPixel, PIXEL_FORMAT_ARGB32, DstFormat, palette);
493  FreeRDPWriteColor_int(pDstPixel, DstFormat, color);
494  pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
495  }
496  }
497 
498  return TRUE;
499 }
500 
509 BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
510  UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
511  UINT32 nWidth, UINT32 nHeight,
512  const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
513  const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
514  UINT32 xorBpp, const gdiPalette* WINPR_RESTRICT palette)
515 {
516  UINT32 dstBitsPerPixel = 0;
517  UINT32 dstBytesPerPixel = 0;
518  dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
519  dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
520 
521  if (nDstStep <= 0)
522  nDstStep = dstBytesPerPixel * nWidth;
523 
524  for (UINT32 y = nYDst; y < nHeight; y++)
525  {
526  BYTE* WINPR_RESTRICT pDstLine = &pDstData[y * nDstStep + nXDst * dstBytesPerPixel];
527  memset(pDstLine, 0, 1ull * dstBytesPerPixel * (nWidth - nXDst));
528  }
529 
530  switch (xorBpp)
531  {
532  case 1:
533  return freerdp_image_copy_from_pointer_data_1bpp(
534  pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
535  xorMaskLength, andMask, andMaskLength, xorBpp);
536 
537  case 8:
538  case 16:
539  case 24:
540  case 32:
541  return freerdp_image_copy_from_pointer_data_xbpp(
542  pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
543  xorMaskLength, andMask, andMaskLength, xorBpp, palette);
544 
545  default:
546  WLog_ERR(TAG, "failed to convert from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
547  dstBitsPerPixel);
548  return FALSE;
549  }
550 }
551 
552 static INLINE BOOL overlapping(const BYTE* pDstData, UINT32 nYDst, UINT32 nDstStep,
553  const BYTE* pSrcData, UINT32 nYSrc, UINT32 nSrcStep, UINT32 nHeight)
554 {
555  const uintptr_t src = (uintptr_t)pSrcData;
556  const uintptr_t srcstart = src + 1ULL * nSrcStep * nYSrc;
557  const uintptr_t srcend = srcstart + 1ULL * nSrcStep * nHeight;
558  const uintptr_t dst = (uintptr_t)pDstData;
559  const uintptr_t dststart = dst + 1ULL * nDstStep * nYDst;
560  const uintptr_t dstend = dststart + 1ULL * nDstStep * nHeight;
561 
562  if ((dststart >= srcstart) && (dststart <= srcend))
563  return TRUE;
564 
565  if ((dstend >= srcstart) && (dstend <= srcend))
566  return TRUE;
567 
568  return FALSE;
569 }
570 
571 static INLINE BOOL freerdp_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
572  UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
573  UINT32 nHeight,
574  const BYTE* WINPR_RESTRICT pSrcData,
575  UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
576  SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
577  SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
578 {
579 
580  const SSIZE_T srcByte = 3;
581  const SSIZE_T dstByte = 4;
582 
583  for (SSIZE_T y = 0; y < nHeight; y++)
584  {
585  const BYTE* WINPR_RESTRICT srcLine =
586  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
587  BYTE* WINPR_RESTRICT dstLine =
588  &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
589 
590  for (SSIZE_T x = 0; x < nWidth; x++)
591  {
592  dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
593  dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
594  dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
595  }
596  }
597 
598  return TRUE;
599 }
600 
601 static INLINE BOOL freerdp_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
602  UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
603  UINT32 nHeight,
604  const BYTE* WINPR_RESTRICT pSrcData,
605  UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
606  SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
607  SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
608 {
609 
610  const SSIZE_T srcByte = 4;
611  const SSIZE_T dstByte = 4;
612 
613  for (SSIZE_T y = 0; y < nHeight; y++)
614  {
615  const BYTE* WINPR_RESTRICT srcLine =
616  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
617  BYTE* WINPR_RESTRICT dstLine =
618  &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
619 
620  for (SSIZE_T x = 0; x < nWidth; x++)
621  {
622  dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
623  dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
624  dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
625  }
626  }
627 
628  return TRUE;
629 }
630 
631 static INLINE BOOL freerdp_image_copy_generic(
632  BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
633  UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcFormat,
634  UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
635  SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
636 {
637 
638  const SSIZE_T srcByte = 4;
639  const SSIZE_T dstByte = 4;
640 
641  for (SSIZE_T y = 0; y < nHeight; y++)
642  {
643  const BYTE* WINPR_RESTRICT srcLine =
644  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
645  BYTE* WINPR_RESTRICT dstLine =
646  &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
647 
648  UINT32 color = FreeRDPReadColor_int(&srcLine[nXSrc * srcByte], SrcFormat);
649  UINT32 oldColor = color;
650  UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
651  FreeRDPWriteColorIgnoreAlpha_int(&dstLine[nXDst * dstByte], DstFormat, dstColor);
652  for (SSIZE_T x = 1; x < nWidth; x++)
653  {
654  color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
655  if (color == oldColor)
656  {
657  FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
658  dstColor);
659  }
660  else
661  {
662  oldColor = color;
663  dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
664  FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
665  dstColor);
666  }
667  }
668  }
669 
670  return TRUE;
671 }
672 
673 static INLINE BOOL freerdp_image_copy_no_overlap_dst_alpha(
674  BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
675  UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
676  UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
677  SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
678 {
679  WINPR_ASSERT(pDstData);
680  WINPR_ASSERT(pSrcData);
681 
682  switch (SrcFormat)
683  {
684  case PIXEL_FORMAT_BGR24:
685  switch (DstFormat)
686  {
687  case PIXEL_FORMAT_BGRX32:
688  case PIXEL_FORMAT_BGRA32:
689  return freerdp_image_copy_bgr24_bgrx32(
690  pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
691  nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
692  default:
693  break;
694  }
695  break;
696  case PIXEL_FORMAT_BGRX32:
697  case PIXEL_FORMAT_BGRA32:
698  switch (DstFormat)
699  {
700  case PIXEL_FORMAT_BGRX32:
701  case PIXEL_FORMAT_BGRA32:
702  return freerdp_image_copy_bgrx32_bgrx32(
703  pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
704  nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
705  default:
706  break;
707  }
708  break;
709  default:
710  break;
711  }
712 
713  return freerdp_image_copy_generic(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
714  pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
715  srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
716 }
717 
718 BOOL freerdp_image_copy_overlap(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
719  UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
720  DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
721  const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
722 {
723  const UINT32 dstByte = FreeRDPGetBytesPerPixel(DstFormat);
724  const UINT32 srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
725  const UINT32 copyDstWidth = nWidth * dstByte;
726  const UINT32 xSrcOffset = nXSrc * srcByte;
727  const UINT32 xDstOffset = nXDst * dstByte;
728  const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) ? TRUE : FALSE;
729  SSIZE_T srcVOffset = 0;
730  SSIZE_T srcVMultiplier = 1;
731  SSIZE_T dstVOffset = 0;
732  SSIZE_T dstVMultiplier = 1;
733 
734  WINPR_ASSERT(overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
735 
736  if ((nWidth == 0) || (nHeight == 0))
737  return TRUE;
738 
739  if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
740  return FALSE;
741 
742  if (!pDstData || !pSrcData)
743  return FALSE;
744 
745  if (nDstStep == 0)
746  nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
747 
748  if (nSrcStep == 0)
749  nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
750 
751  if (vSrcVFlip)
752  {
753  srcVOffset = (nHeight - 1ll) * nSrcStep;
754  srcVMultiplier = -1;
755  }
756 
757  if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
758  {
759  return freerdp_image_copy_no_overlap_dst_alpha(
760  pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
761  nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
762  dstVOffset);
763  }
764  else if (FreeRDPAreColorFormatsEqualNoAlpha_int(SrcFormat, DstFormat))
765  {
766  /* Copy down */
767  if (nYDst < nYSrc)
768  {
769  for (SSIZE_T y = 0; y < nHeight; y++)
770  {
771  const BYTE* srcLine =
772  &pSrcData[(y + nYSrc) * nSrcStep * srcVMultiplier + srcVOffset];
773  BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
774  memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
775  }
776  }
777  /* Copy up */
778  else if (nYDst > nYSrc)
779  {
780  for (SSIZE_T y = nHeight - 1; y >= 0; y--)
781  {
782  const BYTE* srcLine =
783  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
784  BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
785  memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
786  }
787  }
788  /* Copy left */
789  else if (nXSrc > nXDst)
790  {
791  for (SSIZE_T y = 0; y < nHeight; y++)
792  {
793  const BYTE* srcLine =
794  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
795  BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
796  memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
797  }
798  }
799  /* Copy right */
800  else if (nXSrc < nXDst)
801  {
802  for (SSIZE_T y = nHeight - 1; y >= 0; y--)
803  {
804  const BYTE* srcLine =
805  &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
806  BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
807  memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
808  }
809  }
810  /* Source and destination are equal... */
811  else
812  {
813  }
814  }
815  else
816  {
817  for (SSIZE_T y = 0; y < nHeight; y++)
818  {
819  const BYTE* srcLine = &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
820  BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
821 
822  UINT32 color = FreeRDPReadColor_int(&srcLine[1ULL * nXSrc * srcByte], SrcFormat);
823  UINT32 oldColor = color;
824  UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
825  FreeRDPWriteColor_int(&dstLine[1ULL * nXDst * dstByte], DstFormat, dstColor);
826  for (SSIZE_T x = 1; x < nWidth; x++)
827  {
828  color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
829  if (color == oldColor)
830  {
831  FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
832  }
833  else
834  {
835  oldColor = color;
836  dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
837  FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
838  }
839  }
840  }
841  }
842 
843  return TRUE;
844 }
845 
846 BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
847  UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
848  DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
849  const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
850 {
851  if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
852  return FALSE;
853 
854  if (!pDstData || !pSrcData)
855  return FALSE;
856 
857  if ((nWidth == 0) || (nHeight == 0))
858  return TRUE;
859 
860  if (nDstStep == 0)
861  nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
862 
863  if (nSrcStep == 0)
864  nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
865 
866  const BOOL ovl = overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight);
867  if (ovl)
868  return freerdp_image_copy_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
869  nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
870  palette, flags);
871  return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
872  nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
873  palette, flags);
874 }
875 
876 BOOL freerdp_image_fill(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
877  UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color)
878 {
879  if ((nWidth == 0) || (nHeight == 0))
880  return TRUE;
881  const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
882  BYTE* WINPR_RESTRICT pFirstDstLine = NULL;
883  BYTE* WINPR_RESTRICT pFirstDstLineXOffset = NULL;
884 
885  if (nDstStep == 0)
886  nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
887 
888  pFirstDstLine = &pDstData[1ULL * nYDst * nDstStep];
889  pFirstDstLineXOffset = &pFirstDstLine[1ULL * nXDst * bpp];
890 
891  for (size_t x = 0; x < nWidth; x++)
892  {
893  BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp];
894  FreeRDPWriteColor_int(pDst, DstFormat, color);
895  }
896 
897  for (size_t y = 1; y < nHeight; y++)
898  {
899  BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + 1ULL * nXDst * bpp];
900  memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp);
901  }
902 
903  return TRUE;
904 }
905 
906 #if defined(WITH_SWSCALE)
907 static int av_format_for_buffer(UINT32 format)
908 {
909  switch (format)
910  {
911  case PIXEL_FORMAT_ARGB32:
912  return AV_PIX_FMT_BGRA;
913 
914  case PIXEL_FORMAT_XRGB32:
915  return AV_PIX_FMT_BGR0;
916 
917  case PIXEL_FORMAT_BGRA32:
918  return AV_PIX_FMT_RGBA;
919 
920  case PIXEL_FORMAT_BGRX32:
921  return AV_PIX_FMT_RGB0;
922 
923  default:
924  return AV_PIX_FMT_NONE;
925  }
926 }
927 #endif
928 
929 BOOL freerdp_image_scale(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
930  UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
931  const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
932  UINT32 nXSrc, UINT32 nYSrc, UINT32 nSrcWidth, UINT32 nSrcHeight)
933 {
934  BOOL rc = FALSE;
935 
936  if (nDstStep == 0)
937  nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat);
938 
939  if (nSrcStep == 0)
940  nSrcStep = nSrcWidth * FreeRDPGetBytesPerPixel(SrcFormat);
941 
942 #if defined(WITH_SWSCALE) || defined(WITH_CAIRO)
943  const BYTE* src = &pSrcData[nXSrc * FreeRDPGetBytesPerPixel(SrcFormat) + nYSrc * nSrcStep];
944  BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
945 #endif
946 
947  /* direct copy is much faster than scaling, so check if we can simply copy... */
948  if ((nDstWidth == nSrcWidth) && (nDstHeight == nSrcHeight))
949  {
950  return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
951  nDstHeight, pSrcData, SrcFormat, nSrcStep, nXSrc,
952  nYSrc, NULL, FREERDP_FLIP_NONE);
953  }
954  else
955 #if defined(WITH_SWSCALE)
956  {
957  int res = 0;
958  struct SwsContext* resize = NULL;
959  int srcFormat = av_format_for_buffer(SrcFormat);
960  int dstFormat = av_format_for_buffer(DstFormat);
961  const int srcStep[1] = { (int)nSrcStep };
962  const int dstStep[1] = { (int)nDstStep };
963 
964  if ((srcFormat == AV_PIX_FMT_NONE) || (dstFormat == AV_PIX_FMT_NONE))
965  return FALSE;
966 
967  resize = sws_getContext((int)nSrcWidth, (int)nSrcHeight, srcFormat, (int)nDstWidth,
968  (int)nDstHeight, dstFormat, SWS_BILINEAR, NULL, NULL, NULL);
969 
970  if (!resize)
971  goto fail;
972 
973  res = sws_scale(resize, &src, srcStep, 0, (int)nSrcHeight, &dst, dstStep);
974  rc = (res == ((int)nDstHeight));
975  fail:
976  sws_freeContext(resize);
977  }
978 
979 #elif defined(WITH_CAIRO)
980  {
981  const double sx = (double)nDstWidth / (double)nSrcWidth;
982  const double sy = (double)nDstHeight / (double)nSrcHeight;
983  cairo_t* cairo_context;
984  cairo_surface_t *csrc, *cdst;
985 
986  if ((nSrcWidth > INT_MAX) || (nSrcHeight > INT_MAX) || (nSrcStep > INT_MAX))
987  return FALSE;
988 
989  if ((nDstWidth > INT_MAX) || (nDstHeight > INT_MAX) || (nDstStep > INT_MAX))
990  return FALSE;
991 
992  csrc = cairo_image_surface_create_for_data((void*)src, CAIRO_FORMAT_ARGB32, (int)nSrcWidth,
993  (int)nSrcHeight, (int)nSrcStep);
994  cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, (int)nDstWidth,
995  (int)nDstHeight, (int)nDstStep);
996 
997  if (!csrc || !cdst)
998  goto fail;
999 
1000  cairo_context = cairo_create(cdst);
1001 
1002  if (!cairo_context)
1003  goto fail2;
1004 
1005  cairo_scale(cairo_context, sx, sy);
1006  cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
1007  cairo_set_source_surface(cairo_context, csrc, 0, 0);
1008  cairo_paint(cairo_context);
1009  rc = TRUE;
1010  fail2:
1011  cairo_destroy(cairo_context);
1012  fail:
1013  cairo_surface_destroy(csrc);
1014  cairo_surface_destroy(cdst);
1015  }
1016 #else
1017  {
1018  WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!");
1019  }
1020 #endif
1021  return rc;
1022 }
1023 
1024 DWORD FreeRDPAreColorFormatsEqualNoAlpha(DWORD first, DWORD second)
1025 {
1026  return FreeRDPAreColorFormatsEqualNoAlpha_int(first, second);
1027 }
1028 
1029 const char* FreeRDPGetColorFormatName(UINT32 format)
1030 {
1031  switch (format)
1032  {
1033  /* 32bpp formats */
1034  case PIXEL_FORMAT_ARGB32:
1035  return "PIXEL_FORMAT_ARGB32";
1036 
1037  case PIXEL_FORMAT_XRGB32:
1038  return "PIXEL_FORMAT_XRGB32";
1039 
1040  case PIXEL_FORMAT_ABGR32:
1041  return "PIXEL_FORMAT_ABGR32";
1042 
1043  case PIXEL_FORMAT_XBGR32:
1044  return "PIXEL_FORMAT_XBGR32";
1045 
1046  case PIXEL_FORMAT_BGRA32:
1047  return "PIXEL_FORMAT_BGRA32";
1048 
1049  case PIXEL_FORMAT_BGRX32:
1050  return "PIXEL_FORMAT_BGRX32";
1051 
1052  case PIXEL_FORMAT_RGBA32:
1053  return "PIXEL_FORMAT_RGBA32";
1054 
1055  case PIXEL_FORMAT_RGBX32:
1056  return "PIXEL_FORMAT_RGBX32";
1057 
1058  case PIXEL_FORMAT_BGRX32_DEPTH30:
1059  return "PIXEL_FORMAT_BGRX32_DEPTH30";
1060 
1061  case PIXEL_FORMAT_RGBX32_DEPTH30:
1062  return "PIXEL_FORMAT_RGBX32_DEPTH30";
1063 
1064  /* 24bpp formats */
1065  case PIXEL_FORMAT_RGB24:
1066  return "PIXEL_FORMAT_RGB24";
1067 
1068  case PIXEL_FORMAT_BGR24:
1069  return "PIXEL_FORMAT_BGR24";
1070 
1071  /* 16bpp formats */
1072  case PIXEL_FORMAT_RGB16:
1073  return "PIXEL_FORMAT_RGB16";
1074 
1075  case PIXEL_FORMAT_BGR16:
1076  return "PIXEL_FORMAT_BGR16";
1077 
1078  case PIXEL_FORMAT_ARGB15:
1079  return "PIXEL_FORMAT_ARGB15";
1080 
1081  case PIXEL_FORMAT_RGB15:
1082  return "PIXEL_FORMAT_RGB15";
1083 
1084  case PIXEL_FORMAT_ABGR15:
1085  return "PIXEL_FORMAT_ABGR15";
1086 
1087  case PIXEL_FORMAT_BGR15:
1088  return "PIXEL_FORMAT_BGR15";
1089 
1090  /* 8bpp formats */
1091  case PIXEL_FORMAT_RGB8:
1092  return "PIXEL_FORMAT_RGB8";
1093 
1094  /* 4 bpp formats */
1095  case PIXEL_FORMAT_A4:
1096  return "PIXEL_FORMAT_A4";
1097 
1098  /* 1bpp formats */
1099  case PIXEL_FORMAT_MONO:
1100  return "PIXEL_FORMAT_MONO";
1101 
1102  default:
1103  return "UNKNOWN";
1104  }
1105 }
1106 
1107 void FreeRDPSplitColor(UINT32 color, UINT32 format, BYTE* _r, BYTE* _g, BYTE* _b, BYTE* _a,
1108  const gdiPalette* palette)
1109 {
1110  UINT32 tmp = 0;
1111 
1112  switch (format)
1113  {
1114  /* 32bpp formats */
1115  case PIXEL_FORMAT_ARGB32:
1116  if (_a)
1117  *_a = (BYTE)(color >> 24);
1118 
1119  if (_r)
1120  *_r = (BYTE)(color >> 16);
1121 
1122  if (_g)
1123  *_g = (BYTE)(color >> 8);
1124 
1125  if (_b)
1126  *_b = (BYTE)color;
1127 
1128  break;
1129 
1130  case PIXEL_FORMAT_XRGB32:
1131  if (_r)
1132  *_r = (BYTE)(color >> 16);
1133 
1134  if (_g)
1135  *_g = (BYTE)(color >> 8);
1136 
1137  if (_b)
1138  *_b = (BYTE)color;
1139 
1140  if (_a)
1141  *_a = 0xFF;
1142 
1143  break;
1144 
1145  case PIXEL_FORMAT_ABGR32:
1146  if (_a)
1147  *_a = (BYTE)(color >> 24);
1148 
1149  if (_b)
1150  *_b = (BYTE)(color >> 16);
1151 
1152  if (_g)
1153  *_g = (BYTE)(color >> 8);
1154 
1155  if (_r)
1156  *_r = (BYTE)color;
1157 
1158  break;
1159 
1160  case PIXEL_FORMAT_XBGR32:
1161  if (_b)
1162  *_b = (BYTE)(color >> 16);
1163 
1164  if (_g)
1165  *_g = (BYTE)(color >> 8);
1166 
1167  if (_r)
1168  *_r = (BYTE)color;
1169 
1170  if (_a)
1171  *_a = 0xFF;
1172 
1173  break;
1174 
1175  case PIXEL_FORMAT_RGBA32:
1176  if (_r)
1177  *_r = (BYTE)(color >> 24);
1178 
1179  if (_g)
1180  *_g = (BYTE)(color >> 16);
1181 
1182  if (_b)
1183  *_b = (BYTE)(color >> 8);
1184 
1185  if (_a)
1186  *_a = (BYTE)color;
1187 
1188  break;
1189 
1190  case PIXEL_FORMAT_RGBX32:
1191  if (_r)
1192  *_r = (BYTE)(color >> 24);
1193 
1194  if (_g)
1195  *_g = (BYTE)(color >> 16);
1196 
1197  if (_b)
1198  *_b = (BYTE)(color >> 8);
1199 
1200  if (_a)
1201  *_a = 0xFF;
1202 
1203  break;
1204 
1205  case PIXEL_FORMAT_BGRA32:
1206  if (_b)
1207  *_b = (BYTE)(color >> 24);
1208 
1209  if (_g)
1210  *_g = (BYTE)(color >> 16);
1211 
1212  if (_r)
1213  *_r = (BYTE)(color >> 8);
1214 
1215  if (_a)
1216  *_a = (BYTE)color;
1217 
1218  break;
1219 
1220  case PIXEL_FORMAT_BGRX32:
1221  if (_b)
1222  *_b = (BYTE)(color >> 24);
1223 
1224  if (_g)
1225  *_g = (BYTE)(color >> 16);
1226 
1227  if (_r)
1228  *_r = (BYTE)(color >> 8);
1229 
1230  if (_a)
1231  *_a = 0xFF;
1232 
1233  break;
1234 
1235  /* 24bpp formats */
1236  case PIXEL_FORMAT_RGB24:
1237  if (_r)
1238  *_r = (BYTE)(color >> 16);
1239 
1240  if (_g)
1241  *_g = (BYTE)(color >> 8);
1242 
1243  if (_b)
1244  *_b = (BYTE)color;
1245 
1246  if (_a)
1247  *_a = 0xFF;
1248 
1249  break;
1250 
1251  case PIXEL_FORMAT_BGR24:
1252  if (_b)
1253  *_b = (BYTE)(color >> 16);
1254 
1255  if (_g)
1256  *_g = (BYTE)(color >> 8);
1257 
1258  if (_r)
1259  *_r = (BYTE)color;
1260 
1261  if (_a)
1262  *_a = 0xFF;
1263 
1264  break;
1265 
1266  /* 16bpp formats */
1267  case PIXEL_FORMAT_RGB16:
1268  if (_r)
1269  {
1270  const UINT32 c = (color >> 11) & 0x1F;
1271  const UINT32 val = (c << 3) + c / 4;
1272  *_r = (BYTE)(val > 255 ? 255 : val);
1273  }
1274 
1275  if (_g)
1276  {
1277  const UINT32 c = (color >> 5) & 0x3F;
1278  const UINT32 val = (c << 2) + c / 4 / 2;
1279  *_g = (BYTE)(val > 255 ? 255 : val);
1280  }
1281 
1282  if (_b)
1283  {
1284  const UINT32 c = (color)&0x1F;
1285  const UINT32 val = (c << 3) + c / 4;
1286  *_b = (BYTE)(val > 255 ? 255 : val);
1287  }
1288 
1289  if (_a)
1290  *_a = 0xFF;
1291 
1292  break;
1293 
1294  case PIXEL_FORMAT_BGR16:
1295  if (_r)
1296  {
1297  const UINT32 c = (color)&0x1F;
1298  const UINT32 val = (c << 3) + c / 4;
1299  *_r = (BYTE)(val > 255 ? 255 : val);
1300  }
1301 
1302  if (_g)
1303  {
1304  const UINT32 c = (color >> 5) & 0x3F;
1305  const UINT32 val = (c << 2) + c / 4 / 2;
1306  *_g = (BYTE)(val > 255 ? 255 : val);
1307  }
1308 
1309  if (_b)
1310  {
1311  const UINT32 c = (color >> 11) & 0x1F;
1312  const UINT32 val = (c << 3) + c / 4;
1313  *_b = (BYTE)(val > 255 ? 255 : val);
1314  }
1315 
1316  if (_a)
1317  *_a = 0xFF;
1318 
1319  break;
1320 
1321  case PIXEL_FORMAT_ARGB15:
1322  if (_r)
1323  {
1324  const UINT32 c = (color >> 10) & 0x1F;
1325  const UINT32 val = (c << 3) + c / 4;
1326  *_r = (BYTE)(val > 255 ? 255 : val);
1327  }
1328 
1329  if (_g)
1330  {
1331  const UINT32 c = (color >> 5) & 0x1F;
1332  const UINT32 val = (c << 3) + c / 4;
1333  *_g = (BYTE)(val > 255 ? 255 : val);
1334  }
1335 
1336  if (_b)
1337  {
1338  const UINT32 c = (color)&0x1F;
1339  const UINT32 val = (c << 3) + c / 4;
1340  *_b = (BYTE)(val > 255 ? 255 : val);
1341  }
1342 
1343  if (_a)
1344  *_a = color & 0x8000 ? 0xFF : 0x00;
1345 
1346  break;
1347 
1348  case PIXEL_FORMAT_ABGR15:
1349  if (_r)
1350  {
1351  const UINT32 c = (color)&0x1F;
1352  const UINT32 val = (c << 3) + c / 4;
1353  *_r = (BYTE)(val > 255 ? 255 : val);
1354  }
1355 
1356  if (_g)
1357  {
1358  const UINT32 c = (color >> 5) & 0x1F;
1359  const UINT32 val = (c << 3) + c / 4;
1360  *_g = (BYTE)(val > 255 ? 255 : val);
1361  }
1362 
1363  if (_b)
1364  {
1365  const UINT32 c = (color >> 10) & 0x1F;
1366  const UINT32 val = (c << 3) + c / 4;
1367  *_b = (BYTE)(val > 255 ? 255 : val);
1368  }
1369 
1370  if (_a)
1371  *_a = color & 0x8000 ? 0xFF : 0x00;
1372 
1373  break;
1374 
1375  /* 15bpp formats */
1376  case PIXEL_FORMAT_RGB15:
1377  if (_r)
1378  {
1379  const UINT32 c = (color >> 10) & 0x1F;
1380  const UINT32 val = (c << 3) + c / 4;
1381  *_r = (BYTE)(val > 255 ? 255 : val);
1382  }
1383 
1384  if (_g)
1385  {
1386  const UINT32 c = (color >> 5) & 0x1F;
1387  const UINT32 val = (c << 3) + c / 4;
1388  *_g = (BYTE)(val > 255 ? 255 : val);
1389  }
1390 
1391  if (_b)
1392  {
1393  const UINT32 c = (color)&0x1F;
1394  const UINT32 val = (c << 3) + c / 4;
1395  *_b = (BYTE)(val > 255 ? 255 : val);
1396  }
1397 
1398  if (_a)
1399  *_a = 0xFF;
1400 
1401  break;
1402 
1403  case PIXEL_FORMAT_BGR15:
1404  if (_r)
1405  {
1406  const UINT32 c = (color)&0x1F;
1407  const UINT32 val = (c << 3) + c / 4;
1408  *_r = (BYTE)(val > 255 ? 255 : val);
1409  }
1410 
1411  if (_g)
1412  {
1413  const UINT32 c = (color >> 5) & 0x1F;
1414  const UINT32 val = (c << 3) + c / 4;
1415  *_g = (BYTE)(val > 255 ? 255 : val);
1416  }
1417 
1418  if (_b)
1419  {
1420  const UINT32 c = (color >> 10) & 0x1F;
1421  const UINT32 val = (c << 3) + c / 4;
1422  *_b = (BYTE)(val > 255 ? 255 : val);
1423  }
1424 
1425  if (_a)
1426  *_a = 0xFF;
1427 
1428  break;
1429 
1430  /* 8bpp formats */
1431  case PIXEL_FORMAT_RGB8:
1432  if (color <= 0xFF)
1433  {
1434  tmp = palette->palette[color];
1435  FreeRDPSplitColor(tmp, palette->format, _r, _g, _b, _a, NULL);
1436  }
1437  else
1438  {
1439  if (_r)
1440  *_r = 0x00;
1441 
1442  if (_g)
1443  *_g = 0x00;
1444 
1445  if (_b)
1446  *_b = 0x00;
1447 
1448  if (_a)
1449  *_a = 0x00;
1450  }
1451 
1452  break;
1453 
1454  /* 1bpp formats */
1455  case PIXEL_FORMAT_MONO:
1456  if (_r)
1457  *_r = (color) ? 0xFF : 0x00;
1458 
1459  if (_g)
1460  *_g = (color) ? 0xFF : 0x00;
1461 
1462  if (_b)
1463  *_b = (color) ? 0xFF : 0x00;
1464 
1465  if (_a)
1466  *_a = (color) ? 0xFF : 0x00;
1467 
1468  break;
1469 
1470  /* 4 bpp formats */
1471  case PIXEL_FORMAT_A4:
1472  default:
1473  if (_r)
1474  *_r = 0x00;
1475 
1476  if (_g)
1477  *_g = 0x00;
1478 
1479  if (_b)
1480  *_b = 0x00;
1481 
1482  if (_a)
1483  *_a = 0x00;
1484 
1485  WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1486  break;
1487  }
1488 }
1489 
1490 BOOL FreeRDPWriteColorIgnoreAlpha(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1491 {
1492  return FreeRDPWriteColorIgnoreAlpha_int(dst, format, color);
1493 }
1494 
1495 BOOL FreeRDPWriteColor(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1496 {
1497  return FreeRDPWriteColor_int(dst, format, color);
1498 }
1499 
1500 UINT32 FreeRDPReadColor(const BYTE* WINPR_RESTRICT src, UINT32 format)
1501 {
1502  return FreeRDPReadColor_int(src, format);
1503 }
1504 
1505 UINT32 FreeRDPGetColor(UINT32 format, BYTE r, BYTE g, BYTE b, BYTE a)
1506 {
1507  UINT32 _r = r;
1508  UINT32 _g = g;
1509  UINT32 _b = b;
1510  UINT32 _a = a;
1511  UINT32 t = 0;
1512 
1513  switch (format)
1514  {
1515  /* 32bpp formats */
1516  case PIXEL_FORMAT_ARGB32:
1517  return (_a << 24) | (_r << 16) | (_g << 8) | _b;
1518 
1519  case PIXEL_FORMAT_XRGB32:
1520  return (_r << 16) | (_g << 8) | _b;
1521 
1522  case PIXEL_FORMAT_ABGR32:
1523  return (_a << 24) | (_b << 16) | (_g << 8) | _r;
1524 
1525  case PIXEL_FORMAT_XBGR32:
1526  return (_b << 16) | (_g << 8) | _r;
1527 
1528  case PIXEL_FORMAT_RGBA32:
1529  return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1530 
1531  case PIXEL_FORMAT_RGBX32:
1532  return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1533 
1534  case PIXEL_FORMAT_BGRA32:
1535  return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1536 
1537  case PIXEL_FORMAT_BGRX32:
1538  return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1539 
1540  case PIXEL_FORMAT_RGBX32_DEPTH30:
1541  // TODO: Not tested
1542  t = (_r << 22) | (_g << 12) | (_b << 2);
1543  // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1544  return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1545  (t >> 24);
1546 
1547  case PIXEL_FORMAT_BGRX32_DEPTH30:
1548  // NOTE: Swapping b and r channel (unknown reason)
1549  t = (_r << 22) | (_g << 12) | (_b << 2);
1550  // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1551  return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1552  (t >> 24);
1553 
1554  /* 24bpp formats */
1555  case PIXEL_FORMAT_RGB24:
1556  return (_r << 16) | (_g << 8) | _b;
1557 
1558  case PIXEL_FORMAT_BGR24:
1559  return (_b << 16) | (_g << 8) | _r;
1560 
1561  /* 16bpp formats */
1562  case PIXEL_FORMAT_RGB16:
1563  return (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_b >> 3) & 0x1F);
1564 
1565  case PIXEL_FORMAT_BGR16:
1566  return (((_b >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_r >> 3) & 0x1F);
1567 
1568  case PIXEL_FORMAT_ARGB15:
1569  return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F) |
1570  (_a ? 0x8000 : 0x0000);
1571 
1572  case PIXEL_FORMAT_ABGR15:
1573  return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F) |
1574  (_a ? 0x8000 : 0x0000);
1575 
1576  /* 15bpp formats */
1577  case PIXEL_FORMAT_RGB15:
1578  return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F);
1579 
1580  case PIXEL_FORMAT_BGR15:
1581  return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F);
1582 
1583  /* 8bpp formats */
1584  case PIXEL_FORMAT_RGB8:
1585 
1586  /* 4 bpp formats */
1587  case PIXEL_FORMAT_A4:
1588 
1589  /* 1bpp formats */
1590  case PIXEL_FORMAT_MONO:
1591  default:
1592  WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1593  return 0;
1594  }
1595 }
1596 
1597 BOOL freerdp_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1598  UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
1599  const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
1600  UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1601  const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1602 {
1603  static primitives_t* prims = NULL;
1604  if (!prims)
1605  prims = primitives_get();
1606 
1607  WINPR_ASSERT(!overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
1608  WINPR_ASSERT(prims);
1609  WINPR_ASSERT(prims->copy_no_overlap);
1610  return prims->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
1611  pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
1612  flags) == PRIMITIVES_SUCCESS;
1613 }
__copy_no_overlap_t copy_no_overlap
Definition: primitives.h:258