Correct bitmap color depth
[kugel-rb.git] / apps / plugins / ppmviewer.c
blobb186393d0573a0ed31dab1ed113cd6b6a244ed3f
1 /*****************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Alexander Papst
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/pluginlib_bmp.h"
25 #if defined(HAVE_LCD_COLOR)
27 PLUGIN_HEADER
29 /* Magic constants. */
30 #define PPM_MAGIC1 'P'
31 #define PPM_MAGIC2 '3'
32 #define RPPM_MAGIC2 '6'
33 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
34 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
36 #define PPM_OVERALLMAXVAL 65535
37 #define PPM_MAXSIZE (300*1024)/sizeof(fb_data)
39 #define ppm_error(...) rb->splashf(HZ*2, __VA_ARGS__ )
41 static fb_data buffer[PPM_MAXSIZE];
42 static fb_data lcd_buf[LCD_WIDTH * LCD_HEIGHT];
44 int ppm_read_magic_number(int fd)
46 char i1, i2;
47 if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1))
49 ppm_error( "Error reading magic number from ppm image stream. "\
50 "Most often, this means your input file is empty." );
51 return PLUGIN_ERROR;
53 return i1 * 256 + i2;
56 char ppm_getc(int fd)
58 char ch;
60 if (!rb->read(fd, &ch, 1)) {
61 ppm_error("EOF. Read error reading a byte");
62 return PLUGIN_ERROR;
65 if (ch == '#') {
66 do {
67 if (!rb->read(fd, &ch, 1)) {
68 ppm_error("EOF. Read error reading a byte");
69 return PLUGIN_ERROR;
71 } while (ch != '\n' && ch != '\r');
73 return ch;
76 int ppm_getuint(int fd)
78 char ch;
79 int i;
80 int digitVal;
82 do {
83 ch = ppm_getc(fd);
84 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
86 if (ch < '0' || ch > '9') {
87 ppm_error("Junk (%c) in file where an integer should be.", ch);
88 return PLUGIN_ERROR;
91 i = 0;
93 do {
94 digitVal = ch - '0';
96 if (i > INT_MAX/10 - digitVal) {
97 ppm_error("ASCII decimal integer in file is "\
98 "too large to be processed.");
99 return PLUGIN_ERROR;
102 i = i * 10 + digitVal;
103 ch = ppm_getc(fd);
105 } while (ch >= '0' && ch <= '9');
107 return i;
110 int ppm_getrawbyte(int fd)
112 unsigned char by;
114 if (!rb->read(fd, &by, 1)) {
115 ppm_error("EOF. Read error while reading a one-byte sample.");
116 return PLUGIN_ERROR;
119 return (int)by;
122 int ppm_getrawsample(int fd, int const maxval)
124 if (maxval < 256) {
125 /* The sample is just one byte. Read it. */
126 return(ppm_getrawbyte(fd));
127 } else {
128 /* The sample is two bytes. Read both. */
129 unsigned char byte_pair[2];
131 if (!rb->read(fd, byte_pair, 2)) {
132 ppm_error("EOF. Read error while reading a long sample.");
133 return PLUGIN_ERROR;
135 return((byte_pair[0]<<8) | byte_pair[1]);
139 int read_ppm_init_rest(int fd,
140 int * const cols,
141 int * const rows,
142 int * const maxval)
144 /* Read size. */
145 *cols = ppm_getuint(fd);
146 *rows = ppm_getuint(fd);
148 if ((long unsigned int)(*cols * *rows) > PPM_MAXSIZE) {
149 ppm_error("Imagesize (%ld pixels) is too large. "\
150 "The maximum allowed is %ld.",
151 (long unsigned int)(*cols * *rows),
152 (long unsigned int)PPM_MAXSIZE);
153 return PLUGIN_ERROR;
156 /* Read maxval. */
157 *maxval = ppm_getuint(fd);
159 if (*maxval > PPM_OVERALLMAXVAL) {
160 ppm_error("maxval of input image (%u) is too large. "\
161 "The maximum allowed by the PPM is %u.",
162 *maxval, PPM_OVERALLMAXVAL);
163 return PLUGIN_ERROR;
165 if (*maxval == 0) {
166 ppm_error("maxval of input image is zero.");
167 return PLUGIN_ERROR;
169 return 1;
172 void read_ppm_init(int fd,
173 int * const cols,
174 int * const rows,
175 int * const maxval,
176 int * const format)
178 /* Check magic number. */
179 *format = ppm_read_magic_number( fd );
181 if (*format == PLUGIN_ERROR) return;
182 switch (*format) {
183 case PPM_FORMAT:
184 case RPPM_FORMAT:
185 if(read_ppm_init_rest(fd, cols, rows, maxval) == PLUGIN_ERROR) {
186 *format = PLUGIN_ERROR;
188 break;
190 default:
191 ppm_error( "Bad magic number - not a ppm or rppm file." );
192 *format = PLUGIN_ERROR;
196 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
197 #define BUFADDR(x, y, width, height) ( buffer + height*(x) + (y))
198 #else
199 #define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x))
200 #endif
202 int read_ppm_row(int fd,
203 int const row,
204 int const cols,
205 int const rows,
206 int const maxval,
207 int const format)
209 #if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE)
210 (void) rows;
211 #endif
213 int col;
214 int r, g, b;
215 switch (format) {
216 case PPM_FORMAT:
217 for (col = 0; col < cols; ++col) {
218 r = ppm_getuint(fd);
219 g = ppm_getuint(fd);
220 b = ppm_getuint(fd);
222 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
223 b == PLUGIN_ERROR)
225 return PLUGIN_ERROR;
227 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
228 (255 / maxval) * r,
229 (255 / maxval) * g,
230 (255 / maxval) * b);
232 break;
234 case RPPM_FORMAT:
235 for (col = 0; col < cols; ++col) {
236 r = ppm_getrawsample(fd, maxval);
237 g = ppm_getrawsample(fd, maxval);
238 b = ppm_getrawsample(fd, maxval);
240 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
241 b == PLUGIN_ERROR)
243 return PLUGIN_ERROR;
245 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
246 (255 / maxval) * r,
247 (255 / maxval) * g,
248 (255 / maxval) * b);
250 break;
252 default:
253 ppm_error("What?!");
254 return PLUGIN_ERROR;
256 return 1;
259 int read_ppm(int fd,
260 int * const cols,
261 int * const rows,
262 int * const maxval)
264 int row;
265 int format;
267 read_ppm_init(fd, cols, rows, maxval, &format);
269 if(format == PLUGIN_ERROR) {
270 return PLUGIN_ERROR;
273 for (row = 0; row < *rows; ++row) {
274 if( read_ppm_row(fd, row, *cols, *rows, *maxval, format) == PLUGIN_ERROR) {
275 return PLUGIN_ERROR;
278 return 1;
281 /* this is the plugin entry point */
282 enum plugin_status plugin_start(const void* parameter)
284 static char filename[MAX_PATH];
285 int fd;
287 int cols;
288 int rows;
289 int maxval;
291 int result;
293 struct bitmap small_bitmap, orig_bitmap;
295 if(!parameter) return PLUGIN_ERROR;
297 rb->strcpy(filename, parameter);
299 fd = rb->open(filename, O_RDONLY);
300 if (fd < 0)
302 ppm_error("Couldnt open file: %s, %d", filename, fd);
303 return PLUGIN_ERROR;
306 result = read_ppm(fd, &cols, &rows, &maxval);
308 rb->close(fd);
309 if(result == PLUGIN_ERROR) return PLUGIN_ERROR;
311 orig_bitmap.width = cols;
312 orig_bitmap.height = rows;
313 orig_bitmap.data = (char*)buffer;
315 if (cols > LCD_WIDTH || rows > LCD_HEIGHT)
317 if (cols > LCD_WIDTH) {
318 small_bitmap.width = LCD_WIDTH;
319 small_bitmap.height =
320 (int)(((float)LCD_WIDTH / (float)cols) * (float)rows);
322 } else { /* rows > LCD_HEIGHT */
324 small_bitmap.width =
325 (int)(((float)LCD_HEIGHT / (float)rows) * (float)cols);
326 small_bitmap.height = LCD_HEIGHT;
328 small_bitmap.data = (char*)lcd_buf;
330 smooth_resize_bitmap( &orig_bitmap, &small_bitmap );
332 rb->lcd_bitmap((fb_data*)small_bitmap.data, 0, 0,
333 small_bitmap.width, small_bitmap.height);
334 } else {
335 rb->lcd_bitmap((fb_data*)orig_bitmap.data, 0, 0, cols, rows);
337 rb->lcd_update();
338 rb->button_get(true);
340 return PLUGIN_OK;
343 #endif