FreeRDP
Loading...
Searching...
No Matches
libfreerdp/codec/include/bitmap.h
1
22#include <winpr/assert.h>
23#include <winpr/cast.h>
24#include <winpr/wtypes.h>
25
26/* do not compile the file directly */
27
31WINPR_ATTR_NODISCARD
32static inline BYTE* WRITEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
33 const BYTE* WINPR_RESTRICT pbDestEnd, UINT32 rowDelta,
34 BYTE bitmask, PIXEL fgPel, UINT32 cBits)
35{
36 PIXEL xorPixel = 0;
37 BYTE mask = 0x01;
38
39 if (cBits > 8)
40 {
41 WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
42 return nullptr;
43 }
44
45 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
46 return nullptr;
47
48 UNROLL(cBits, {
49 PIXEL data = 0;
50 DESTREADPIXEL(xorPixel, pbDest - rowDelta);
51
52 if (bitmask & mask)
53 data = xorPixel ^ fgPel;
54 else
55 data = xorPixel;
56
57 DESTWRITEPIXEL(pbDest, data);
58 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
59 });
60 return pbDest;
61}
62
67WINPR_ATTR_NODISCARD
68static inline BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
69 const BYTE* WINPR_RESTRICT pbDestEnd, BYTE bitmask,
70 PIXEL fgPel, UINT32 cBits)
71{
72 BYTE mask = 0x01;
73
74 if (cBits > 8)
75 {
76 WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
77 return nullptr;
78 }
79
80 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
81 return nullptr;
82
83 UNROLL(cBits, {
84 PIXEL data;
85
86 if (bitmask & mask)
87 data = fgPel;
88 else
89 data = BLACK_PIXEL;
90
91 DESTWRITEPIXEL(pbDest, data);
92 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
93 });
94 return pbDest;
95}
96
100WINPR_ATTR_NODISCARD
101static inline BOOL RLEDECOMPRESS(const BYTE* WINPR_RESTRICT pbSrcBuffer, UINT32 cbSrcBuffer,
102 BYTE* WINPR_RESTRICT pbDestBuffer, UINT32 rowDelta, UINT32 width,
103 UINT32 height)
104{
105 const BYTE* pbSrc = pbSrcBuffer;
106 BYTE* pbDest = pbDestBuffer;
107 PIXEL temp = 0;
108 PIXEL fgPel = WHITE_PIXEL;
109 BOOL fInsertFgPel = FALSE;
110 BOOL fFirstLine = TRUE;
111 BYTE bitmask = 0;
112 PIXEL pixelA = 0;
113 PIXEL pixelB = 0;
114 UINT32 runLength = 0;
115 UINT32 code = 0;
116 UINT32 advance = 0;
117 RLEEXTRA
118
119 if ((rowDelta == 0) || (rowDelta < width))
120 {
121 WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta,
122 width);
123 return FALSE;
124 }
125
126 if (!pbSrcBuffer || !pbDestBuffer)
127 {
128 WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p",
129 WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
130 WINPR_CXX_COMPAT_CAST(const void*, pbDestBuffer));
131 return FALSE;
132 }
133
134 const BYTE* pbEnd = &pbSrcBuffer[cbSrcBuffer];
135 const BYTE* pbDestEnd = &pbDestBuffer[1ULL * rowDelta * height];
136
137 while (pbSrc < pbEnd)
138 {
139 /* Watch out for the end of the first scanline. */
140 if (fFirstLine)
141 {
142 if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
143 {
144 fFirstLine = FALSE;
145 fInsertFgPel = FALSE;
146 }
147 }
148
149 /*
150 Extract the compression order code ID from the compression
151 order header.
152 */
153 code = ExtractCodeId(*pbSrc);
154
155#if defined(WITH_DEBUG_CODECS)
156 WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%ld", (const void*)pbSrc, rle_code_str(code),
157 pbEnd - pbSrc);
158#endif
159
160 /* Handle Background Run Orders. */
161 if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
162 {
163 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
164 if (advance == 0)
165 return FALSE;
166 pbSrc = pbSrc + advance;
167
168 if (fFirstLine)
169 {
170 if (fInsertFgPel)
171 {
172 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
173 return FALSE;
174
175 DESTWRITEPIXEL(pbDest, fgPel);
176 runLength = runLength - 1;
177 }
178
179 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
180 return FALSE;
181
182 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
183 }
184 else
185 {
186 if (fInsertFgPel)
187 {
188 DESTREADPIXEL(temp, pbDest - rowDelta);
189
190 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
191 return FALSE;
192
193 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
194 runLength--;
195 }
196
197 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
198 return FALSE;
199
200 UNROLL(runLength, {
201 DESTREADPIXEL(temp, pbDest - rowDelta);
202 DESTWRITEPIXEL(pbDest, temp);
203 });
204 }
205
206 /* A follow-on background run order will need a foreground pel inserted. */
207 fInsertFgPel = TRUE;
208 continue;
209 }
210
211 /* For any of the other run-types a follow-on background run
212 order does not need a foreground pel inserted. */
213 fInsertFgPel = FALSE;
214
215 switch (code)
216 {
217 /* Handle Foreground Run Orders. */
218 case REGULAR_FG_RUN:
219 case MEGA_MEGA_FG_RUN:
220 case LITE_SET_FG_FG_RUN:
221 case MEGA_MEGA_SET_FG_RUN:
222 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
223 if (advance == 0)
224 return FALSE;
225 pbSrc = pbSrc + advance;
226
227 if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
228 {
229 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
230 return FALSE;
231 SRCREADPIXEL(fgPel, pbSrc);
232 }
233
234 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
235 return FALSE;
236
237 if (fFirstLine)
238 {
239 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
240 }
241 else
242 {
243 UNROLL(runLength, {
244 DESTREADPIXEL(temp, pbDest - rowDelta);
245 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
246 });
247 }
248
249 break;
250
251 /* Handle Dithered Run Orders. */
252 case LITE_DITHERED_RUN:
253 case MEGA_MEGA_DITHERED_RUN:
254 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
255 if (advance == 0)
256 return FALSE;
257 pbSrc = pbSrc + advance;
258 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
259 return FALSE;
260 SRCREADPIXEL(pixelA, pbSrc);
261 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
262 return FALSE;
263 SRCREADPIXEL(pixelB, pbSrc);
264
265 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
266 return FALSE;
267
268 UNROLL(runLength, {
269 DESTWRITEPIXEL(pbDest, pixelA);
270 DESTWRITEPIXEL(pbDest, pixelB);
271 });
272 break;
273
274 /* Handle Color Run Orders. */
275 case REGULAR_COLOR_RUN:
276 case MEGA_MEGA_COLOR_RUN:
277 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
278 if (advance == 0)
279 return FALSE;
280 pbSrc = pbSrc + advance;
281 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
282 return FALSE;
283 SRCREADPIXEL(pixelA, pbSrc);
284
285 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
286 return FALSE;
287
288 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
289 break;
290
291 /* Handle Foreground/Background Image Orders. */
292 case REGULAR_FGBG_IMAGE:
293 case MEGA_MEGA_FGBG_IMAGE:
294 case LITE_SET_FG_FGBG_IMAGE:
295 case MEGA_MEGA_SET_FGBG_IMAGE:
296 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
297 if (advance == 0)
298 return FALSE;
299 pbSrc = pbSrc + advance;
300
301 if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
302 {
303 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
304 return FALSE;
305 SRCREADPIXEL(fgPel, pbSrc);
306 }
307
308 if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
309 return FALSE;
310 if (fFirstLine)
311 {
312 while (runLength > 8)
313 {
314 bitmask = *pbSrc;
315 pbSrc = pbSrc + 1;
316 pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
317
318 if (!pbDest)
319 return FALSE;
320
321 runLength = runLength - 8;
322 }
323 }
324 else
325 {
326 while (runLength > 8)
327 {
328 bitmask = *pbSrc++;
329
330 pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
331
332 if (!pbDest)
333 return FALSE;
334
335 runLength = runLength - 8;
336 }
337 }
338
339 if (runLength > 0)
340 {
341 if (!buffer_within_range(pbSrc, 1, pbEnd))
342 return FALSE;
343 bitmask = *pbSrc++;
344
345 if (fFirstLine)
346 {
347 pbDest =
348 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
349 }
350 else
351 {
352 pbDest =
353 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
354 }
355
356 if (!pbDest)
357 return FALSE;
358 }
359
360 break;
361
362 /* Handle Color Image Orders. */
363 case REGULAR_COLOR_IMAGE:
364 case MEGA_MEGA_COLOR_IMAGE:
365 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
366 if (advance == 0)
367 return FALSE;
368 pbSrc = pbSrc + advance;
369 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
370 return FALSE;
371 if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
372 return FALSE;
373
374 UNROLL(runLength, {
375 SRCREADPIXEL(temp, pbSrc);
376 DESTWRITEPIXEL(pbDest, temp);
377 });
378 break;
379
380 /* Handle Special Order 1. */
381 case SPECIAL_FGBG_1:
382 if (!buffer_within_range(pbSrc, 1, pbEnd))
383 return FALSE;
384 pbSrc = pbSrc + 1;
385
386 if (fFirstLine)
387 {
388 pbDest =
389 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
390 }
391 else
392 {
393 pbDest =
394 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
395 }
396
397 if (!pbDest)
398 return FALSE;
399
400 break;
401
402 /* Handle Special Order 2. */
403 case SPECIAL_FGBG_2:
404 if (!buffer_within_range(pbSrc, 1, pbEnd))
405 return FALSE;
406 pbSrc = pbSrc + 1;
407
408 if (fFirstLine)
409 {
410 pbDest =
411 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
412 }
413 else
414 {
415 pbDest =
416 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
417 }
418
419 if (!pbDest)
420 return FALSE;
421
422 break;
423
424 /* Handle White Order. */
425 case SPECIAL_WHITE:
426 if (!buffer_within_range(pbSrc, 1, pbEnd))
427 return FALSE;
428 pbSrc = pbSrc + 1;
429
430 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
431 return FALSE;
432
433 DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
434 break;
435
436 /* Handle Black Order. */
437 case SPECIAL_BLACK:
438 if (!buffer_within_range(pbSrc, 1, pbEnd))
439 return FALSE;
440 pbSrc = pbSrc + 1;
441
442 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
443 return FALSE;
444
445 DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
446 break;
447
448 default:
449 WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
450 code, WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
451 WINPR_CXX_COMPAT_CAST(const void*, pbSrc),
452 WINPR_CXX_COMPAT_CAST(const void*, pbEnd));
453 return FALSE;
454 }
455 }
456
457 return TRUE;
458}