Coverage Report

Created: 2023-11-19 06:16

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