Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-codec / bitmap.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Compressed Bitmap
4  *
5  * Copyright 2011 Jay Sorg <jay.sorg@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <freerdp/utils/stream.h>
21 #include <freerdp/utils/memory.h>
22 #include <freerdp/codec/color.h>
23
24 #include <freerdp/codec/bitmap.h>
25
26 /*
27    RLE Compressed Bitmap Stream (RLE_BITMAP_STREAM)
28    http://msdn.microsoft.com/en-us/library/cc240895%28v=prot.10%29.aspx
29    pseudo-code
30    http://msdn.microsoft.com/en-us/library/dd240593%28v=prot.10%29.aspx
31 */
32
33 #define REGULAR_BG_RUN              0x00
34 #define MEGA_MEGA_BG_RUN            0xF0
35 #define REGULAR_FG_RUN              0x01
36 #define MEGA_MEGA_FG_RUN            0xF1
37 #define LITE_SET_FG_FG_RUN          0x0C
38 #define MEGA_MEGA_SET_FG_RUN        0xF6
39 #define LITE_DITHERED_RUN           0x0E
40 #define MEGA_MEGA_DITHERED_RUN      0xF8
41 #define REGULAR_COLOR_RUN           0x03
42 #define MEGA_MEGA_COLOR_RUN         0xF3
43 #define REGULAR_FGBG_IMAGE          0x02
44 #define MEGA_MEGA_FGBG_IMAGE        0xF2
45 #define LITE_SET_FG_FGBG_IMAGE      0x0D
46 #define MEGA_MEGA_SET_FGBG_IMAGE    0xF7
47 #define REGULAR_COLOR_IMAGE         0x04
48 #define MEGA_MEGA_COLOR_IMAGE       0xF4
49 #define SPECIAL_FGBG_1              0xF9
50 #define SPECIAL_FGBG_2              0xFA
51 #define SPECIAL_WHITE               0xFD
52 #define SPECIAL_BLACK               0xFE
53
54 #define BLACK_PIXEL 0x000000
55 #define WHITE_PIXEL 0xFFFFFF
56
57 typedef uint32 PIXEL;
58
59 static const uint8 g_MaskBit0 = 0x01; /* Least significant bit */
60 static const uint8 g_MaskBit1 = 0x02;
61 static const uint8 g_MaskBit2 = 0x04;
62 static const uint8 g_MaskBit3 = 0x08;
63 static const uint8 g_MaskBit4 = 0x10;
64 static const uint8 g_MaskBit5 = 0x20;
65 static const uint8 g_MaskBit6 = 0x40;
66 static const uint8 g_MaskBit7 = 0x80; /* Most significant bit */
67
68 static const uint8 g_MaskSpecialFgBg1 = 0x03;
69 static const uint8 g_MaskSpecialFgBg2 = 0x05;
70
71 static const uint8 g_MaskRegularRunLength = 0x1F;
72 static const uint8 g_MaskLiteRunLength = 0x0F;
73
74 /**
75  * Reads the supplied order header and extracts the compression
76  * order code ID.
77  */
78 static uint32 ExtractCodeId(uint8 bOrderHdr)
79 {
80         int code;
81
82         switch (bOrderHdr)
83         {
84                 case MEGA_MEGA_BG_RUN:
85                 case MEGA_MEGA_FG_RUN:
86                 case MEGA_MEGA_SET_FG_RUN:
87                 case MEGA_MEGA_DITHERED_RUN:
88                 case MEGA_MEGA_COLOR_RUN:
89                 case MEGA_MEGA_FGBG_IMAGE:
90                 case MEGA_MEGA_SET_FGBG_IMAGE:
91                 case MEGA_MEGA_COLOR_IMAGE:
92                 case SPECIAL_FGBG_1:
93                 case SPECIAL_FGBG_2:
94                 case SPECIAL_WHITE:
95                 case SPECIAL_BLACK:
96                         return bOrderHdr;
97         }
98         code = bOrderHdr >> 5;
99         switch (code)
100         {
101                 case REGULAR_BG_RUN:
102                 case REGULAR_FG_RUN:
103                 case REGULAR_COLOR_RUN:
104                 case REGULAR_FGBG_IMAGE:
105                 case REGULAR_COLOR_IMAGE:
106                         return code;
107         }
108         return bOrderHdr >> 4;
109 }
110
111 /**
112  * Extract the run length of a compression order.
113  */
114 static uint32 ExtractRunLength(uint32 code, uint8* pbOrderHdr, uint32* advance)
115 {
116         uint32 runLength;
117         uint32 ladvance;
118
119         ladvance = 1;
120         runLength = 0;
121         switch (code)
122         {
123                 case REGULAR_FGBG_IMAGE:
124                         runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
125                         if (runLength == 0)
126                         {
127                                 runLength = (*(pbOrderHdr + 1)) + 1;
128                                 ladvance += 1;
129                         }
130                         else
131                         {
132                                 runLength = runLength * 8;
133                         }
134                         break;
135                 case LITE_SET_FG_FGBG_IMAGE:
136                         runLength = (*pbOrderHdr) & g_MaskLiteRunLength;
137                         if (runLength == 0)
138                         {
139                                 runLength = (*(pbOrderHdr + 1)) + 1;
140                                 ladvance += 1;
141                         }
142                         else
143                         {
144                                 runLength = runLength * 8;
145                         }
146                         break;
147                 case REGULAR_BG_RUN:
148                 case REGULAR_FG_RUN:
149                 case REGULAR_COLOR_RUN:
150                 case REGULAR_COLOR_IMAGE:
151                         runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
152                         if (runLength == 0)
153                         {
154                                 /* An extended (MEGA) run. */
155                                 runLength = (*(pbOrderHdr + 1)) + 32;
156                                 ladvance += 1;
157                         }
158                         break;
159                 case LITE_SET_FG_FG_RUN:
160                 case LITE_DITHERED_RUN:
161                         runLength = (*pbOrderHdr) & g_MaskLiteRunLength;
162                         if (runLength == 0)
163                         {
164                                 /* An extended (MEGA) run. */
165                                 runLength = (*(pbOrderHdr + 1)) + 16;
166                                 ladvance += 1;
167                         }
168                         break;
169                 case MEGA_MEGA_BG_RUN:
170                 case MEGA_MEGA_FG_RUN:
171                 case MEGA_MEGA_SET_FG_RUN:
172                 case MEGA_MEGA_DITHERED_RUN:
173                 case MEGA_MEGA_COLOR_RUN:
174                 case MEGA_MEGA_FGBG_IMAGE:
175                 case MEGA_MEGA_SET_FGBG_IMAGE:
176                 case MEGA_MEGA_COLOR_IMAGE:
177                         runLength = ((uint16) pbOrderHdr[1]) | ((uint16) (pbOrderHdr[2] << 8));
178                         ladvance += 2;
179                         break;
180         }
181         *advance = ladvance;
182         return runLength;
183 }
184
185 #define UNROLL_COUNT 4
186 #define UNROLL(_exp) do { _exp _exp _exp _exp } while (0)
187
188 #undef DESTWRITEPIXEL
189 #undef DESTREADPIXEL
190 #undef SRCREADPIXEL
191 #undef DESTNEXTPIXEL
192 #undef SRCNEXTPIXEL
193 #undef WRITEFGBGIMAGE
194 #undef WRITEFIRSTLINEFGBGIMAGE
195 #undef RLEDECOMPRESS
196 #undef RLEEXTRA
197 #define DESTWRITEPIXEL(_buf, _pix) (_buf)[0] = (uint8)(_pix)
198 #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]
199 #define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0]
200 #define DESTNEXTPIXEL(_buf) _buf += 1
201 #define SRCNEXTPIXEL(_buf) _buf += 1
202 #define WRITEFGBGIMAGE WriteFgBgImage8to8
203 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8
204 #define RLEDECOMPRESS RleDecompress8to8
205 #define RLEEXTRA
206 #include "include/bitmap.c"
207
208 #undef DESTWRITEPIXEL
209 #undef DESTREADPIXEL
210 #undef SRCREADPIXEL
211 #undef DESTNEXTPIXEL
212 #undef SRCNEXTPIXEL
213 #undef WRITEFGBGIMAGE
214 #undef WRITEFIRSTLINEFGBGIMAGE
215 #undef RLEDECOMPRESS
216 #undef RLEEXTRA
217 #define DESTWRITEPIXEL(_buf, _pix) ((uint16*)(_buf))[0] = (uint16)(_pix)
218 #define DESTREADPIXEL(_pix, _buf) _pix = ((uint16*)(_buf))[0]
219 #define SRCREADPIXEL(_pix, _buf) _pix = ((uint16*)(_buf))[0]
220 #define DESTNEXTPIXEL(_buf) _buf += 2
221 #define SRCNEXTPIXEL(_buf) _buf += 2
222 #define WRITEFGBGIMAGE WriteFgBgImage16to16
223 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16
224 #define RLEDECOMPRESS RleDecompress16to16
225 #define RLEEXTRA
226 #include "include/bitmap.c"
227
228 #undef DESTWRITEPIXEL
229 #undef DESTREADPIXEL
230 #undef SRCREADPIXEL
231 #undef DESTNEXTPIXEL
232 #undef SRCNEXTPIXEL
233 #undef WRITEFGBGIMAGE
234 #undef WRITEFIRSTLINEFGBGIMAGE
235 #undef RLEDECOMPRESS
236 #undef RLEEXTRA
237 #define DESTWRITEPIXEL(_buf, _pix) do { (_buf)[0] = (uint8)(_pix);  \
238   (_buf)[1] = (uint8)((_pix) >> 8); (_buf)[2] = (uint8)((_pix) >> 16); } while (0)
239 #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | \
240   ((_buf)[2] << 16)
241 #define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | \
242   ((_buf)[2] << 16)
243 #define DESTNEXTPIXEL(_buf) _buf += 3
244 #define SRCNEXTPIXEL(_buf) _buf += 3
245 #define WRITEFGBGIMAGE WriteFgBgImage24to24
246 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24
247 #define RLEDECOMPRESS RleDecompress24to24
248 #define RLEEXTRA
249 #include "include/bitmap.c"
250
251 #define IN_UINT8_MV(_p) (*((_p)++))
252
253 /**
254  * decompress an RLE color plane
255  * RDP6_BITMAP_STREAM
256  */
257 static int process_rle_plane(uint8* in, int width, int height, uint8* out, int size)
258 {
259         int indexw;
260         int indexh;
261         int code;
262         int collen;
263         int replen;
264         int color;
265         int x;
266         int revcode;
267         uint8* last_line;
268         uint8* this_line;
269         uint8* org_in;
270         uint8* org_out;
271
272         org_in = in;
273         org_out = out;
274         last_line = 0;
275         indexh = 0;
276         while (indexh < height)
277         {
278                 out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
279                 color = 0;
280                 this_line = out;
281                 indexw = 0;
282                 if (last_line == 0)
283                 {
284                         while (indexw < width)
285                         {
286                                 code = IN_UINT8_MV(in);
287                                 replen = code & 0xf;
288                                 collen = (code >> 4) & 0xf;
289                                 revcode = (replen << 4) | collen;
290                                 if ((revcode <= 47) && (revcode >= 16))
291                                 {
292                                         replen = revcode;
293                                         collen = 0;
294                                 }
295                                 while (collen > 0)
296                                 {
297                                         color = IN_UINT8_MV(in);
298                                         *out = color;
299                                         out += 4;
300                                         indexw++;
301                                         collen--;
302                                 }
303                                 while (replen > 0)
304                                 {
305                                         *out = color;
306                                         out += 4;
307                                         indexw++;
308                                         replen--;
309                                 }
310                         }
311                 }
312                 else
313                 {
314                         while (indexw < width)
315                         {
316                                 code = IN_UINT8_MV(in);
317                                 replen = code & 0xf;
318                                 collen = (code >> 4) & 0xf;
319                                 revcode = (replen << 4) | collen;
320                                 if ((revcode <= 47) && (revcode >= 16))
321                                 {
322                                         replen = revcode;
323                                         collen = 0;
324                                 }
325                                 while (collen > 0)
326                                 {
327                                         x = IN_UINT8_MV(in);
328                                         if (x & 1)
329                                         {
330                                                 x = x >> 1;
331                                                 x = x + 1;
332                                                 color = -x;
333                                         }
334                                         else
335                                         {
336                                                 x = x >> 1;
337                                                 color = x;
338                                         }
339                                         x = last_line[indexw * 4] + color;
340                                         *out = x;
341                                         out += 4;
342                                         indexw++;
343                                         collen--;
344                                 }
345                                 while (replen > 0)
346                                 {
347                                         x = last_line[indexw * 4] + color;
348                                         *out = x;
349                                         out += 4;
350                                         indexw++;
351                                         replen--;
352                                 }
353                         }
354                 }
355                 indexh++;
356                 last_line = this_line;
357         }
358         return (int) (in - org_in);
359 }
360
361 /**
362  * process a raw color plane
363  */
364 static int process_raw_plane(uint8* srcData, int width, int height, uint8* dstData, int size)
365 {
366         int x, y;
367
368         for (y = 0; y < height; y++)
369         {
370                 for (x = 0; x < width; x++)
371                 {
372                         dstData[(((height - y - 1) * width) + x) * 4] = srcData[((y * width) + x)];
373                 }
374         }
375
376         return (width * height);
377 }
378
379 /**
380  * 4 byte bitmap decompress
381  * RDP6_BITMAP_STREAM
382  */
383 static boolean bitmap_decompress4(uint8* srcData, uint8* dstData, int width, int height, int size)
384 {
385         int RLE;
386         int code;
387         int NoAlpha;
388         int bytes_processed;
389         int total_processed;
390
391         code = IN_UINT8_MV(srcData);
392         RLE = code & 0x10;
393
394         total_processed = 1;
395         NoAlpha = code & 0x20;
396
397         if (NoAlpha == 0)
398         {
399                 bytes_processed = process_rle_plane(srcData, width, height, dstData + 3, size - total_processed);
400                 total_processed += bytes_processed;
401                 srcData += bytes_processed;
402         }
403
404         if (RLE != 0)
405         {
406                 bytes_processed = process_rle_plane(srcData, width, height, dstData + 2, size - total_processed);
407                 total_processed += bytes_processed;
408                 srcData += bytes_processed;
409
410                 bytes_processed = process_rle_plane(srcData, width, height, dstData + 1, size - total_processed);
411                 total_processed += bytes_processed;
412                 srcData += bytes_processed;
413
414                 bytes_processed = process_rle_plane(srcData, width, height, dstData + 0, size - total_processed);
415                 total_processed += bytes_processed;
416         }
417         else
418         {
419                 bytes_processed = process_raw_plane(srcData, width, height, dstData + 2, size - total_processed);
420                 total_processed += bytes_processed;
421                 srcData += bytes_processed;
422
423                 bytes_processed = process_raw_plane(srcData, width, height, dstData + 1, size - total_processed);
424                 total_processed += bytes_processed;
425                 srcData += bytes_processed;
426
427                 bytes_processed = process_raw_plane(srcData, width, height, dstData + 0, size - total_processed);
428                 total_processed += bytes_processed + 1;
429         }
430
431         return (size == total_processed) ? true : false;
432 }
433
434
435 /**
436  * bitmap decompression routine
437  */
438 boolean bitmap_decompress(uint8* srcData, uint8* dstData, int width, int height, int size, int srcBpp, int dstBpp)
439 {
440         if (srcBpp == 16 && dstBpp == 16)
441         {
442                 RleDecompress16to16(srcData, size, dstData, width * 2, width, height);
443                 freerdp_bitmap_flip(dstData, dstData, width * 2, height);
444         }
445         else if (srcBpp == 32 && dstBpp == 32)
446         {
447                 if (!bitmap_decompress4(srcData, dstData, width, height, size))
448                         return false;
449         }
450         else if (srcBpp == 15 && dstBpp == 15)
451         {
452                 RleDecompress16to16(srcData, size, dstData, width * 2, width, height);
453                 freerdp_bitmap_flip(dstData, dstData, width * 2, height);
454         }
455         else if (srcBpp == 8 && dstBpp == 8)
456         {
457                 RleDecompress8to8(srcData, size, dstData, width, width, height);
458                 freerdp_bitmap_flip(dstData, dstData, width, height);
459         }
460         else if (srcBpp == 24 && dstBpp == 24)
461         {
462                 RleDecompress24to24(srcData, size, dstData, width * 3, width, height);
463                 freerdp_bitmap_flip(dstData, dstData, width * 3, height);
464         }
465         else
466         {
467                 return false;
468         }
469
470         return true;
471 }