/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 | } |