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