summaryrefslogtreecommitdiff
path: root/apps/plugins/imageviewer/ppm/ppm_decoder.c
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2011-01-09 13:22:54 +0000
committerMarcin Bukat <marcin.bukat@gmail.com>2011-01-09 13:22:54 +0000
commit6e3da841be4f0c7eda5d0daec19fc4919bd56d9f (patch)
tree05c2b3628720bcf2fd6f181b25771a874628cb38 /apps/plugins/imageviewer/ppm/ppm_decoder.c
parent6d05e27d68ff6a65580e771bccb20e6139ef5d68 (diff)
Rework ppmviewer to fit our shiny new imageviewer framework. FS#11818 by me.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29012 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/imageviewer/ppm/ppm_decoder.c')
-rw-r--r--apps/plugins/imageviewer/ppm/ppm_decoder.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/apps/plugins/imageviewer/ppm/ppm_decoder.c b/apps/plugins/imageviewer/ppm/ppm_decoder.c
new file mode 100644
index 0000000000..44c4f9232e
--- /dev/null
+++ b/apps/plugins/imageviewer/ppm/ppm_decoder.c
@@ -0,0 +1,250 @@
+/*****************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
+ * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2008 Alexander Papst
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "plugin.h"
+#include "lib/pluginlib_bmp.h"
+#include "ppm_decoder.h"
+
+static int ppm_read_magic_number(int fd)
+{
+ char i1, i2;
+ if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1))
+ {
+ ppm_error( "Error reading magic number from ppm image stream. "\
+ "Most often, this means your input file is empty." );
+ return PLUGIN_ERROR;
+ }
+ return i1 * 256 + i2;
+}
+
+static char ppm_getc(int fd)
+{
+ char ch;
+
+ if (!rb->read(fd, &ch, 1)) {
+ ppm_error("EOF. Read error reading a byte");
+ return PLUGIN_ERROR;
+ }
+
+ if (ch == '#') {
+ do {
+ if (!rb->read(fd, &ch, 1)) {
+ ppm_error("EOF. Read error reading a byte");
+ return PLUGIN_ERROR;
+ }
+ } while (ch != '\n' && ch != '\r');
+ }
+ return ch;
+}
+
+static int ppm_getuint(int fd)
+{
+ char ch;
+ int i;
+ int digitVal;
+
+ do {
+ ch = ppm_getc(fd);
+ } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+ if (ch < '0' || ch > '9') {
+ ppm_error("Junk (%c) in file where an integer should be.", ch);
+ return PLUGIN_ERROR;
+ }
+
+ i = 0;
+
+ do {
+ digitVal = ch - '0';
+
+ if (i > INT_MAX/10 - digitVal) {
+ ppm_error("ASCII decimal integer in file is "\
+ "too large to be processed.");
+ return PLUGIN_ERROR;
+ }
+
+ i = i * 10 + digitVal;
+ ch = ppm_getc(fd);
+
+ } while (ch >= '0' && ch <= '9');
+
+ return i;
+}
+
+static int ppm_getrawbyte(int fd)
+{
+ unsigned char by;
+
+ if (!rb->read(fd, &by, 1)) {
+ ppm_error("EOF. Read error while reading a one-byte sample.");
+ return PLUGIN_ERROR;
+ }
+
+ return (int)by;
+}
+
+static int ppm_getrawsample(int fd, int const maxval)
+{
+ if (maxval < 256) {
+ /* The sample is just one byte. Read it. */
+ return(ppm_getrawbyte(fd));
+ } else {
+ /* The sample is two bytes. Read both. */
+ unsigned char byte_pair[2];
+
+ if (!rb->read(fd, byte_pair, 2)) {
+ ppm_error("EOF. Read error while reading a long sample.");
+ return PLUGIN_ERROR;
+ }
+ return((byte_pair[0]<<8) | byte_pair[1]);
+ }
+}
+
+/* Read from the file header dimensions as well as max
+ * int value used
+ */
+static int read_ppm_init_rest(int fd, struct ppm_info *ppm)
+{
+ /* Read size. */
+ ppm->x = ppm_getuint(fd);
+ ppm->y = ppm_getuint(fd);
+
+#ifdef HAVE_LCD_COLOR
+ ppm->native_img_size = ppm->x * ppm->y * FB_DATA_SZ;
+#endif
+
+ if (ppm->native_img_size > ppm->buf_size) {
+ ppm_error("Imagesize (%ld pixels) is too large. "\
+ "The maximum allowed is %ld.",
+ (long)ppm->native_img_size,
+ (long)ppm->buf_size);
+ return PLUGIN_ERROR;
+ }
+
+ /* Read maxval. */
+ ppm->maxval = ppm_getuint(fd);
+
+ if (ppm->maxval > PPM_OVERALLMAXVAL) {
+ ppm_error("maxval of input image (%u) is too large. "\
+ "The maximum allowed by the PPM is %u.",
+ ppm->maxval, PPM_OVERALLMAXVAL);
+ return PLUGIN_ERROR;
+ }
+ if (ppm->maxval == 0) {
+ ppm_error("maxval of input image is zero.");
+ return PLUGIN_ERROR;
+ }
+ return 1;
+}
+
+static void read_ppm_init(int fd, struct ppm_info *ppm)
+{
+ /* Check magic number. */
+ ppm->format = ppm_read_magic_number( fd );
+
+ if (ppm->format == PLUGIN_ERROR) return;
+ switch (ppm->format) {
+ case PPM_FORMAT:
+ case RPPM_FORMAT:
+ if(read_ppm_init_rest(fd, ppm) == PLUGIN_ERROR) {
+ ppm->format = PLUGIN_ERROR;
+ }
+ break;
+
+ default:
+ ppm_error( "Bad magic number - not a ppm or rppm file." );
+ ppm->format = PLUGIN_ERROR;
+ }
+}
+
+#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
+#define BUFADDR(x, y, width, height) ( ppm->buf + (height*(x) + (y))*FB_DATA_SZ)
+#else
+#define BUFADDR(x, y, width, height) ( ppm->buf + (width*(y) + (x))*FB_DATA_SZ)
+#endif
+
+static int read_ppm_row(int fd, struct ppm_info *ppm, int row)
+{
+
+ int col;
+ int r, g, b;
+ switch (ppm->format) {
+ case PPM_FORMAT:
+ for (col = 0; col < ppm->x; ++col) {
+ r = ppm_getuint(fd);
+ g = ppm_getuint(fd);
+ b = ppm_getuint(fd);
+
+ if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
+ b == PLUGIN_ERROR)
+ {
+ return PLUGIN_ERROR;
+ }
+ *(fb_data *)BUFADDR(col, row, ppm->x, ppm->y) = LCD_RGBPACK(
+ (255 * r)/ppm->maxval,
+ (255 * g)/ppm->maxval,
+ (255 * b)/ppm->maxval);
+ }
+ break;
+
+ case RPPM_FORMAT:
+ for (col = 0; col < ppm->x; ++col) {
+ r = ppm_getrawsample(fd, ppm->maxval);
+ g = ppm_getrawsample(fd, ppm->maxval);
+ b = ppm_getrawsample(fd, ppm->maxval);
+
+ if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
+ b == PLUGIN_ERROR)
+ {
+ return PLUGIN_ERROR;
+ }
+ *(fb_data *)BUFADDR(col, row, ppm->x, ppm->y) = LCD_RGBPACK(
+ (255 * r)/ppm->maxval,
+ (255 * g)/ppm->maxval,
+ (255 * b)/ppm->maxval);
+ }
+ break;
+
+ default:
+ ppm_error("What?!");
+ return PLUGIN_ERROR;
+ }
+ return 1;
+}
+
+/* public */
+int read_ppm(int fd, struct ppm_info *ppm)
+{
+ int row;
+
+ read_ppm_init(fd, ppm);
+
+ if(ppm->format == PLUGIN_ERROR) {
+ return PLUGIN_ERROR;
+ }
+
+ for (row = 0; row < ppm->y; ++row) {
+ if( read_ppm_row(fd, ppm, row) == PLUGIN_ERROR) {
+ return PLUGIN_ERROR;
+ }
+ }
+ return 1;
+}