ppmviewer/rockpaint: do not steal the audiobuffer (and stop playback) if the plugin...
[kugel-rb.git] / apps / plugins / ppmviewer.c
blobc947af10bd071c812bfdccc307e3f1419720312d
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, *lcd_buf;
43 int ppm_read_magic_number(int fd)
45 char i1, i2;
46 if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1))
48 ppm_error( "Error reading magic number from ppm image stream. "\
49 "Most often, this means your input file is empty." );
50 return PLUGIN_ERROR;
52 return i1 * 256 + i2;
55 char ppm_getc(int fd)
57 char ch;
59 if (!rb->read(fd, &ch, 1)) {
60 ppm_error("EOF. Read error reading a byte");
61 return PLUGIN_ERROR;
64 if (ch == '#') {
65 do {
66 if (!rb->read(fd, &ch, 1)) {
67 ppm_error("EOF. Read error reading a byte");
68 return PLUGIN_ERROR;
70 } while (ch != '\n' && ch != '\r');
72 return ch;
75 int ppm_getuint(int fd)
77 char ch;
78 int i;
79 int digitVal;
81 do {
82 ch = ppm_getc(fd);
83 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
85 if (ch < '0' || ch > '9') {
86 ppm_error("Junk (%c) in file where an integer should be.", ch);
87 return PLUGIN_ERROR;
90 i = 0;
92 do {
93 digitVal = ch - '0';
95 if (i > INT_MAX/10 - digitVal) {
96 ppm_error("ASCII decimal integer in file is "\
97 "too large to be processed.");
98 return PLUGIN_ERROR;
101 i = i * 10 + digitVal;
102 ch = ppm_getc(fd);
104 } while (ch >= '0' && ch <= '9');
106 return i;
109 int ppm_getrawbyte(int fd)
111 unsigned char by;
113 if (!rb->read(fd, &by, 1)) {
114 ppm_error("EOF. Read error while reading a one-byte sample.");
115 return PLUGIN_ERROR;
118 return (int)by;
121 int ppm_getrawsample(int fd, int const maxval)
123 if (maxval < 256) {
124 /* The sample is just one byte. Read it. */
125 return(ppm_getrawbyte(fd));
126 } else {
127 /* The sample is two bytes. Read both. */
128 unsigned char byte_pair[2];
130 if (!rb->read(fd, byte_pair, 2)) {
131 ppm_error("EOF. Read error while reading a long sample.");
132 return PLUGIN_ERROR;
134 return((byte_pair[0]<<8) | byte_pair[1]);
138 int read_ppm_init_rest(int fd,
139 int * const cols,
140 int * const rows,
141 int * const maxval)
143 /* Read size. */
144 *cols = ppm_getuint(fd);
145 *rows = ppm_getuint(fd);
147 if ((long unsigned int)(*cols * *rows) > PPM_MAXSIZE) {
148 ppm_error("Imagesize (%ld pixels) is too large. "\
149 "The maximum allowed is %ld.",
150 (long unsigned int)(*cols * *rows),
151 (long unsigned int)PPM_MAXSIZE);
152 return PLUGIN_ERROR;
155 /* Read maxval. */
156 *maxval = ppm_getuint(fd);
158 if (*maxval > PPM_OVERALLMAXVAL) {
159 ppm_error("maxval of input image (%u) is too large. "\
160 "The maximum allowed by the PPM is %u.",
161 *maxval, PPM_OVERALLMAXVAL);
162 return PLUGIN_ERROR;
164 if (*maxval == 0) {
165 ppm_error("maxval of input image is zero.");
166 return PLUGIN_ERROR;
168 return 1;
171 void read_ppm_init(int fd,
172 int * const cols,
173 int * const rows,
174 int * const maxval,
175 int * const format)
177 /* Check magic number. */
178 *format = ppm_read_magic_number( fd );
180 if (*format == PLUGIN_ERROR) return;
181 switch (*format) {
182 case PPM_FORMAT:
183 case RPPM_FORMAT:
184 if(read_ppm_init_rest(fd, cols, rows, maxval) == PLUGIN_ERROR) {
185 *format = PLUGIN_ERROR;
187 break;
189 default:
190 ppm_error( "Bad magic number - not a ppm or rppm file." );
191 *format = PLUGIN_ERROR;
195 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
196 #define BUFADDR(x, y, width, height) ( buffer + height*(x) + (y))
197 #else
198 #define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x))
199 #endif
201 int read_ppm_row(int fd,
202 int const row,
203 int const cols,
204 int const rows,
205 int const maxval,
206 int const format)
208 #if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE)
209 (void) rows;
210 #endif
212 int col;
213 int r, g, b;
214 switch (format) {
215 case PPM_FORMAT:
216 for (col = 0; col < cols; ++col) {
217 r = ppm_getuint(fd);
218 g = ppm_getuint(fd);
219 b = ppm_getuint(fd);
221 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
222 b == PLUGIN_ERROR)
224 return PLUGIN_ERROR;
226 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
227 (255 / maxval) * r,
228 (255 / maxval) * g,
229 (255 / maxval) * b);
231 break;
233 case RPPM_FORMAT:
234 for (col = 0; col < cols; ++col) {
235 r = ppm_getrawsample(fd, maxval);
236 g = ppm_getrawsample(fd, maxval);
237 b = ppm_getrawsample(fd, maxval);
239 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
240 b == PLUGIN_ERROR)
242 return PLUGIN_ERROR;
244 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
245 (255 / maxval) * r,
246 (255 / maxval) * g,
247 (255 / maxval) * b);
249 break;
251 default:
252 ppm_error("What?!");
253 return PLUGIN_ERROR;
255 return 1;
258 int read_ppm(int fd,
259 int * const cols,
260 int * const rows,
261 int * const maxval)
263 int row;
264 int format;
266 read_ppm_init(fd, cols, rows, maxval, &format);
268 if(format == PLUGIN_ERROR) {
269 return PLUGIN_ERROR;
272 for (row = 0; row < *rows; ++row) {
273 if( read_ppm_row(fd, row, *cols, *rows, *maxval, format) == PLUGIN_ERROR) {
274 return PLUGIN_ERROR;
277 return 1;
280 /* this is the plugin entry point */
281 enum plugin_status plugin_start(const void* parameter)
283 static char filename[MAX_PATH];
284 int fd;
286 int cols;
287 int rows;
288 int maxval;
290 int result;
292 struct bitmap small_bitmap, orig_bitmap;
294 if(!parameter) return PLUGIN_ERROR;
296 size_t buffer_size;
297 char *audiobuf = rb->plugin_get_buffer(&buffer_size);
298 if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1)
300 /* steal from audiobuffer if plugin buffer is too small */
301 audiobuf = rb->plugin_get_audio_buffer(&buffer_size);
303 if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1)
305 rb->splash(HZ, "Not enough memory");
306 return PLUGIN_ERROR;
310 /* align on 16 bits */
311 audiobuf = (char *)(((uintptr_t)audiobuf + 1) & ~1);
312 buffer = (fb_data *)audiobuf;
313 lcd_buf = (fb_data*) (audiobuf + PPM_MAXSIZE);
315 rb->strcpy(filename, parameter);
317 fd = rb->open(filename, O_RDONLY);
318 if (fd < 0)
320 ppm_error("Couldnt open file: %s, %d", filename, fd);
321 return PLUGIN_ERROR;
324 result = read_ppm(fd, &cols, &rows, &maxval);
326 rb->close(fd);
327 if(result == PLUGIN_ERROR) return PLUGIN_ERROR;
329 orig_bitmap.width = cols;
330 orig_bitmap.height = rows;
331 orig_bitmap.data = (char*)buffer;
333 if (cols > LCD_WIDTH || rows > LCD_HEIGHT)
335 if (cols > LCD_WIDTH) {
336 small_bitmap.width = LCD_WIDTH;
337 small_bitmap.height =
338 (int)(((float)LCD_WIDTH / (float)cols) * (float)rows);
340 } else { /* rows > LCD_HEIGHT */
342 small_bitmap.width =
343 (int)(((float)LCD_HEIGHT / (float)rows) * (float)cols);
344 small_bitmap.height = LCD_HEIGHT;
346 small_bitmap.data = (char*)lcd_buf;
348 smooth_resize_bitmap( &orig_bitmap, &small_bitmap );
350 rb->lcd_bitmap((fb_data*)small_bitmap.data, 0, 0,
351 small_bitmap.width, small_bitmap.height);
352 } else {
353 rb->lcd_bitmap((fb_data*)orig_bitmap.data, 0, 0, cols, rows);
355 rb->lcd_update();
356 rb->button_get(true);
358 return PLUGIN_OK;
361 #endif