1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
29 #include "core/GP_Fill.h"
33 /* end of RLE or bitmap was reached */
35 /* in the middle of repeat sequence */
37 /* in the middle of undecoded run */
49 /* current position */
55 /* set to 1 if next pixel is in c */
68 #define DECLARE_RLE(name, iw, ih, iio) struct RLE name = { \
78 #define GETC(rle) do { \
79 if (rle->buf_pos < rle->buf_end) { \
80 rle->c = rle->buf[rle->buf_pos++]; \
82 rle->buf_end = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));\
83 if (rle->buf_end <= 0) \
85 rle->c = rle->buf[0]; \
90 static void RLE8_move(struct RLE
*rle
)
95 if (++rle
->x
>= rle
->w
) {
96 /* wrap around the end of line */
99 /* all pixels filled */
100 if (++rle
->y
>= rle
->h
) {
101 GP_DEBUG(4, "y >= h, stop");
102 rle
->state
= RLE_STOP
;
106 //GP_DEBUG(4, "RLE Move to %u %u", rle->x, rle->y);
111 static int RLE8_end_of_scanline(struct RLE
*rle
)
113 GP_DEBUG(4, "End of scanline at %u %u", rle
->x
, rle
->y
);
119 if (rle
->y
>= rle
->h
) {
120 GP_DEBUG(4, "y >= h, stop");
121 rle
->state
= RLE_STOP
;
127 static int RLE8_end_of_bitmap(struct RLE
*rle
)
129 GP_DEBUG(4, "End of bitmap data");
131 rle
->state
= RLE_STOP
;
136 static int RLE8_repeat(uint8_t rep
, struct RLE
*rle
)
140 GP_DEBUG(4, "RLE Repeat %i x 0x%02x", rep
, rle
->c
);
143 rle
->state
= RLE_REPEAT
;
148 static int RLE8_offset(struct RLE
*rle
)
157 if (x
== EOF
|| y
== EOF
)
160 GP_DEBUG(1, "RLE offset %i %i", x
, y
);
162 if (rle
->x
+ (uint32_t)x
>= rle
->w
|| rle
->y
+ (uint32_t)y
>= rle
->h
) {
163 GP_DEBUG(1, "RLE offset out of image, stop");
164 rle
->state
= RLE_STOP
;
173 static int RLE8_next_undecoded(struct RLE
*rle
)
177 //GP_DEBUG(4, "RLE unencoded %u %u -> %02x", rle->x, rle->y, rle->c);
179 if (--rle
->rep
== 0) {
180 rle
->state
= RLE_START
;
181 /* must be padded to odd number of bytes */
193 static int RLE8_next_repeat(struct RLE
*rle
)
195 //GP_DEBUG(4, "RLE repeat %u %u -> %02x", rle->x, rle->y, rle->c);
198 rle
->state
= RLE_START
;
207 static int RLE8_esc(struct RLE
*rle
)
211 GP_DEBUG(4, "RLE ESC %02x", rle
->c
);
215 return RLE8_end_of_scanline(rle
);
217 return RLE8_end_of_bitmap(rle
);
219 return RLE8_offset(rle
);
220 /* Undecoded sequence */
222 GP_DEBUG(4, "RLE Undecoded x %i", rle
->c
);
223 rle
->state
= RLE_UNDECODED
;
225 rle
->flag
= rle
->c
% 2;
230 static int RLE8_start(struct RLE
*rle
)
236 return RLE8_esc(rle
);
238 return RLE8_repeat(rle
->c
, rle
);
242 static int RLE8_next(struct RLE
*rle
)
247 switch (rle
->state
) {
249 if ((err
= RLE8_start(rle
)))
253 return RLE8_next_repeat(rle
);
255 return RLE8_next_undecoded(rle
);
259 /* Shouldn't be reached */
260 GP_BUG("Invalid RLE state %u", rle
->state
);
266 static int read_RLE8(GP_IO
*io
, struct bitmap_info_header
*header
,
267 GP_Pixmap
*pixmap
, GP_ProgressCallback
*callback
)
269 uint32_t palette_size
= get_palette_size(header
);
270 DECLARE_RLE(rle
, header
->w
, GP_ABS(header
->h
), io
);
273 if (pixmap
->pixel_type
!= GP_PIXEL_RGB888
) {
274 GP_WARN("Corrupted BMP header! "
275 "RLE8 is 24bit (RGB888) palette but header says %s",
276 GP_PixelTypeName(pixmap
->pixel_type
));
280 GP_Pixel
*palette
= GP_TempAlloc(palette_size
* sizeof(GP_Pixel
));
282 if ((err
= read_bitmap_palette(io
, header
, palette
, palette_size
)))
285 if ((err
= seek_pixels_offset(io
, header
)))
291 * Fill the image with first palette color.
293 * TODO: Untouched pixels should be treated as
294 * 1 bit transpanrency (in header3+)
296 GP_Fill(pixmap
, palette
[0]);
299 if ((err
= RLE8_next(&rle
)))
302 if (rle
.state
== RLE_STOP
)
309 if (idx
>= palette_size
) {
310 GP_DEBUG(1, "Index out of palette, ignoring");
321 ry
= GP_ABS(header
->h
) - 1 - rle
.y
;
323 GP_PutPixel_Raw_24BPP(pixmap
, rle
.x
, ry
, p
);
325 if (cnt
++ > header
->w
) {
327 if (GP_ProgressCallbackReport(callback
, rle
.y
,
328 pixmap
->h
, pixmap
->w
)) {
329 GP_DEBUG(1, "Operation aborted");
336 GP_ProgressCallbackDone(callback
);
338 GP_TempFree(palette_size
* sizeof(GP_Pixel
), palette
);