1 /*****************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "lib/pluginlib_bmp.h"
25 /* Magic constants. */
26 #define PPM_MAGIC1 'P'
27 #define PPM_MAGIC2 '3'
28 #define RPPM_MAGIC2 '6'
29 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
30 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
32 #define PPM_OVERALLMAXVAL 65535
33 #define PPM_MAXSIZE (300*1024)/sizeof(fb_data)
35 #define ppm_error(...) rb->splashf(HZ*2, __VA_ARGS__ )
37 static fb_data
*buffer
, *lcd_buf
;
39 int ppm_read_magic_number(int fd
)
42 if(!rb
->read(fd
, &i1
, 1) || !rb
->read(fd
, &i2
, 1))
44 ppm_error( "Error reading magic number from ppm image stream. "\
45 "Most often, this means your input file is empty." );
55 if (!rb
->read(fd
, &ch
, 1)) {
56 ppm_error("EOF. Read error reading a byte");
62 if (!rb
->read(fd
, &ch
, 1)) {
63 ppm_error("EOF. Read error reading a byte");
66 } while (ch
!= '\n' && ch
!= '\r');
71 int ppm_getuint(int fd
)
79 } while (ch
== ' ' || ch
== '\t' || ch
== '\n' || ch
== '\r');
81 if (ch
< '0' || ch
> '9') {
82 ppm_error("Junk (%c) in file where an integer should be.", ch
);
91 if (i
> INT_MAX
/10 - digitVal
) {
92 ppm_error("ASCII decimal integer in file is "\
93 "too large to be processed.");
97 i
= i
* 10 + digitVal
;
100 } while (ch
>= '0' && ch
<= '9');
105 int ppm_getrawbyte(int fd
)
109 if (!rb
->read(fd
, &by
, 1)) {
110 ppm_error("EOF. Read error while reading a one-byte sample.");
117 int ppm_getrawsample(int fd
, int const maxval
)
120 /* The sample is just one byte. Read it. */
121 return(ppm_getrawbyte(fd
));
123 /* The sample is two bytes. Read both. */
124 unsigned char byte_pair
[2];
126 if (!rb
->read(fd
, byte_pair
, 2)) {
127 ppm_error("EOF. Read error while reading a long sample.");
130 return((byte_pair
[0]<<8) | byte_pair
[1]);
134 int read_ppm_init_rest(int fd
,
140 *cols
= ppm_getuint(fd
);
141 *rows
= ppm_getuint(fd
);
143 if ((long unsigned int)(*cols
* *rows
) > PPM_MAXSIZE
) {
144 ppm_error("Imagesize (%ld pixels) is too large. "\
145 "The maximum allowed is %ld.",
146 (long unsigned int)(*cols
* *rows
),
147 (long unsigned int)PPM_MAXSIZE
);
152 *maxval
= ppm_getuint(fd
);
154 if (*maxval
> PPM_OVERALLMAXVAL
) {
155 ppm_error("maxval of input image (%u) is too large. "\
156 "The maximum allowed by the PPM is %u.",
157 *maxval
, PPM_OVERALLMAXVAL
);
161 ppm_error("maxval of input image is zero.");
167 void read_ppm_init(int fd
,
173 /* Check magic number. */
174 *format
= ppm_read_magic_number( fd
);
176 if (*format
== PLUGIN_ERROR
) return;
180 if(read_ppm_init_rest(fd
, cols
, rows
, maxval
) == PLUGIN_ERROR
) {
181 *format
= PLUGIN_ERROR
;
186 ppm_error( "Bad magic number - not a ppm or rppm file." );
187 *format
= PLUGIN_ERROR
;
191 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
192 #define BUFADDR(x, y, width, height) ( buffer + height*(x) + (y))
194 #define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x))
197 int read_ppm_row(int fd
,
204 #if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE)
212 for (col
= 0; col
< cols
; ++col
) {
217 if (r
== PLUGIN_ERROR
|| g
== PLUGIN_ERROR
||
222 *BUFADDR(col
, row
, cols
, rows
) = LCD_RGBPACK(
230 for (col
= 0; col
< cols
; ++col
) {
231 r
= ppm_getrawsample(fd
, maxval
);
232 g
= ppm_getrawsample(fd
, maxval
);
233 b
= ppm_getrawsample(fd
, maxval
);
235 if (r
== PLUGIN_ERROR
|| g
== PLUGIN_ERROR
||
240 *BUFADDR(col
, row
, cols
, rows
) = LCD_RGBPACK(
262 read_ppm_init(fd
, cols
, rows
, maxval
, &format
);
264 if(format
== PLUGIN_ERROR
) {
268 for (row
= 0; row
< *rows
; ++row
) {
269 if( read_ppm_row(fd
, row
, *cols
, *rows
, *maxval
, format
) == PLUGIN_ERROR
) {
276 /* this is the plugin entry point */
277 enum plugin_status
plugin_start(const void* parameter
)
279 static char filename
[MAX_PATH
];
288 struct bitmap small_bitmap
, orig_bitmap
;
290 if(!parameter
) return PLUGIN_ERROR
;
293 char *audiobuf
= rb
->plugin_get_buffer(&buffer_size
);
294 if (buffer_size
< PPM_MAXSIZE
+ LCD_WIDTH
* LCD_HEIGHT
+ 1)
296 /* steal from audiobuffer if plugin buffer is too small */
297 audiobuf
= rb
->plugin_get_audio_buffer(&buffer_size
);
299 if (buffer_size
< PPM_MAXSIZE
+ LCD_WIDTH
* LCD_HEIGHT
+ 1)
301 rb
->splash(HZ
, "Not enough memory");
306 /* align on 16 bits */
307 audiobuf
= (char *)(((uintptr_t)audiobuf
+ 1) & ~1);
308 buffer
= (fb_data
*)audiobuf
;
309 lcd_buf
= (fb_data
*) (audiobuf
+ PPM_MAXSIZE
);
311 rb
->strcpy(filename
, parameter
);
313 fd
= rb
->open(filename
, O_RDONLY
);
316 ppm_error("Couldnt open file: %s, %d", filename
, fd
);
320 result
= read_ppm(fd
, &cols
, &rows
, &maxval
);
323 if(result
== PLUGIN_ERROR
) return PLUGIN_ERROR
;
325 orig_bitmap
.width
= cols
;
326 orig_bitmap
.height
= rows
;
327 orig_bitmap
.data
= (char*)buffer
;
329 if (cols
> LCD_WIDTH
|| rows
> LCD_HEIGHT
)
331 if (cols
> LCD_WIDTH
) {
332 small_bitmap
.width
= LCD_WIDTH
;
333 small_bitmap
.height
=
334 (int)(((float)LCD_WIDTH
/ (float)cols
) * (float)rows
);
336 } else { /* rows > LCD_HEIGHT */
339 (int)(((float)LCD_HEIGHT
/ (float)rows
) * (float)cols
);
340 small_bitmap
.height
= LCD_HEIGHT
;
342 small_bitmap
.data
= (char*)lcd_buf
;
344 smooth_resize_bitmap( &orig_bitmap
, &small_bitmap
);
346 rb
->lcd_bitmap((fb_data
*)small_bitmap
.data
, 0, 0,
347 small_bitmap
.width
, small_bitmap
.height
);
349 rb
->lcd_bitmap((fb_data
*)orig_bitmap
.data
, 0, 0, cols
, rows
);
352 rb
->button_get(true);