Add ppm and rppm viewer by Alexander Papst
[Rockbox.git] / apps / plugins / ppmviewer.c
blob4bb43e50da5cf1921da1fb90265175c4ed598feb
1 /*****************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Alexander Papst
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "plugin.h"
21 #include "bmp.h"
23 #if defined(HAVE_LCD_COLOR)
25 PLUGIN_HEADER
27 /* Magic constants. */
28 #define PPM_MAGIC1 'P'
29 #define PPM_MAGIC2 '3'
30 #define RPPM_MAGIC2 '6'
31 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
32 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
34 #define PPM_OVERALLMAXVAL 65535
35 #define PPM_MAXSIZE (300*1024)/sizeof(fb_data)
37 #define ppm_error(...) rb->splash(HZ*2, __VA_ARGS__ )
39 static fb_data buffer[PPM_MAXSIZE];
40 static fb_data lcd_buf[LCD_WIDTH * LCD_HEIGHT];
42 static const struct plugin_api* rb; /* global api struct pointer */
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 int read_ppm_row(int fd,
197 int const row,
198 int const cols,
199 int const maxval,
200 int const format)
202 int col;
203 int r, g, b;
204 switch (format) {
205 case PPM_FORMAT:
206 for (col = 0; col < cols; ++col) {
207 r = ppm_getuint(fd);
208 g = ppm_getuint(fd);
209 b = ppm_getuint(fd);
211 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
212 b == PLUGIN_ERROR)
214 return PLUGIN_ERROR;
216 buffer[(cols * row) + col] = LCD_RGBPACK(
217 (255 / maxval) * r,
218 (255 / maxval) * g,
219 (255 / maxval) * b);
221 break;
223 case RPPM_FORMAT:
224 for (col = 0; col < cols; ++col) {
225 r = ppm_getrawsample(fd, maxval);
226 g = ppm_getrawsample(fd, maxval);
227 b = ppm_getrawsample(fd, maxval);
229 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
230 b == PLUGIN_ERROR)
232 return PLUGIN_ERROR;
234 buffer[(cols * row) + col] = LCD_RGBPACK(
235 (255 / maxval) * r,
236 (255 / maxval) * g,
237 (255 / maxval) * b);
239 break;
241 default:
242 ppm_error("What?!");
243 return PLUGIN_ERROR;
245 return 1;
248 int read_ppm(int fd,
249 int * const cols,
250 int * const rows,
251 int * const maxval)
253 int row;
254 int format;
256 read_ppm_init(fd, cols, rows, maxval, &format);
258 if(format == PLUGIN_ERROR) {
259 return PLUGIN_ERROR;
262 for (row = 0; row < *rows; ++row) {
263 if( read_ppm_row(fd, row, *cols, *maxval, format) == PLUGIN_ERROR) {
264 return PLUGIN_ERROR;
267 return 1;
270 /* this is the plugin entry point */
271 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
273 static char filename[MAX_PATH];
274 int fd;
276 int cols;
277 int rows;
278 int maxval;
280 int result;
282 struct bitmap small_bitmap, orig_bitmap;
284 if(!parameter) return PLUGIN_ERROR;
286 rb = api;
288 rb->strcpy(filename, parameter);
290 fd = rb->open(filename, O_RDONLY);
291 if (fd < 0)
293 ppm_error("Couldnt open file: %s, %d", filename, fd);
294 return PLUGIN_ERROR;
297 result = read_ppm(fd, &cols, &rows, &maxval);
299 rb->close(fd);
300 if(result == PLUGIN_ERROR) return PLUGIN_ERROR;
302 orig_bitmap.width = cols;
303 orig_bitmap.height = rows;
304 orig_bitmap.data = (char*)buffer;
306 if (cols > LCD_WIDTH || rows > LCD_HEIGHT)
308 if (cols > LCD_WIDTH) {
309 small_bitmap.width = LCD_WIDTH;
310 small_bitmap.height =
311 (int)(((float)LCD_WIDTH / (float)cols) * (float)rows);
313 } else { /* rows > LCD_HEIGHT */
315 small_bitmap.width =
316 (int)(((float)LCD_HEIGHT / (float)rows) * (float)cols);
317 small_bitmap.height = LCD_HEIGHT;
319 small_bitmap.data = (char*)lcd_buf;
321 smooth_resize_bitmap( &orig_bitmap, &small_bitmap );
323 rb->lcd_bitmap((fb_data*)small_bitmap.data, 0, 0,
324 small_bitmap.width, small_bitmap.height);
325 } else {
326 rb->lcd_bitmap((fb_data*)orig_bitmap.data, 0, 0, cols, rows);
328 rb->lcd_update();
329 rb->button_get(true);
331 return PLUGIN_OK;
334 #endif