FreeRDP
codec/bitmap.c
1 
20 #include <freerdp/config.h>
21 
22 #include <freerdp/codec/bitmap.h>
23 #include <freerdp/codec/planar.h>
24 
25 static INLINE UINT16 GETPIXEL16(const void* WINPR_RESTRICT d, UINT32 x, UINT32 y, UINT32 w)
26 {
27  const BYTE* WINPR_RESTRICT src = (const BYTE*)d + ((y * w + x) * sizeof(UINT16));
28  return (UINT16)(((UINT16)src[1] << 8) | (UINT16)src[0]);
29 }
30 
31 static INLINE UINT32 GETPIXEL32(const void* WINPR_RESTRICT d, UINT32 x, UINT32 y, UINT32 w)
32 {
33  const BYTE* WINPR_RESTRICT src = (const BYTE*)d + ((y * w + x) * sizeof(UINT32));
34  return (((UINT32)src[3]) << 24) | (((UINT32)src[2]) << 16) | (((UINT32)src[1]) << 8) |
35  (src[0] & 0xFF);
36 }
37 
38 /*****************************************************************************/
39 static INLINE UINT16 IN_PIXEL16(const void* WINPR_RESTRICT in_ptr, UINT32 in_x, UINT32 in_y,
40  UINT32 in_w, UINT16 in_last_pixel)
41 {
42  if (in_ptr == 0)
43  return 0;
44  else if (in_x < in_w)
45  return GETPIXEL16(in_ptr, in_x, in_y, in_w);
46  else
47  return in_last_pixel;
48 }
49 
50 /*****************************************************************************/
51 static INLINE UINT32 IN_PIXEL32(const void* WINPR_RESTRICT in_ptr, UINT32 in_x, UINT32 in_y,
52  UINT32 in_w, UINT32 in_last_pixel)
53 {
54  if (in_ptr == 0)
55  return 0;
56  else if (in_x < in_w)
57  return GETPIXEL32(in_ptr, in_x, in_y, in_w);
58  else
59  return in_last_pixel;
60 }
61 
62 /*****************************************************************************/
63 /* color */
64 static INLINE UINT16 out_color_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
65  UINT16 in_data)
66 {
67  if (in_count > 0)
68  {
69  if (in_count < 32)
70  {
71  const BYTE temp = ((0x3 << 5) | in_count) & 0xFF;
72  Stream_Write_UINT8(in_s, temp);
73  }
74  else if (in_count < 256 + 32)
75  {
76  const BYTE temp = (in_count - 32) & 0xFF;
77  Stream_Write_UINT8(in_s, 0x60);
78  Stream_Write_UINT8(in_s, temp);
79  }
80  else
81  {
82  Stream_Write_UINT8(in_s, 0xf3);
83  Stream_Write_UINT16(in_s, in_count);
84  }
85 
86  Stream_Write_UINT16(in_s, in_data);
87  }
88 
89  return 0;
90 }
91 #define OUT_COLOR_COUNT2(in_count, in_s, in_data) \
92  in_count = out_color_count_2(in_count, in_s, in_data)
93 
94 /*****************************************************************************/
95 /* color */
96 static INLINE UINT16 out_color_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
97  UINT32 in_data)
98 {
99  if (in_count > 0)
100  {
101  if (in_count < 32)
102  {
103  const BYTE temp = ((0x3 << 5) | in_count) & 0xFF;
104  Stream_Write_UINT8(in_s, temp);
105  }
106  else if (in_count < 256 + 32)
107  {
108  const BYTE temp = (in_count - 32) & 0xFF;
109  Stream_Write_UINT8(in_s, 0x60);
110  Stream_Write_UINT8(in_s, temp);
111  }
112  else
113  {
114  Stream_Write_UINT8(in_s, 0xf3);
115  Stream_Write_UINT16(in_s, in_count);
116  }
117 
118  Stream_Write_UINT8(in_s, in_data & 0xFF);
119 
120  Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF);
121  Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF);
122  }
123 
124  return 0;
125 }
126 
127 #define OUT_COLOR_COUNT3(in_count, in_s, in_data) \
128  in_count = out_color_count_3(in_count, in_s, in_data)
129 
130 /*****************************************************************************/
131 /* copy */
132 static INLINE UINT16 out_copy_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
133  wStream* WINPR_RESTRICT in_data)
134 
135 {
136  if (in_count > 0)
137  {
138  if (in_count < 32)
139  {
140  const BYTE temp = ((0x4 << 5) | in_count) & 0xFF;
141  Stream_Write_UINT8(in_s, temp);
142  }
143  else if (in_count < 256 + 32)
144  {
145  const BYTE temp = (in_count - 32) & 0xFF;
146  Stream_Write_UINT8(in_s, 0x80);
147  Stream_Write_UINT8(in_s, temp);
148  }
149  else
150  {
151  Stream_Write_UINT8(in_s, 0xf4);
152  Stream_Write_UINT16(in_s, in_count);
153  }
154 
155  Stream_Write(in_s, Stream_Buffer(in_data), 2ULL * in_count);
156  }
157 
158  Stream_SetPosition(in_data, 0);
159  return 0;
160 }
161 #define OUT_COPY_COUNT2(in_count, in_s, in_data) \
162  in_count = out_copy_count_2(in_count, in_s, in_data)
163 /*****************************************************************************/
164 /* copy */
165 static INLINE UINT16 out_copy_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
166  wStream* WINPR_RESTRICT in_data)
167 {
168  if (in_count > 0)
169  {
170  if (in_count < 32)
171  {
172  const BYTE temp = ((0x4 << 5) | in_count) & 0xFF;
173  Stream_Write_UINT8(in_s, temp);
174  }
175  else if (in_count < 256 + 32)
176  {
177  const BYTE temp = (in_count - 32) & 0xFF;
178  Stream_Write_UINT8(in_s, 0x80);
179  Stream_Write_UINT8(in_s, temp);
180  }
181  else
182  {
183  Stream_Write_UINT8(in_s, 0xf4);
184  Stream_Write_UINT16(in_s, in_count);
185  }
186 
187  Stream_Write(in_s, Stream_Pointer(in_data), 3ULL * in_count);
188  }
189 
190  Stream_SetPosition(in_data, 0);
191  return 0;
192 }
193 #define OUT_COPY_COUNT3(in_count, in_s, in_data) \
194  in_count = out_copy_count_3(in_count, in_s, in_data)
195 
196 /*****************************************************************************/
197 /* bicolor */
198 static INLINE UINT16 out_bicolor_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
199  UINT16 in_color1, UINT16 in_color2)
200 {
201  if (in_count > 0)
202  {
203  if (in_count / 2 < 16)
204  {
205  const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF;
206  Stream_Write_UINT8(in_s, temp);
207  }
208  else if (in_count / 2 < 256 + 16)
209  {
210  const BYTE temp = (in_count / 2 - 16) & 0xFF;
211  Stream_Write_UINT8(in_s, 0xe0);
212  Stream_Write_UINT8(in_s, temp);
213  }
214  else
215  {
216  Stream_Write_UINT8(in_s, 0xf8);
217  Stream_Write_UINT16(in_s, in_count / 2);
218  }
219 
220  Stream_Write_UINT16(in_s, in_color1);
221  Stream_Write_UINT16(in_s, in_color2);
222  }
223 
224  return 0;
225 }
226 
227 #define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \
228  in_count = out_bicolor_count_2(in_count, in_s, in_color1, in_color2)
229 
230 /*****************************************************************************/
231 /* bicolor */
232 static INLINE UINT16 out_bicolor_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
233  UINT32 in_color1, UINT32 in_color2)
234 {
235  if (in_count > 0)
236  {
237  if (in_count / 2 < 16)
238  {
239  const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF;
240  Stream_Write_UINT8(in_s, temp);
241  }
242  else if (in_count / 2 < 256 + 16)
243  {
244  const BYTE temp = (in_count / 2 - 16) & 0xFF;
245  Stream_Write_UINT8(in_s, 0xe0);
246  Stream_Write_UINT8(in_s, temp);
247  }
248  else
249  {
250  Stream_Write_UINT8(in_s, 0xf8);
251  Stream_Write_UINT16(in_s, in_count / 2);
252  }
253 
254  Stream_Write_UINT8(in_s, in_color1 & 0xFF);
255  Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF);
256  Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF);
257  Stream_Write_UINT8(in_s, in_color2 & 0xFF);
258  Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF);
259  Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF);
260  }
261 
262  return 0;
263 }
264 
265 #define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \
266  in_count = out_bicolor_count_3(in_count, in_s, in_color1, in_color2)
267 
268 /*****************************************************************************/
269 /* fill */
270 static INLINE UINT16 out_fill_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
271 {
272  if (in_count > 0)
273  {
274  if (in_count < 32)
275  {
276  Stream_Write_UINT8(in_s, in_count & 0xFF);
277  }
278  else if (in_count < 256 + 32)
279  {
280  const BYTE temp = (in_count - 32) & 0xFF;
281  Stream_Write_UINT8(in_s, 0x0);
282  Stream_Write_UINT8(in_s, temp);
283  }
284  else
285  {
286  Stream_Write_UINT8(in_s, 0xf0);
287  Stream_Write_UINT16(in_s, in_count);
288  }
289  }
290 
291  return 0;
292 }
293 
294 #define OUT_FILL_COUNT2(in_count, in_s) in_count = out_fill_count_2(in_count, in_s)
295 
296 /*****************************************************************************/
297 /* fill */
298 static INLINE UINT16 out_fill_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
299 {
300  if (in_count > 0)
301  {
302  if (in_count < 32)
303  {
304  Stream_Write_UINT8(in_s, in_count & 0xFF);
305  }
306  else if (in_count < 256 + 32)
307  {
308  const BYTE temp = (in_count - 32) & 0xFF;
309  Stream_Write_UINT8(in_s, 0x0);
310  Stream_Write_UINT8(in_s, temp);
311  }
312  else
313  {
314  Stream_Write_UINT8(in_s, 0xf0);
315  Stream_Write_UINT16(in_s, in_count);
316  }
317  }
318 
319  return 0;
320 }
321 #define OUT_FILL_COUNT3(in_count, in_s) in_count = out_fill_count_3(in_count, in_s)
322 
323 /*****************************************************************************/
324 /* mix */
325 static INLINE UINT16 out_mix_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
326 {
327  if (in_count > 0)
328  {
329  if (in_count < 32)
330  {
331  const BYTE temp = ((0x1 << 5) | in_count) & 0xFF;
332  Stream_Write_UINT8(in_s, temp);
333  }
334  else if (in_count < 256 + 32)
335  {
336  const BYTE temp = (in_count - 32) & 0xFF;
337  Stream_Write_UINT8(in_s, 0x20);
338  Stream_Write_UINT8(in_s, temp);
339  }
340  else
341  {
342  Stream_Write_UINT8(in_s, 0xf1);
343  Stream_Write_UINT16(in_s, in_count);
344  }
345  }
346 
347  return 0;
348 }
349 #define OUT_MIX_COUNT2(in_count, in_s) in_count = out_mix_count_2(in_count, in_s)
350 
351 /*****************************************************************************/
352 /* mix */
353 static INLINE UINT16 out_mix_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s)
354 {
355  if (in_count > 0)
356  {
357  if (in_count < 32)
358  {
359  const BYTE temp = ((0x1 << 5) | in_count) & 0xFF;
360  Stream_Write_UINT8(in_s, temp);
361  }
362  else if (in_count < 256 + 32)
363  {
364  const BYTE temp = (in_count - 32) & 0xFF;
365  Stream_Write_UINT8(in_s, 0x20);
366  Stream_Write_UINT8(in_s, temp);
367  }
368  else
369  {
370  Stream_Write_UINT8(in_s, 0xf1);
371  Stream_Write_UINT16(in_s, in_count);
372  }
373  }
374 
375  return 0;
376 }
377 
378 #define OUT_MIX_COUNT3(in_count, in_s) in_count = out_mix_count_3(in_count, in_s)
379 
380 /*****************************************************************************/
381 /* fom */
382 static INLINE UINT16 out_from_count_2(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
383  const char* WINPR_RESTRICT in_mask, size_t in_mask_len)
384 {
385  if (in_count > 0)
386  {
387  if ((in_count % 8) == 0 && in_count < 249)
388  {
389  const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF;
390  Stream_Write_UINT8(in_s, temp);
391  }
392  else if (in_count < 256)
393  {
394  const BYTE temp = (in_count - 1) & 0xFF;
395  Stream_Write_UINT8(in_s, 0x40);
396  Stream_Write_UINT8(in_s, temp);
397  }
398  else
399  {
400  Stream_Write_UINT8(in_s, 0xf2);
401  Stream_Write_UINT16(in_s, in_count);
402  }
403 
404  Stream_Write(in_s, in_mask, in_mask_len);
405  }
406 
407  return 0;
408 }
409 #define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \
410  in_count = out_from_count_2(in_count, in_s, in_mask, in_mask_len)
411 
412 /*****************************************************************************/
413 /* fill or mix (fom) */
414 static INLINE UINT16 out_from_count_3(UINT16 in_count, wStream* WINPR_RESTRICT in_s,
415  const char* WINPR_RESTRICT in_mask, size_t in_mask_len)
416 {
417  if (in_count > 0)
418  {
419  if ((in_count % 8) == 0 && in_count < 249)
420  {
421  const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF;
422  Stream_Write_UINT8(in_s, temp);
423  }
424  else if (in_count < 256)
425  {
426  const BYTE temp = (in_count - 1) & 0xFF;
427  Stream_Write_UINT8(in_s, 0x40);
428  Stream_Write_UINT8(in_s, temp);
429  }
430  else
431  {
432  Stream_Write_UINT8(in_s, 0xf2);
433  Stream_Write_UINT16(in_s, in_count);
434  }
435 
436  Stream_Write(in_s, in_mask, in_mask_len);
437  }
438 
439  return 0;
440 }
441 #define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \
442  in_count = out_from_count_3(in_count, in_s, in_mask, in_mask_len)
443 
444 #define TEST_FILL ((last_line == 0 && pixel == 0) || (last_line != 0 && pixel == ypixel))
445 #define TEST_MIX ((last_line == 0 && pixel == mix) || (last_line != 0 && pixel == (ypixel ^ mix)))
446 #define TEST_FOM TEST_FILL || TEST_MIX
447 #define TEST_COLOR pixel == last_pixel
448 #define TEST_BICOLOR \
449  ((pixel != last_pixel) && \
450  ((!bicolor_spin && (pixel == bicolor1) && (last_pixel == bicolor2)) || \
451  (bicolor_spin && (pixel == bicolor2) && (last_pixel == bicolor1))))
452 #define RESET_COUNTS \
453  do \
454  { \
455  bicolor_count = 0; \
456  fill_count = 0; \
457  color_count = 0; \
458  mix_count = 0; \
459  fom_count = 0; \
460  fom_mask_len = 0; \
461  bicolor_spin = FALSE; \
462  } while (0)
463 
464 static INLINE SSIZE_T freerdp_bitmap_compress_24(const void* WINPR_RESTRICT srcData, UINT32 width,
465  UINT32 height, wStream* WINPR_RESTRICT s,
466  UINT32 byte_limit, UINT32 start_line,
467  wStream* WINPR_RESTRICT temp_s, UINT32 e)
468 {
469  char fom_mask[8192] = { 0 }; /* good for up to 64K bitmap */
470  SSIZE_T lines_sent = 0;
471  UINT16 count = 0;
472  UINT16 color_count = 0;
473  UINT32 last_pixel = 0;
474  UINT32 last_ypixel = 0;
475  UINT16 bicolor_count = 0;
476  UINT32 bicolor1 = 0;
477  UINT32 bicolor2 = 0;
478  BOOL bicolor_spin = FALSE;
479  UINT32 end = width + e;
480  UINT32 out_count = end * 3;
481  UINT16 fill_count = 0;
482  UINT16 mix_count = 0;
483  const UINT32 mix = 0xFFFFFF;
484  UINT16 fom_count = 0;
485  size_t fom_mask_len = 0;
486  const char* start = (const char*)srcData;
487  const char* line = start + 4ULL * width * start_line;
488  const char* last_line = NULL;
489 
490  while ((line >= start) && (out_count < 32768))
491  {
492  size_t i = Stream_GetPosition(s) + 3ULL * count;
493 
494  if ((i - (3ULL * color_count) >= byte_limit) &&
495  (i - (3ULL * bicolor_count) >= byte_limit) && (i - (3ULL * fill_count) >= byte_limit) &&
496  (i - (3ULL * mix_count) >= byte_limit) && (i - (3ULL * fom_count) >= byte_limit))
497  {
498  break;
499  }
500 
501  out_count += end * 3;
502 
503  for (UINT32 j = 0; j < end; j++)
504  {
505  /* read next pixel */
506  const UINT32 pixel = IN_PIXEL32(line, j, 0, width, last_pixel);
507  const UINT32 ypixel = IN_PIXEL32(last_line, j, 0, width, last_ypixel);
508 
509  if (!TEST_FILL)
510  {
511  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
512  fill_count >= mix_count && fill_count >= fom_count)
513  {
514  if (fill_count > count)
515  return -1;
516 
517  count -= fill_count;
518  OUT_COPY_COUNT3(count, s, temp_s);
519  OUT_FILL_COUNT3(fill_count, s);
520  RESET_COUNTS;
521  }
522 
523  fill_count = 0;
524  }
525 
526  if (!TEST_MIX)
527  {
528  if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
529  mix_count >= color_count && mix_count >= fom_count)
530  {
531  if (mix_count > count)
532  return -1;
533 
534  count -= mix_count;
535  OUT_COPY_COUNT3(count, s, temp_s);
536  OUT_MIX_COUNT3(mix_count, s);
537  RESET_COUNTS;
538  }
539 
540  mix_count = 0;
541  }
542 
543  if (!(TEST_COLOR))
544  {
545  if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count &&
546  color_count >= mix_count && color_count >= fom_count)
547  {
548  if (color_count > count)
549  return -1;
550 
551  count -= color_count;
552  OUT_COPY_COUNT3(count, s, temp_s);
553  OUT_COLOR_COUNT3(color_count, s, last_pixel);
554  RESET_COUNTS;
555  }
556 
557  color_count = 0;
558  }
559 
560  if (!TEST_BICOLOR)
561  {
562  if (bicolor_count > 3 && bicolor_count >= fill_count &&
563  bicolor_count >= color_count && bicolor_count >= mix_count &&
564  bicolor_count >= fom_count)
565  {
566  if ((bicolor_count % 2) != 0)
567  bicolor_count--;
568 
569  if (bicolor_count > count)
570  return -1;
571 
572  count -= bicolor_count;
573  OUT_COPY_COUNT3(count, s, temp_s);
574  OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1);
575  RESET_COUNTS;
576  }
577 
578  bicolor_count = 0;
579  bicolor1 = last_pixel;
580  bicolor2 = pixel;
581  bicolor_spin = FALSE;
582  }
583 
584  if (!(TEST_FOM))
585  {
586  if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
587  fom_count >= mix_count && fom_count >= bicolor_count)
588  {
589  if (fom_count > count)
590  return -1;
591 
592  count -= fom_count;
593  OUT_COPY_COUNT3(count, s, temp_s);
594  OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
595  RESET_COUNTS;
596  }
597 
598  fom_count = 0;
599  fom_mask_len = 0;
600  }
601 
602  if (TEST_FILL)
603  {
604  fill_count++;
605  }
606 
607  if (TEST_MIX)
608  {
609  mix_count++;
610  }
611 
612  if (TEST_COLOR)
613  {
614  color_count++;
615  }
616 
617  if (TEST_BICOLOR)
618  {
619  bicolor_spin = !bicolor_spin;
620  bicolor_count++;
621  }
622 
623  if (TEST_FOM)
624  {
625  if ((fom_count % 8) == 0)
626  {
627  fom_mask[fom_mask_len] = 0;
628  fom_mask_len++;
629  }
630 
631  if (pixel == (ypixel ^ mix))
632  {
633  fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8));
634  }
635 
636  fom_count++;
637  }
638 
639  Stream_Write_UINT8(temp_s, pixel & 0xff);
640  Stream_Write_UINT8(temp_s, (pixel >> 8) & 0xff);
641  Stream_Write_UINT8(temp_s, (pixel >> 16) & 0xff);
642  count++;
643  last_pixel = pixel;
644  last_ypixel = ypixel;
645  }
646 
647  /* can't take fix, mix, or fom past first line */
648  if (last_line == 0)
649  {
650  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
651  fill_count >= mix_count && fill_count >= fom_count)
652  {
653  if (fill_count > count)
654  return -1;
655 
656  count -= fill_count;
657  OUT_COPY_COUNT3(count, s, temp_s);
658  OUT_FILL_COUNT3(fill_count, s);
659  RESET_COUNTS;
660  }
661 
662  fill_count = 0;
663 
664  if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
665  mix_count >= color_count && mix_count >= fom_count)
666  {
667  if (mix_count > count)
668  return -1;
669 
670  count -= mix_count;
671  OUT_COPY_COUNT3(count, s, temp_s);
672  OUT_MIX_COUNT3(mix_count, s);
673  RESET_COUNTS;
674  }
675 
676  mix_count = 0;
677 
678  if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
679  fom_count >= mix_count && fom_count >= bicolor_count)
680  {
681  if (fom_count > count)
682  return -1;
683 
684  count -= fom_count;
685  OUT_COPY_COUNT3(count, s, temp_s);
686  OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
687  RESET_COUNTS;
688  }
689 
690  fom_count = 0;
691  fom_mask_len = 0;
692  }
693 
694  last_line = line;
695  line = line - 4ULL * width;
696  start_line--;
697  lines_sent++;
698  }
699 
700  Stream_SetPosition(temp_s, 0);
701 
702  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
703  fill_count >= mix_count && fill_count >= fom_count)
704  {
705  if (fill_count > count)
706  return -1;
707 
708  count -= fill_count;
709  OUT_COPY_COUNT3(count, s, temp_s);
710  OUT_FILL_COUNT3(fill_count, s);
711  }
712  else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count &&
713  mix_count >= fill_count && mix_count >= fom_count)
714  {
715  if (mix_count > count)
716  return -1;
717 
718  count -= mix_count;
719  OUT_COPY_COUNT3(count, s, temp_s);
720  OUT_MIX_COUNT3(mix_count, s);
721  }
722  else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count &&
723  color_count >= fill_count && color_count >= fom_count)
724  {
725  if (color_count > count)
726  return -1;
727 
728  count -= color_count;
729  OUT_COPY_COUNT3(count, s, temp_s);
730  OUT_COLOR_COUNT3(color_count, s, last_pixel);
731  }
732  else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count &&
733  bicolor_count >= fill_count && bicolor_count >= fom_count)
734  {
735  if ((bicolor_count % 2) != 0)
736  bicolor_count--;
737 
738  if (bicolor_count > count)
739  return -1;
740 
741  count -= bicolor_count;
742  OUT_COPY_COUNT3(count, s, temp_s);
743  OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1);
744 
745  if (bicolor_count > count)
746  return -1;
747 
748  count -= bicolor_count;
749  OUT_COPY_COUNT3(count, s, temp_s);
750  OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2);
751  }
752  else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count &&
753  fom_count >= fill_count && fom_count >= bicolor_count)
754  {
755  if (fom_count > count)
756  return -1;
757 
758  count -= fom_count;
759  OUT_COPY_COUNT3(count, s, temp_s);
760  OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len);
761  }
762  else
763  {
764  OUT_COPY_COUNT3(count, s, temp_s);
765  }
766 
767  return lines_sent;
768 }
769 
770 static INLINE SSIZE_T freerdp_bitmap_compress_16(const void* WINPR_RESTRICT srcData, UINT32 width,
771  UINT32 height, wStream* WINPR_RESTRICT s,
772  UINT32 bpp, UINT32 byte_limit, UINT32 start_line,
773  wStream* WINPR_RESTRICT temp_s, UINT32 e)
774 {
775  char fom_mask[8192] = { 0 }; /* good for up to 64K bitmap */
776  SSIZE_T lines_sent = 0;
777  UINT16 count = 0;
778  UINT16 color_count = 0;
779  UINT16 last_pixel = 0;
780  UINT16 last_ypixel = 0;
781  UINT16 bicolor_count = 0;
782  UINT16 bicolor1 = 0;
783  UINT16 bicolor2 = 0;
784  BOOL bicolor_spin = FALSE;
785  UINT32 end = width + e;
786  UINT32 out_count = end * 2;
787  UINT16 fill_count = 0;
788  UINT16 mix_count = 0;
789  const UINT32 mix = (bpp == 15) ? 0xBA1F : 0xFFFF;
790  UINT16 fom_count = 0;
791  size_t fom_mask_len = 0;
792  const char* start = (const char*)srcData;
793  const char* line = start + 2ULL * width * start_line;
794  const char* last_line = NULL;
795 
796  while ((line >= start) && (out_count < 32768))
797  {
798  size_t i = Stream_GetPosition(s) + 2ULL * count;
799 
800  if ((i - (2ULL * color_count) >= byte_limit) &&
801  (i - (2ULL * bicolor_count) >= byte_limit) && (i - (2ULL * fill_count) >= byte_limit) &&
802  (i - (2ULL * mix_count) >= byte_limit) && (i - (2ULL * fom_count) >= byte_limit))
803  {
804  break;
805  }
806 
807  out_count += end * 2;
808 
809  for (UINT32 j = 0; j < end; j++)
810  {
811  /* read next pixel */
812  const UINT16 pixel = IN_PIXEL16(line, j, 0, width, last_pixel);
813  const UINT16 ypixel = IN_PIXEL16(last_line, j, 0, width, last_ypixel);
814 
815  if (!TEST_FILL)
816  {
817  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
818  fill_count >= mix_count && fill_count >= fom_count)
819  {
820  if (fill_count > count)
821  return -1;
822 
823  count -= fill_count;
824  OUT_COPY_COUNT2(count, s, temp_s);
825  OUT_FILL_COUNT2(fill_count, s);
826  RESET_COUNTS;
827  }
828 
829  fill_count = 0;
830  }
831 
832  if (!TEST_MIX)
833  {
834  if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
835  mix_count >= color_count && mix_count >= fom_count)
836  {
837  if (mix_count > count)
838  return -1;
839 
840  count -= mix_count;
841  OUT_COPY_COUNT2(count, s, temp_s);
842  OUT_MIX_COUNT2(mix_count, s);
843  RESET_COUNTS;
844  }
845 
846  mix_count = 0;
847  }
848 
849  if (!(TEST_COLOR))
850  {
851  if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count &&
852  color_count >= mix_count && color_count >= fom_count)
853  {
854  if (color_count > count)
855  return -1;
856 
857  count -= color_count;
858  OUT_COPY_COUNT2(count, s, temp_s);
859  OUT_COLOR_COUNT2(color_count, s, last_pixel);
860  RESET_COUNTS;
861  }
862 
863  color_count = 0;
864  }
865 
866  if (!TEST_BICOLOR)
867  {
868  if ((bicolor_count > 3) && (bicolor_count >= fill_count) &&
869  (bicolor_count >= color_count) && (bicolor_count >= mix_count) &&
870  (bicolor_count >= fom_count))
871  {
872  if ((bicolor_count % 2) != 0)
873  bicolor_count--;
874 
875  if (bicolor_count > count)
876  return -1;
877 
878  count -= bicolor_count;
879  OUT_COPY_COUNT2(count, s, temp_s);
880  OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1);
881  RESET_COUNTS;
882  }
883 
884  bicolor_count = 0;
885  bicolor1 = last_pixel;
886  bicolor2 = pixel;
887  bicolor_spin = FALSE;
888  }
889 
890  if (!(TEST_FOM))
891  {
892  if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
893  fom_count >= mix_count && fom_count >= bicolor_count)
894  {
895  if (fom_count > count)
896  return -1;
897 
898  count -= fom_count;
899  OUT_COPY_COUNT2(count, s, temp_s);
900  OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
901  RESET_COUNTS;
902  }
903 
904  fom_count = 0;
905  fom_mask_len = 0;
906  }
907 
908  if (TEST_FILL)
909  {
910  fill_count++;
911  }
912 
913  if (TEST_MIX)
914  {
915  mix_count++;
916  }
917 
918  if (TEST_COLOR)
919  {
920  color_count++;
921  }
922 
923  if (TEST_BICOLOR)
924  {
925  bicolor_spin = !bicolor_spin;
926  bicolor_count++;
927  }
928 
929  if (TEST_FOM)
930  {
931  if ((fom_count % 8) == 0)
932  {
933  fom_mask[fom_mask_len] = 0;
934  fom_mask_len++;
935  }
936 
937  if (pixel == (ypixel ^ mix))
938  {
939  fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8));
940  }
941 
942  fom_count++;
943  }
944 
945  Stream_Write_UINT16(temp_s, pixel);
946  count++;
947  last_pixel = pixel;
948  last_ypixel = ypixel;
949  }
950 
951  /* can't take fix, mix, or fom past first line */
952  if (last_line == 0)
953  {
954  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
955  fill_count >= mix_count && fill_count >= fom_count)
956  {
957  if (fill_count > count)
958  return -1;
959 
960  count -= fill_count;
961  OUT_COPY_COUNT2(count, s, temp_s);
962  OUT_FILL_COUNT2(fill_count, s);
963  RESET_COUNTS;
964  }
965 
966  fill_count = 0;
967 
968  if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count &&
969  mix_count >= color_count && mix_count >= fom_count)
970  {
971  if (mix_count > count)
972  return -1;
973 
974  count -= mix_count;
975  OUT_COPY_COUNT2(count, s, temp_s);
976  OUT_MIX_COUNT2(mix_count, s);
977  RESET_COUNTS;
978  }
979 
980  mix_count = 0;
981 
982  if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count &&
983  fom_count >= mix_count && fom_count >= bicolor_count)
984  {
985  if (fom_count > count)
986  return -1;
987 
988  count -= fom_count;
989  OUT_COPY_COUNT2(count, s, temp_s);
990  OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
991  RESET_COUNTS;
992  }
993 
994  fom_count = 0;
995  fom_mask_len = 0;
996  }
997 
998  last_line = line;
999  line = line - 2ULL * width;
1000  start_line--;
1001  lines_sent++;
1002  }
1003 
1004  Stream_SetPosition(temp_s, 0);
1005 
1006  if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count &&
1007  fill_count >= mix_count && fill_count >= fom_count)
1008  {
1009  if (fill_count > count)
1010  return -1;
1011 
1012  count -= fill_count;
1013  OUT_COPY_COUNT2(count, s, temp_s);
1014  OUT_FILL_COUNT2(fill_count, s);
1015  }
1016  else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count &&
1017  mix_count >= fill_count && mix_count >= fom_count)
1018  {
1019  if (mix_count > count)
1020  return -1;
1021 
1022  count -= mix_count;
1023  OUT_COPY_COUNT2(count, s, temp_s);
1024  OUT_MIX_COUNT2(mix_count, s);
1025  }
1026  else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count &&
1027  color_count >= fill_count && color_count >= fom_count)
1028  {
1029  if (color_count > count)
1030  return -1;
1031 
1032  count -= color_count;
1033  OUT_COPY_COUNT2(count, s, temp_s);
1034  OUT_COLOR_COUNT2(color_count, s, last_pixel);
1035  }
1036  else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count &&
1037  bicolor_count >= fill_count && bicolor_count >= fom_count)
1038  {
1039  if ((bicolor_count % 2) != 0)
1040  bicolor_count--;
1041 
1042  if (bicolor_count > count)
1043  return -1;
1044 
1045  count -= bicolor_count;
1046  OUT_COPY_COUNT2(count, s, temp_s);
1047  OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1);
1048 
1049  if (bicolor_count > count)
1050  return -1;
1051 
1052  count -= bicolor_count;
1053  OUT_COPY_COUNT2(count, s, temp_s);
1054  OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2);
1055  }
1056  else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count &&
1057  fom_count >= fill_count && fom_count >= bicolor_count)
1058  {
1059  if (fom_count > count)
1060  return -1;
1061 
1062  count -= fom_count;
1063  OUT_COPY_COUNT2(count, s, temp_s);
1064  OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len);
1065  }
1066  else
1067  {
1068  OUT_COPY_COUNT2(count, s, temp_s);
1069  }
1070 
1071  return lines_sent;
1072 }
1073 
1074 SSIZE_T freerdp_bitmap_compress(const void* WINPR_RESTRICT srcData, UINT32 width, UINT32 height,
1075  wStream* WINPR_RESTRICT s, UINT32 bpp, UINT32 byte_limit,
1076  UINT32 start_line, wStream* WINPR_RESTRICT temp_s, UINT32 e)
1077 {
1078  Stream_SetPosition(temp_s, 0);
1079 
1080  switch (bpp)
1081  {
1082  case 15:
1083  case 16:
1084  return freerdp_bitmap_compress_16(srcData, width, height, s, bpp, byte_limit,
1085  start_line, temp_s, e);
1086 
1087  case 24:
1088  return freerdp_bitmap_compress_24(srcData, width, height, s, byte_limit, start_line,
1089  temp_s, e);
1090 
1091  default:
1092  return -1;
1093  }
1094 }