blob: b11c41b424cf62e6cd78ae96dd59e9e576eb2594 [file] [log] [blame]
Daniel Stenberg1c0c8612002-05-17 12:22:24 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +000021
22/*
232005-04-16 Tomas Salfischberger:
24 - New BMP loader function, based on the old one (borrowed a lot of
25 calculations and checks there.)
26 - Conversion part needs some optimization, doing unneeded calulations now.
Jens Arnoldadc48482006-11-18 14:29:51 +0000272006-11-18 Jens Arnold: complete rework
28 - All canonical formats supported now (1, 4, 8, 15/16, 24 and 32 bit)
29 - better protection against malformed / non-standard BMPs
30 - code heavily optimised for both size and speed
31 - dithering for 2 bit targets
Andrew Mahone781421a2008-12-09 23:07:59 +0000322008-11-02 Akio Idehara: refactor for scaler frontend
332008-12-08 Andrew Mahone: partial-line reading, scaler frontend
34 - read_part_line does the actual source BMP reading, return columns read
35 and updates fields in a struct bmp_args with the new data and current
36 reader state
37 - skip_lines_bmp and store_part_bmp implement the scaler callbacks to skip
38 ahead by whole lines, or read the next chunk of the current line
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +000039*/
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000040
41#include <stdio.h>
42#include <stdlib.h>
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +000043#include <string.h>
Jens Arnold83e18d92006-11-11 11:26:42 +000044#include "inttypes.h"
Nils Wallméniusd1a9e0c2009-10-06 22:02:06 +000045#include "system.h"
Andrew Mahone4eedc932009-01-04 21:22:05 +000046#ifndef PLUGIN
Felix Arends1f50b8b2002-05-29 14:36:09 +000047#include "debug.h"
Andrew Mahone4eedc932009-01-04 21:22:05 +000048#endif
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +000049#include "lcd.h"
Dave Chapman78d29f52008-03-26 23:35:34 +000050#include "file.h"
Maurus Cuelenaere36c71a62009-01-29 20:49:43 +000051#include "bmp.h"
Jens Arnold848e0b52006-11-20 00:20:09 +000052#ifdef HAVE_REMOTE_LCD
53#include "lcd-remote.h"
54#endif
Andrew Mahone781421a2008-12-09 23:07:59 +000055#ifdef ROCKBOX_DEBUG_BMP_LOADER
Thomas Martitz2f4a9412014-01-05 19:37:48 +010056#define BDEBUGF DEBUGF
Andrew Mahone781421a2008-12-09 23:07:59 +000057#else
58#define BDEBUGF(...)
59#endif
Dave Chapmanb9bb7232008-03-26 18:18:22 +000060#ifndef __PCTOOL__
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +000061#include "config.h"
Andrew Mahone781421a2008-12-09 23:07:59 +000062#include "resize.h"
Dave Chapmanb9bb7232008-03-26 18:18:22 +000063#else
64#undef DEBUGF
65#define DEBUGF(...)
66#endif
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000067
68#ifdef __GNUC__
69#define STRUCT_PACKED __attribute__((packed))
Felix Arends1f50b8b2002-05-29 14:36:09 +000070#else
71#define STRUCT_PACKED
72#pragma pack (push, 2)
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000073#endif
74
Jens Arnoldadc48482006-11-18 14:29:51 +000075/* BMP header structure */
76struct bmp_header {
77 uint16_t type; /* signature - 'BM' */
78 uint32_t size; /* file size in bytes */
79 uint16_t reserved1; /* 0 */
80 uint16_t reserved2; /* 0 */
81 uint32_t off_bits; /* offset to bitmap */
82 uint32_t struct_size; /* size of this struct (40) */
Jens Arnold89bfb662007-11-30 08:51:18 +000083 int32_t width; /* bmap width in pixels */
84 int32_t height; /* bmap height in pixels */
Jens Arnoldadc48482006-11-18 14:29:51 +000085 uint16_t planes; /* num planes - always 1 */
86 uint16_t bit_count; /* bits per pixel */
87 uint32_t compression; /* compression flag */
88 uint32_t size_image; /* image size in bytes */
89 int32_t x_pels_per_meter; /* horz resolution */
90 int32_t y_pels_per_meter; /* vert resolution */
91 uint32_t clr_used; /* 0 -> color table size */
92 uint32_t clr_important; /* important color count */
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000093} STRUCT_PACKED;
94
Andrew Mahone781421a2008-12-09 23:07:59 +000095/* masks for supported BI_BITFIELDS encodings (16/32 bit) */
Thomas Martitzef92ed42013-12-21 17:12:21 +010096static const struct uint8_rgb bitfields[][4] = {
Andrew Mahone781421a2008-12-09 23:07:59 +000097 /* 15bit */
98 {
Thomas Martitzef92ed42013-12-21 17:12:21 +010099 { .blue = 0x00, .green = 0x7c, .red = 0x00, .alpha = 0x00 },
100 { .blue = 0xe0, .green = 0x03, .red = 0x00, .alpha = 0x00 },
101 { .blue = 0x1f, .green = 0x00, .red = 0x00, .alpha = 0x00 },
102 { .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0x00 },
Andrew Mahone781421a2008-12-09 23:07:59 +0000103 },
104 /* 16bit */
105 {
Thomas Martitzef92ed42013-12-21 17:12:21 +0100106 { .blue = 0x00, .green = 0xf8, .red = 0x00, .alpha = 0x00 },
107 { .blue = 0xe0, .green = 0x07, .red = 0x00, .alpha = 0x00 },
108 { .blue = 0x1f, .green = 0x00, .red = 0x00, .alpha = 0x00 },
109 { .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0x00 },
Andrew Mahone781421a2008-12-09 23:07:59 +0000110 },
Thomas Martitzef92ed42013-12-21 17:12:21 +0100111 /* 32bit BGRA */
Andrew Mahone781421a2008-12-09 23:07:59 +0000112 {
Thomas Martitzef92ed42013-12-21 17:12:21 +0100113 { .blue = 0x00, .green = 0x00, .red = 0xff, .alpha = 0x00 },
114 { .blue = 0x00, .green = 0xff, .red = 0x00, .alpha = 0x00 },
115 { .blue = 0xff, .green = 0x00, .red = 0x00, .alpha = 0x00 },
116 { .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0xff },
117 },
118 /* 32bit ABGR */
119 {
120 { .blue = 0x00, .green = 0x00, .red = 0x00, .alpha = 0xff },
121 { .blue = 0x00, .green = 0x00, .red = 0xff, .alpha = 0x00 },
122 { .blue = 0x00, .green = 0xff, .red = 0x00, .alpha = 0x00 },
123 { .blue = 0xff, .green = 0x00, .red = 0x00, .alpha = 0x00 },
Andrew Mahone781421a2008-12-09 23:07:59 +0000124 },
Jens Arnoldadc48482006-11-18 14:29:51 +0000125};
Michael Sevakis76a6aaa2006-10-11 01:26:09 +0000126
Andrew Mahone07e982d2009-01-08 02:49:23 +0000127#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000128/* the full 16x16 Bayer dither matrix may be calculated quickly with this table
129*/
130const unsigned char dither_table[16] =
131 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 };
Jens Arnoldadc48482006-11-18 14:29:51 +0000132#endif
Michael Sevakisbed0db22006-10-11 18:12:36 +0000133
Jens Arnold81137172008-03-20 17:40:58 +0000134#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
135 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
136 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
Andrew Mahone781421a2008-12-09 23:07:59 +0000137const unsigned short vi_pattern[4] = {
Jens Arnold848e0b52006-11-20 00:20:09 +0000138 0x0101, 0x0100, 0x0001, 0x0000
139};
140#endif
141
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000142/******************************************************************************
143 * read_bmp_file()
144 *
Jens Arnoldadc48482006-11-18 14:29:51 +0000145 * Reads a BMP file and puts the data in rockbox format in *bitmap.
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000146 *
147 *****************************************************************************/
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000148int read_bmp_file(const char* filename,
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +0000149 struct bitmap *bm,
150 int maxsize,
Andrew Mahone90586202008-12-26 07:05:13 +0000151 int format,
152 const struct custom_format *cformat)
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000153{
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000154 int fd, ret;
Andrew Mahone07e982d2009-01-08 02:49:23 +0000155 fd = open(filename, O_RDONLY);
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000156
157 /* Exit if file opening failed */
158 if (fd < 0) {
159 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
160 return fd * 10 - 1;
161 }
162
Andrew Mahone781421a2008-12-09 23:07:59 +0000163 BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
164 filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
165 !!(format & FORMAT_KEEP_ASPECT));
Andrew Mahone90586202008-12-26 07:05:13 +0000166 ret = read_bmp_fd(fd, bm, maxsize, format, cformat);
Andrew Mahone07e982d2009-01-08 02:49:23 +0000167 close(fd);
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000168 return ret;
169}
170
Thomas Martitzef92ed42013-12-21 17:12:21 +0100171enum color_order {
172 /* only used for different types of 32bpp images */
173 BGRA, /* should be most common */
174 ABGR /* generated by some GIMP versions */
175};
Andrew Mahone781421a2008-12-09 23:07:59 +0000176
177struct bmp_args {
Thomas Martitz042d8bf2014-01-05 01:14:14 +0100178 /* needs to be at least 2byte aligned for faster 16bit reads.
179 * but aligning to cache should be even faster */
180 unsigned char buf[BM_MAX_WIDTH * 4] CACHEALIGN_AT_LEAST_ATTR(2);
Andrew Mahone781421a2008-12-09 23:07:59 +0000181 int fd;
182 short padded_width;
183 short read_width;
184 short width;
185 short depth;
Thomas Martitzef92ed42013-12-21 17:12:21 +0100186 enum color_order order;
Andrew Mahone781421a2008-12-09 23:07:59 +0000187 struct uint8_rgb *palette;
Andrew Mahone20f76d62009-05-04 15:46:41 +0000188#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
189 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000190 int cur_row;
191 int cur_col;
192 struct img_part part;
193#endif
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000194 /* as read_part_line() goes through the rows it'll set this to true
Thomas Martitzcaec07b2011-11-11 22:03:29 +0000195 * if it finds transparency. Initialize to 0 before calling */
196 int alpha_detected;
197 /* for checking transparency it checks the against the very first byte
198 * of the bitmap. Initalize to 0x80 before calling */
199 unsigned char first_alpha_byte;
Andrew Mahone781421a2008-12-09 23:07:59 +0000200};
201
202static unsigned int read_part_line(struct bmp_args *ba)
203{
204 const int padded_width = ba->padded_width;
205 const int read_width = ba->read_width;
206 const int width = ba->width;
Thomas Martitzef92ed42013-12-21 17:12:21 +0100207 int depth = ba->depth;
Andrew Mahone20f76d62009-05-04 15:46:41 +0000208#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
209 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000210 int cur_row = ba->cur_row;
211 int cur_col = ba->cur_col;
212#endif
213 const int fd = ba->fd;
214 uint8_t *ibuf;
215 struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
216 const struct uint8_rgb *palette = ba->palette;
Nils Wallménius3b04a852011-06-12 22:17:45 +0000217 uint32_t component, data;
Andrew Mahone781421a2008-12-09 23:07:59 +0000218 int ret;
219 int i, cols, len;
220
Andrew Mahone20f76d62009-05-04 15:46:41 +0000221#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
222 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000223 cols = MIN(width - cur_col,(int)BM_MAX_WIDTH);
224 BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH);
Andrew Mahone781421a2008-12-09 23:07:59 +0000225 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
226#else
227 cols = width;
228 len = read_width;
229#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000230 ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len;
Andrew Mahone781421a2008-12-09 23:07:59 +0000231 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
Andrew Mahone07e982d2009-01-08 02:49:23 +0000232 ret = read(fd, ibuf, len);
Andrew Mahone781421a2008-12-09 23:07:59 +0000233 if (ret != len)
234 {
235 DEBUGF("read_part_line: error reading image, read returned %d "
236 "expected %d\n", ret, len);
Andrew Mahone20f76d62009-05-04 15:46:41 +0000237#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
238 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000239 BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
240 cols, len);
Andrew Mahone4eedc932009-01-04 21:22:05 +0000241#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000242 return 0;
243 }
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000244
Thomas Martitzcaec07b2011-11-11 22:03:29 +0000245 /* detect if the image has useful alpha information.
246 * if all alpha bits are 0xff or 0x00 discard the information.
247 * if it has other bits, or is mixed with 0x00 and 0xff then interpret
248 * as alpha. assume no alpha until the opposite is proven. as mixed
249 * is alpha, compare to the first byte instead of 0xff and 0x00 separately
250 */
251 if (depth == 32 && ba->first_alpha_byte == 0x80)
252 ba->first_alpha_byte = ibuf[3] ? 0xff : 0x0;
253
Thomas Martitzef92ed42013-12-21 17:12:21 +0100254 /* select different color orders within the switch-case to avoid
255 * nested if/switch */
256 if (depth == 32)
257 depth += ba->order;
258
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000259 while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
Andrew Mahone781421a2008-12-09 23:07:59 +0000260 {
261 switch (depth)
262 {
263 case 1:
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000264 data = *ibuf++;
265 for (i = 0; i < 8; i++)
266 {
267 *buf++ = palette[data & 0x80 ? 1 : 0];
268 data <<= 1;
269 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000270 break;
271 case 4:
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000272 data = *ibuf++;
273 *buf++ = palette[data >> 4];
274 *buf++ = palette[data & 0xf];
Andrew Mahone781421a2008-12-09 23:07:59 +0000275 break;
276 case 8:
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000277 *buf++ = palette[*ibuf++];
Andrew Mahone781421a2008-12-09 23:07:59 +0000278 break;
279 case 15:
280 case 16:
Thomas Martitz042d8bf2014-01-05 01:14:14 +0100281 data = letoh16(*(uint16_t*)ibuf);
Andrew Mahone781421a2008-12-09 23:07:59 +0000282 component = (data << 3) & 0xf8;
283 component |= component >> 5;
284 buf->blue = component;
285 if (depth == 15)
286 {
287 data >>= 2;
288 component = data & 0xf8;
289 component |= component >> 5;
290 } else {
291 data >>= 3;
292 component = data & 0xfc;
293 component |= component >> 6;
294 }
295 buf->green = component;
296 data >>= 5;
297 component = data & 0xf8;
298 component |= component >> 5;
299 buf->red = component;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000300 buf->alpha = 0xff;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000301 buf++;
Andrew Mahone781421a2008-12-09 23:07:59 +0000302 ibuf += 2;
303 break;
Andrew Mahone781421a2008-12-09 23:07:59 +0000304 case 24:
305 buf->blue = *ibuf++;
306 buf->green = *ibuf++;
307 buf->red = *ibuf++;
Thomas Martitzcaec07b2011-11-11 22:03:29 +0000308 buf->alpha = 0xff;
309 buf++;
310 break;
Thomas Martitzef92ed42013-12-21 17:12:21 +0100311 case 32 + BGRA:
Thomas Martitzcaec07b2011-11-11 22:03:29 +0000312 buf->blue = *ibuf++;
313 buf->green = *ibuf++;
314 buf->red = *ibuf++;
315 buf->alpha = *ibuf++;
316 ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000317 buf++;
Andrew Mahone781421a2008-12-09 23:07:59 +0000318 break;
Thomas Martitzef92ed42013-12-21 17:12:21 +0100319 case 32 + ABGR:
320 buf->alpha = *ibuf++;
321 buf->blue = *ibuf++;
322 buf->green = *ibuf++;
323 buf->red = *ibuf++;
324 ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte);
325 buf++;
326 break;
Andrew Mahone781421a2008-12-09 23:07:59 +0000327 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000328 }
Andrew Mahone20f76d62009-05-04 15:46:41 +0000329#if !defined(HAVE_LCD_COLOR) && \
330 ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
331 defined(PLUGIN))
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000332 ibuf = ba->buf;
333 buf = (struct uint8_rgb*)ba->buf;
334 while (ibuf < ba->buf + cols)
335 *ibuf++ = brightness(*buf++);
336#endif
337
Andrew Mahone20f76d62009-05-04 15:46:41 +0000338#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
339 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000340 cur_col += cols;
341 if (cur_col == width)
342 {
343#endif
344 int pad = padded_width - read_width;
345 if (pad > 0)
346 {
347 BDEBUGF("seeking %d bytes to next line\n",pad);
Andrew Mahone07e982d2009-01-08 02:49:23 +0000348 lseek(fd, pad, SEEK_CUR);
Andrew Mahone781421a2008-12-09 23:07:59 +0000349 }
Andrew Mahone20f76d62009-05-04 15:46:41 +0000350#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
351 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000352 cur_col = 0;
353 BDEBUGF("read_part_line: completed row %d\n", cur_row);
354 cur_row += 1;
355 }
356
357 ba->cur_row = cur_row;
358 ba->cur_col = cur_col;
359#endif
360 return cols;
361}
362
Andrew Mahone20f76d62009-05-04 15:46:41 +0000363#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
364 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000365static struct img_part *store_part_bmp(void *args)
366{
367 struct bmp_args *ba = (struct bmp_args *)args;
368
369 ba->part.len = read_part_line(ba);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000370#ifdef HAVE_LCD_COLOR
Andrew Mahone781421a2008-12-09 23:07:59 +0000371 ba->part.buf = (struct uint8_rgb *)ba->buf;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000372#else
373 ba->part.buf = (uint8_t *)ba->buf;
374#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000375 if (ba->part.len)
376 return &(ba->part);
377 else
378 return NULL;
379}
Andrew Mahone781421a2008-12-09 23:07:59 +0000380#endif
381
Thomas Martitzef92ed42013-12-21 17:12:21 +0100382static inline int rgbcmp(const struct uint8_rgb *rgb1, const struct uint8_rgb *rgb2)
Andrew Mahone781421a2008-12-09 23:07:59 +0000383{
Thomas Martitzef92ed42013-12-21 17:12:21 +0100384 return memcmp(rgb1, rgb2, sizeof(struct uint8_rgb));
Andrew Mahone781421a2008-12-09 23:07:59 +0000385}
Thomas Martitzef92ed42013-12-21 17:12:21 +0100386
Andrew Mahone91efc162009-05-09 07:31:27 +0000387#if LCD_DEPTH > 1
Andrew Mahone59e70b52009-05-09 10:32:07 +0000388#if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
389static inline
390#endif
Andrew Mahone91efc162009-05-09 07:31:27 +0000391void output_row_8_native(uint32_t row, void * row_in,
392 struct scaler_context *ctx)
393{
394 int col;
395 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
396 uint8_t dy = DITHERY(row);
397#ifdef HAVE_LCD_COLOR
398 struct uint8_rgb *qp = (struct uint8_rgb*)row_in;
399#else
400 uint8_t *qp = (uint8_t*)row_in;
401#endif
402 BDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
403#if LCD_DEPTH == 2
404#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
405 /* greyscale iPods */
406 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
407 int shift = 6;
408 int delta = 127;
409 unsigned bright;
410 unsigned data = 0;
411
412 for (col = 0; col < ctx->bm->width; col++) {
413 if (ctx->dither)
414 delta = DITHERXDY(col,dy);
415 bright = *qp++;
416 bright = (3 * bright + (bright >> 6) + delta) >> 8;
417 data |= (~bright & 3) << shift;
418 shift -= 2;
419 if (shift < 0) {
420 *dest++ = data;
421 data = 0;
422 shift = 6;
423 }
424 }
425 if (shift < 6)
426 *dest++ = data;
427#elif LCD_PIXELFORMAT == VERTICAL_PACKING
428 /* iriver H1x0 */
429 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
430 (row >> 2);
431 int shift = 2 * (row & 3);
432 int delta = 127;
433 unsigned bright;
434
435 for (col = 0; col < ctx->bm->width; col++) {
436 if (ctx->dither)
437 delta = DITHERXDY(col,dy);
438 bright = *qp++;
439 bright = (3 * bright + (bright >> 6) + delta) >> 8;
440 *dest++ |= (~bright & 3) << shift;
441 }
442#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
443 /* iAudio M3 */
444 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
445 (row >> 3);
446 int shift = row & 7;
447 int delta = 127;
448 unsigned bright;
449
450 for (col = 0; col < ctx->bm->width; col++) {
451 if (ctx->dither)
452 delta = DITHERXDY(col,dy);
453 bright = *qp++;
454 bright = (3 * bright + (bright >> 6) + delta) >> 8;
455 *dest++ |= vi_pattern[bright] << shift;
456 }
457#endif /* LCD_PIXELFORMAT */
Thomas Martitza1842c02014-06-18 07:15:00 +0200458#elif LCD_DEPTH >= 16
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000459 /* iriver h300, colour iPods, X5 */
460 (void)fb_width;
461 fb_data *dest = STRIDE_MAIN((fb_data *)ctx->bm->data + fb_width * row,
462 (fb_data *)ctx->bm->data + row);
Karl Kurbjune4345362009-09-01 00:57:47 +0000463 int delta = 127;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000464 unsigned r, g, b;
465 /* setup alpha channel buffer */
466 unsigned char *bm_alpha = NULL;
467 if (ctx->bm->alpha_offset > 0)
468 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset;
469 if (bm_alpha)
Thomas Martitz312b2a22011-11-11 19:05:11 +0000470 bm_alpha += ALIGN_UP(ctx->bm->width, 2) * row/2;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000471
Karl Kurbjune4345362009-09-01 00:57:47 +0000472 for (col = 0; col < ctx->bm->width; col++) {
Thomas Martitza1842c02014-06-18 07:15:00 +0200473 (void) delta;
Karl Kurbjune4345362009-09-01 00:57:47 +0000474 if (ctx->dither)
475 delta = DITHERXDY(col,dy);
476 r = qp->red;
477 g = qp->green;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000478 b = qp->blue;
Thomas Martitza1842c02014-06-18 07:15:00 +0200479#if LCD_DEPTH < 24
Karl Kurbjune4345362009-09-01 00:57:47 +0000480 r = (31 * r + (r >> 3) + delta) >> 8;
481 g = (63 * g + (g >> 2) + delta) >> 8;
482 b = (31 * b + (b >> 3) + delta) >> 8;
Thomas Martitza1842c02014-06-18 07:15:00 +0200483#endif
484 *dest = FB_RGBPACK_LCD(r, g, b);
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000485 dest += STRIDE_MAIN(1, ctx->bm->height);
486 if (bm_alpha) {
Thomas Martitzca634a02013-02-12 10:26:44 +0100487 /* pack alpha channel for 2 pixels into 1 byte and negate
488 * according to the interal alpha channel format */
489 uint8_t alpha = ~qp->alpha;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000490 if (col%2)
491 *bm_alpha++ |= alpha&0xf0;
492 else
493 *bm_alpha = alpha>>4;
494 }
495 qp++;
Karl Kurbjune4345362009-09-01 00:57:47 +0000496 }
Andrew Mahone91efc162009-05-09 07:31:27 +0000497#endif /* LCD_DEPTH */
498}
499#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000500
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000501/******************************************************************************
502 * read_bmp_fd()
503 *
504 * Reads a BMP file in an open file descriptor and puts the data in rockbox
505 * format in *bitmap.
506 *
507 *****************************************************************************/
508int read_bmp_fd(int fd,
509 struct bitmap *bm,
510 int maxsize,
Andrew Mahone90586202008-12-26 07:05:13 +0000511 int format,
512 const struct custom_format *cformat)
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000513{
Jens Arnoldadc48482006-11-18 14:29:51 +0000514 struct bmp_header bmph;
Andrew Mahone781421a2008-12-09 23:07:59 +0000515 int padded_width;
516 int read_width;
Jens Arnoldadc48482006-11-18 14:29:51 +0000517 int depth, numcolors, compression, totalsize;
Thomas Martitzce8aef72014-01-11 14:14:46 +0100518 int ret, hdr_size;
Maurus Cuelenaereaec37aa2009-05-25 11:12:27 +0000519 bool return_size = format & FORMAT_RETURN_SIZE;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000520 bool read_alpha = format & FORMAT_TRANSPARENT;
Thomas Martitzef92ed42013-12-21 17:12:21 +0100521 enum color_order order = BGRA;
Jens Arnoldadc48482006-11-18 14:29:51 +0000522
523 unsigned char *bitmap = bm->data;
Andrew Mahone781421a2008-12-09 23:07:59 +0000524 struct uint8_rgb palette[256];
Andrew Mahone781421a2008-12-09 23:07:59 +0000525 struct rowset rset;
526 struct dim src_dim;
Andrew Mahone20f76d62009-05-04 15:46:41 +0000527#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
528 defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000529 bool dither = false;
Andrew Mahone20f76d62009-05-04 15:46:41 +0000530#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000531
Andree Buschmann29f04cc2011-09-03 11:04:41 +0000532 bool remote = false;
Thomas Martitza1842c02014-06-18 07:15:00 +0200533#ifdef HAVE_REMOTE_LCD
Jens Arnold848e0b52006-11-20 00:20:09 +0000534 if (format & FORMAT_REMOTE) {
Andree Buschmann29f04cc2011-09-03 11:04:41 +0000535 remote = true;
Jens Arnold848e0b52006-11-20 00:20:09 +0000536#if LCD_REMOTE_DEPTH == 1
537 format = FORMAT_MONO;
Jens Arnold848e0b52006-11-20 00:20:09 +0000538#endif
539 }
540#endif /* HAVE_REMOTE_LCD */
Andrew Mahone781421a2008-12-09 23:07:59 +0000541
Thomas Martitz354015e2011-11-08 22:34:35 +0000542#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
543 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
544 unsigned int resize = IMG_NORESIZE;
545
Andrew Mahone781421a2008-12-09 23:07:59 +0000546 if (format & FORMAT_RESIZE) {
547 resize = IMG_RESIZE;
Andrew Mahone781421a2008-12-09 23:07:59 +0000548 }
549
Michael Sevakis76a6aaa2006-10-11 01:26:09 +0000550#else
Jens Arnoldadc48482006-11-18 14:29:51 +0000551
552 (void)format;
Andrew Mahone781421a2008-12-09 23:07:59 +0000553#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
Andrew Mahone20f76d62009-05-04 15:46:41 +0000554#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
555 defined(PLUGIN)
556 if (format & FORMAT_DITHER) {
557 dither = true;
558 }
559#endif
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000560 /* read fileheader */
Andrew Mahone07e982d2009-01-08 02:49:23 +0000561 ret = read(fd, &bmph, sizeof(struct bmp_header));
Jens Arnoldadc48482006-11-18 14:29:51 +0000562 if (ret < 0) {
Jens Arnoldadc48482006-11-18 14:29:51 +0000563 return ret * 10 - 2;
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000564 }
Michael Sevakise0710b22006-10-15 17:51:00 +0000565
Jens Arnoldadc48482006-11-18 14:29:51 +0000566 if (ret != sizeof(struct bmp_header)) {
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000567 DEBUGF("read_bmp_fd: can't read BMP header.");
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000568 return -3;
569 }
570
Andrew Mahone781421a2008-12-09 23:07:59 +0000571 src_dim.width = letoh32(bmph.width);
572 src_dim.height = letoh32(bmph.height);
573 if (src_dim.height < 0) { /* Top-down BMP file */
574 src_dim.height = -src_dim.height;
575 rset.rowstep = 1;
Jens Arnold89bfb662007-11-30 08:51:18 +0000576 } else { /* normal BMP */
Andrew Mahone781421a2008-12-09 23:07:59 +0000577 rset.rowstep = -1;
Jens Arnold89bfb662007-11-30 08:51:18 +0000578 }
579
Andrew Mahone781421a2008-12-09 23:07:59 +0000580 depth = letoh16(bmph.bit_count);
581 /* 4-byte boundary aligned */
582 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
583 padded_width = (read_width + 3) & ~3;
Jens Arnoldadc48482006-11-18 14:29:51 +0000584
Andrew Mahone781421a2008-12-09 23:07:59 +0000585 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
586 src_dim.height, depth, padded_width);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000587
588#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
Andrew Mahone781421a2008-12-09 23:07:59 +0000589 if ((format & 3) == FORMAT_ANY) {
Jens Arnoldadc48482006-11-18 14:29:51 +0000590 if (depth == 1)
Andrew Mahone781421a2008-12-09 23:07:59 +0000591 format = (format & ~3);
Jens Arnoldadc48482006-11-18 14:29:51 +0000592 else
Andrew Mahone781421a2008-12-09 23:07:59 +0000593 format = (format & ~3) | FORMAT_NATIVE;
Jens Arnoldadc48482006-11-18 14:29:51 +0000594 }
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000595 bm->format = format & 1;
596 if ((format & 1) == FORMAT_MONO)
Jens Arnoldadc48482006-11-18 14:29:51 +0000597 {
Andrew Mahone20f76d62009-05-04 15:46:41 +0000598#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
599 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000600 resize &= ~IMG_RESIZE;
601 resize |= IMG_NORESIZE;
Andrew Mahone20f76d62009-05-04 15:46:41 +0000602#endif
Frank Gevaertsbd3056c2011-08-01 20:07:05 +0000603 remote = false;
Jens Arnoldadc48482006-11-18 14:29:51 +0000604 }
Andrew Mahone4eedc932009-01-04 21:22:05 +0000605#elif !defined(PLUGIN)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000606 if (src_dim.width > BM_MAX_WIDTH)
Andrew Mahone781421a2008-12-09 23:07:59 +0000607 return -6;
608#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
609
Andrew Mahone20f76d62009-05-04 15:46:41 +0000610#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
611 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000612 if (resize & IMG_RESIZE) {
613 if(format & FORMAT_KEEP_ASPECT) {
614 /* keep aspect ratio.. */
Andrew Mahone781421a2008-12-09 23:07:59 +0000615 struct dim resize_dim = {
616 .width = bm->width,
617 .height = bm->height,
618 };
619 if (recalc_dimension(&resize_dim, &src_dim))
620 resize = IMG_NORESIZE;
621 bm->width = resize_dim.width;
622 bm->height = resize_dim.height;
623 }
624 }
625
626 if (!(resize & IMG_RESIZE)) {
627#endif
628 /* returning image size */
629 bm->width = src_dim.width;
630 bm->height = src_dim.height;
631
Andrew Mahone20f76d62009-05-04 15:46:41 +0000632#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
633 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000634 }
635#endif
Andrew Mahone20f76d62009-05-04 15:46:41 +0000636#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
637 format &= 1;
638#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000639 if (rset.rowstep > 0) { /* Top-down BMP file */
640 rset.rowstart = 0;
641 rset.rowstop = bm->height;
642 } else { /* normal BMP */
643 rset.rowstart = bm->height - 1;
644 rset.rowstop = -1;
645 }
646
Thomas Martitz312b2a22011-11-11 19:05:11 +0000647 /* need even rows (see lcd-16bit-common.c for details) */
648 int alphasize = ALIGN_UP(bm->width, 2) * bm->height / 2;
Andrew Mahone90586202008-12-26 07:05:13 +0000649 if (cformat)
650 totalsize = cformat->get_size(bm);
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000651 else {
Andrew Mahone90586202008-12-26 07:05:13 +0000652 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000653 if (!remote)
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000654 if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */
Thomas Martitz312b2a22011-11-11 19:05:11 +0000655 totalsize += alphasize;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000656 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000657
Maurus Cuelenaereaec37aa2009-05-25 11:12:27 +0000658 if(return_size)
Maurus Cuelenaere0bddb7e2009-05-25 15:19:34 +0000659 {
Maurus Cuelenaered2ea7db2009-05-25 20:15:02 +0000660#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
661 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Maurus Cuelenaere0bddb7e2009-05-25 15:19:34 +0000662 if(resize)
663 totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0);
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000664 else if (bm->width > BM_MAX_WIDTH)
665 totalsize += bm->width*4;
Maurus Cuelenaered2ea7db2009-05-25 20:15:02 +0000666#endif
Maurus Cuelenaereaec37aa2009-05-25 11:12:27 +0000667 return totalsize;
Maurus Cuelenaere0bddb7e2009-05-25 15:19:34 +0000668 }
Maurus Cuelenaereaec37aa2009-05-25 11:12:27 +0000669
Jens Arnoldadc48482006-11-18 14:29:51 +0000670 /* Check if this fits the buffer */
671 if (totalsize > maxsize) {
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000672 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
Marcin Bukatd5568092017-04-27 11:36:40 +0200673 "%d bytes (%d max).\n", totalsize, maxsize);
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000674 return -6;
675 }
676
Thomas Martitzce8aef72014-01-11 14:14:46 +0100677 hdr_size = letoh32(bmph.struct_size);
Andrew Mahone781421a2008-12-09 23:07:59 +0000678 compression = letoh32(bmph.compression);
Jens Arnoldadc48482006-11-18 14:29:51 +0000679 if (depth <= 8) {
Andrew Mahone781421a2008-12-09 23:07:59 +0000680 numcolors = letoh32(bmph.clr_used);
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +0000681 if (numcolors == 0)
Jens Arnold1d6df542009-06-07 21:27:05 +0000682 numcolors = BIT_N(depth);
Thomas Martitzce8aef72014-01-11 14:14:46 +0100683 /* forward to the color table */
684 lseek(fd, 14+hdr_size, SEEK_SET);
Thomas Martitzef92ed42013-12-21 17:12:21 +0100685 } else {
Thomas Martitzef92ed42013-12-21 17:12:21 +0100686 numcolors = 0;
687 if (compression == 3) {
688 if (hdr_size >= 56)
689 numcolors = 4;
690 else /* hdr_size == 52 */
691 numcolors = 3;
692 }
693 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000694
Thomas Martitzef92ed42013-12-21 17:12:21 +0100695 /* read color tables. for BI_BITFIELDS this actually
696 * reads the color masks */
Jens Arnoldadc48482006-11-18 14:29:51 +0000697 if (numcolors > 0 && numcolors <= 256) {
Andrew Mahone781421a2008-12-09 23:07:59 +0000698 int i;
Andrew Mahone781421a2008-12-09 23:07:59 +0000699 for (i = 0; i < numcolors; i++) {
Thomas Martitzef92ed42013-12-21 17:12:21 +0100700 if (read(fd, &palette[i], sizeof(struct uint8_rgb))
701 != (int)sizeof(struct uint8_rgb)) {
Andrew Mahone781421a2008-12-09 23:07:59 +0000702 DEBUGF("read_bmp_fd: Can't read color palette\n");
703 return -7;
704 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000705 }
706 }
707
708 switch (depth) {
709 case 16:
710#if LCD_DEPTH >= 16
711 /* don't dither 16 bit BMP to LCD with same or larger depth */
Jens Arnold848e0b52006-11-20 00:20:09 +0000712 if (!remote)
Jens Arnold848e0b52006-11-20 00:20:09 +0000713 dither = false;
Jens Arnoldadc48482006-11-18 14:29:51 +0000714#endif
715 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
716 depth = 15;
717 break;
718 } /* else fall through */
719
720 case 32:
721 if (compression == 3) { /* BI_BITFIELDS */
Thomas Martitza62bd922013-12-22 20:15:03 +0100722 bool found = false;
Andrew Mahone781421a2008-12-09 23:07:59 +0000723 int i, j;
724
Thomas Martitz9f878b12013-12-22 21:04:11 +0100725 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == {2,3}) is 32bit */
Thomas Martitza62bd922013-12-22 20:15:03 +0100726 for (i = 0; i < ARRAY_SIZE(bitfields) && !found; i++) {
Thomas Martitzef92ed42013-12-21 17:12:21 +0100727 /* for 15bpp and higher numcolors has the number of color masks */
728 for (j = 0; j < numcolors; j++) {
729 if (!rgbcmp(&palette[j], &bitfields[i][j])) {
Andrew Mahone781421a2008-12-09 23:07:59 +0000730 found = true;
731 } else {
732 found = false;
733 break;
734 }
735 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000736 }
Thomas Martitza62bd922013-12-22 20:15:03 +0100737 if (found) {
Thomas Martitz9f878b12013-12-22 21:04:11 +0100738 if (i == 1) /* 15bit */
Thomas Martitza62bd922013-12-22 20:15:03 +0100739 depth = 15;
Thomas Martitz9f878b12013-12-22 21:04:11 +0100740 else if (i == 4) /* 32bit, ABGR bitmap */
Thomas Martitza62bd922013-12-22 20:15:03 +0100741 order = ABGR;
Thomas Martitz9f878b12013-12-22 21:04:11 +0100742 break;
Thomas Martitza62bd922013-12-22 20:15:03 +0100743 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000744 } /* else fall through */
745
746 default:
747 if (compression != 0) { /* not BI_RGB */
Nicolas Pennequinec6569e2007-11-10 13:26:11 +0000748 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
Jens Arnoldadc48482006-11-18 14:29:51 +0000749 compression);
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +0000750 return -8;
751 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000752 break;
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +0000753 }
Michael Sevakise0710b22006-10-15 17:51:00 +0000754
Thomas Martitza1842c02014-06-18 07:15:00 +0200755#if LCD_DEPTH >= 24
756 /* Never dither 24/32 bit BMP to 24 bit LCDs */
757 if (depth >= 24 && !remote)
758 dither = false;
759#endif
760
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000761 /* Search to the beginning of the image data */
Andrew Mahone07e982d2009-01-08 02:49:23 +0000762 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000763
Andrew Mahone07e982d2009-01-08 02:49:23 +0000764 memset(bitmap, 0, totalsize);
Michael Sevakise0710b22006-10-15 17:51:00 +0000765
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000766#ifdef HAVE_LCD_COLOR
767 if (read_alpha && depth == 32)
Thomas Martitz312b2a22011-11-11 19:05:11 +0000768 bm->alpha_offset = totalsize - alphasize;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000769 else
770 bm->alpha_offset = 0;
771#endif
772
Andrew Mahone781421a2008-12-09 23:07:59 +0000773 struct bmp_args ba = {
774 .fd = fd, .padded_width = padded_width, .read_width = read_width,
775 .width = src_dim.width, .depth = depth, .palette = palette,
Andrew Mahone20f76d62009-05-04 15:46:41 +0000776#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
777 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000778 .cur_row = 0, .cur_col = 0, .part = {0,0},
Jens Arnoldadc48482006-11-18 14:29:51 +0000779#endif
Thomas Martitzcaec07b2011-11-11 22:03:29 +0000780 .alpha_detected = false, .first_alpha_byte = 0x80,
Thomas Martitzef92ed42013-12-21 17:12:21 +0100781 .order = order,
Andrew Mahone781421a2008-12-09 23:07:59 +0000782 };
Jens Arnoldadc48482006-11-18 14:29:51 +0000783
Andrew Mahone20f76d62009-05-04 15:46:41 +0000784#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
785 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
Andrew Mahone91efc162009-05-09 07:31:27 +0000786 if (resize)
Andrew Mahone90586202008-12-26 07:05:13 +0000787 {
788 if (resize_on_load(bm, dither, &src_dim, &rset,
789 bitmap + totalsize, maxsize - totalsize,
Andrew Mahoneeef79452009-05-06 04:53:56 +0000790 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
Andrew Mahone90586202008-12-26 07:05:13 +0000791 return totalsize;
792 else
793 return 0;
794 }
Jens Arnoldadc48482006-11-18 14:29:51 +0000795#endif /* LCD_DEPTH */
Jens Arnoldadc48482006-11-18 14:29:51 +0000796
Andrew Mahone91efc162009-05-09 07:31:27 +0000797#if LCD_DEPTH > 1 || defined(PLUGIN)
798 struct scaler_context ctx = {
799 .bm = bm,
800 .dither = dither,
801 };
Andrew Mahone20f76d62009-05-04 15:46:41 +0000802#endif
Andrew Mahone59e70b52009-05-09 10:32:07 +0000803#if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
Andrew Mahone91efc162009-05-09 07:31:27 +0000804#if LCD_DEPTH > 1
805 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
806 output_row_8_native;
807#elif defined(PLUGIN)
808 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
809#endif
810#if LCD_DEPTH > 1 || defined(PLUGIN)
811 if (cformat)
812 output_row_8 = cformat->output_row_8;
813#endif
Andrew Mahone59e70b52009-05-09 10:32:07 +0000814#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000815
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000816 unsigned char *buf = ba.buf;
817#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
818 defined(PLUGIN)
819 if (bm->width > BM_MAX_WIDTH)
820 {
821#if defined(HAVE_BMP_SCALING) || defined(PLUGIN)
822 unsigned int len = maxsize - totalsize;
823 buf = bitmap + totalsize;
824 ALIGN_BUFFER(buf, len, sizeof(uint32_t));
825 if (bm->width*4 > (int)len)
826#endif
827 return -6;
828 }
829#endif
Andrew Mahone91efc162009-05-09 07:31:27 +0000830 int row;
Andrew Mahone781421a2008-12-09 23:07:59 +0000831 /* loop to read rows and put them to buffer */
832 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000833#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
834 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
835 if (bm->width > BM_MAX_WIDTH)
836 {
837#if defined(HAVE_LCD_COLOR)
838 struct uint8_rgb *p = (struct uint8_rgb *)buf;
839#else
840 uint8_t* p = buf;
841#endif
842 do {
843 int len = read_part_line(&ba);
844 if (!len)
845 return -9;
846 memcpy(p, ba.buf, len*sizeof(*p));
847 p += len;
848 } while (ba.cur_col);
849 }
850 else
851#endif
Andrew Mahone91efc162009-05-09 07:31:27 +0000852 if (!read_part_line(&ba))
853 return -9;
854#ifndef PLUGIN
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000855#if !defined(HAVE_LCD_COLOR) && \
856 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000857 uint8_t* qp = buf;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000858#else
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000859 struct uint8_rgb *qp = (struct uint8_rgb *)buf;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000860#endif
Andrew Mahone91efc162009-05-09 07:31:27 +0000861#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000862 /* Convert to destination format */
Andrew Mahone91efc162009-05-09 07:31:27 +0000863#if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
864 !defined(PLUGIN)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000865 if (format == FORMAT_NATIVE) {
866#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
867 if (remote) {
Andrew Mahone91efc162009-05-09 07:31:27 +0000868 unsigned char dy = DITHERY(row);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000869#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
870 /* iAudio X5/M5 remote */
871 fb_remote_data *dest = (fb_remote_data *)bitmap
872 + bm->width * (row >> 3);
873 int shift = row & 7;
874 int delta = 127;
875 unsigned bright;
Andrew Mahone781421a2008-12-09 23:07:59 +0000876
Andrew Mahone91efc162009-05-09 07:31:27 +0000877 int col;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000878 for (col = 0; col < bm->width; col++) {
879 if (dither)
880 delta = DITHERXDY(col,dy);
881#if !defined(HAVE_LCD_COLOR) && \
882 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
883 bright = *qp++;
884#else
885 bright = brightness(*qp++);
Andrew Mahone781421a2008-12-09 23:07:59 +0000886#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000887 bright = (3 * bright + (bright >> 6) + delta) >> 8;
888 *dest++ |= vi_pattern[bright] << shift;
889 }
890#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
891 } else
892#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
Andrew Mahone91efc162009-05-09 07:31:27 +0000893#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
894 (LCD_REMOTE_DEPTH > 1) */
895#if LCD_DEPTH > 1 || defined(PLUGIN)
Andrew Mahone781421a2008-12-09 23:07:59 +0000896 {
Andrew Mahone59e70b52009-05-09 10:32:07 +0000897#if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000898 output_row_8_native(row, buf, &ctx);
Andrew Mahone59e70b52009-05-09 10:32:07 +0000899#else
Teruaki Kawashimac4eea8f2010-02-18 15:10:31 +0000900 output_row_8(row, buf, &ctx);
Andrew Mahone59e70b52009-05-09 10:32:07 +0000901#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000902 }
Andrew Mahone91efc162009-05-09 07:31:27 +0000903#endif
904#if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
905 !defined(PLUGIN)
906 }
907#ifndef PLUGIN
908 else
909#endif
910#endif
911#ifndef PLUGIN
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000912 {
Andrew Mahone91efc162009-05-09 07:31:27 +0000913 unsigned char *p = bitmap + bm->width * (row >> 3);
Jens Arnold1d6df542009-06-07 21:27:05 +0000914 unsigned char mask = BIT_N(row & 7);
Andrew Mahone91efc162009-05-09 07:31:27 +0000915 int col;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000916 for (col = 0; col < bm->width; col++, p++)
917#if !defined(HAVE_LCD_COLOR) && \
918 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
919 if (*qp++ < 128)
920 *p |= mask;
921#else
Jens Arnoldadc48482006-11-18 14:29:51 +0000922 if (brightness(*qp++) < 128)
923 *p |= mask;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000924#endif
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000925 }
Andrew Mahone91efc162009-05-09 07:31:27 +0000926#endif
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000927 }
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000928#ifdef HAVE_LCD_COLOR
929 if (!ba.alpha_detected)
930 { /* if this has an alpha channel, totalsize accounts for it as well
931 * subtract if no actual alpha information was found */
932 if (bm->alpha_offset > 0)
Thomas Martitz312b2a22011-11-11 19:05:11 +0000933 totalsize -= alphasize;
Thomas Martitzf443e7b2011-11-08 21:36:49 +0000934 bm->alpha_offset = 0;
935 }
936#endif
Linus Nielsen Feltzing745adad2006-01-28 12:12:42 +0000937 return totalsize; /* return the used buffer size. */
Linus Nielsen Feltzing250678b2005-04-25 07:42:10 +0000938}