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