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 #if defined(HAVE_LCD_COLOR)
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
)
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." );
59 if (!rb
->read(fd
, &ch
, 1)) {
60 ppm_error("EOF. Read error reading a byte");
66 if (!rb
->read(fd
, &ch
, 1)) {
67 ppm_error("EOF. Read error reading a byte");
70 } while (ch
!= '\n' && ch
!= '\r');
75 int ppm_getuint(int 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
);
95 if (i
> INT_MAX
/10 - digitVal
) {
96 ppm_error("ASCII decimal integer in file is "\
97 "too large to be processed.");
101 i
= i
* 10 + digitVal
;
104 } while (ch
>= '0' && ch
<= '9');
109 int ppm_getrawbyte(int fd
)
113 if (!rb
->read(fd
, &by
, 1)) {
114 ppm_error("EOF. Read error while reading a one-byte sample.");
121 int ppm_getrawsample(int fd
, int const maxval
)
124 /* The sample is just one byte. Read it. */
125 return(ppm_getrawbyte(fd
));
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.");
134 return((byte_pair
[0]<<8) | byte_pair
[1]);
138 int read_ppm_init_rest(int fd
,
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
);
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
);
165 ppm_error("maxval of input image is zero.");
171 void read_ppm_init(int fd
,
177 /* Check magic number. */
178 *format
= ppm_read_magic_number( fd
);
180 if (*format
== PLUGIN_ERROR
) return;
184 if(read_ppm_init_rest(fd
, cols
, rows
, maxval
) == PLUGIN_ERROR
) {
185 *format
= PLUGIN_ERROR
;
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))
198 #define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x))
201 int read_ppm_row(int fd
,
208 #if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE)
216 for (col
= 0; col
< cols
; ++col
) {
221 if (r
== PLUGIN_ERROR
|| g
== PLUGIN_ERROR
||
226 *BUFADDR(col
, row
, cols
, rows
) = LCD_RGBPACK(
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
||
244 *BUFADDR(col
, row
, cols
, rows
) = LCD_RGBPACK(
266 read_ppm_init(fd
, cols
, rows
, maxval
, &format
);
268 if(format
== PLUGIN_ERROR
) {
272 for (row
= 0; row
< *rows
; ++row
) {
273 if( read_ppm_row(fd
, row
, *cols
, *rows
, *maxval
, format
) == PLUGIN_ERROR
) {
280 /* this is the plugin entry point */
281 enum plugin_status
plugin_start(const void* parameter
)
283 static char filename
[MAX_PATH
];
292 struct bitmap small_bitmap
, orig_bitmap
;
294 if(!parameter
) return PLUGIN_ERROR
;
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");
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
);
320 ppm_error("Couldnt open file: %s, %d", filename
, fd
);
324 result
= read_ppm(fd
, &cols
, &rows
, &maxval
);
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 */
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
);
353 rb
->lcd_bitmap((fb_data
*)orig_bitmap
.data
, 0, 0, cols
, rows
);
356 rb
->button_get(true);