diff options
author | Havoc Pennington <hp@redhat.com> | 2000-10-09 17:22:20 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2000-10-09 17:22:20 +0000 |
commit | 518f32d97e0e097c10a99d65da8e0e215c796c3a (patch) | |
tree | 3bdd86d81f59adff2ac1c3dff7bc19672ea9e23f /gdk-pixbuf/io-pnm.c | |
parent | 25840ef4a566630948e838ec69bccd392befca9e (diff) | |
download | gtk+-518f32d97e0e097c10a99d65da8e0e215c796c3a.tar.gz |
contrib subdir
2000-10-06 Havoc Pennington <hp@redhat.com>
* Makefile.am (SRC_SUBDIRS): contrib subdir
* gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
so it can be used in Xlib version
* demos/testpixbuf.c (update_timeout): error checking from 1.0
tree
* gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
change from 1.0 tree that returns first frame of animation
if the loaded file is an animation.
* contrib: add new directory to hold stuff that comes with GTK+
but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
* configure.in: add contrib/*
2000-10-06 Havoc Pennington <hp@redhat.com>
* gdk-pixbuf.h: add GdkPixbufAlphaMode
2000-10-06 Havoc Pennington <hp@redhat.com>
This entry is a summary of the merged-in changes from 1.0.
Relevant original ChangeLog entries are spliced in after
this entry; the files they refer to are from the 1.0
gdk-pixbuf sources.
* pixops/pixops.c (pixops_composite_nearest): sync a small fix
from 1.0
* io-xpm.c (xpm_seek_string): add fscanf error check from 1.0
Add progressive loader from 1.0
* io-tiff.c (gdk_pixbuf__tiff_image_begin_load): mem leak fixes
from 1.0 tree
* io-pnm.c: new version from 1.0 tree
* io-jpeg.c (gdk_pixbuf__jpeg_image_load): sync from 1.0, use
malloc not g_malloc
* io-gif.c (lzw_read_byte): sync from 1.0, change a g_error to
g_warning
(gif_get_next_step): return 0 here, sync from 1.0
* gdk-pixbuf-util.c: sync email address change for Cody
Russell
2000-09-11 Jeffrey Stedfast <fejj@helixcode.com>
* gdk-pixbuf/io-pnm.c: Pretty much totally rewrote again because
last nights code was still "broken". Should now properly handle
all error conditions gracefully.
2000-09-10 Jeffrey Stedfast <fejj@helixcode.com>
* gdk-pixbuf/io-pnm.c: Rewrote.
2000-09-09 Federico Mena Quintero <federico@helixcode.com>
* gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): Compute
the correct dest offset.
2000-08-25 Federico Mena Quintero <federico@helixcode.com>
* gdk-pixbuf/io-xpm.c: #include <unistd.h>
2000-08-05 Larry Ewing <lewing@helixcode.com>
* gdk-pixbuf/io-tiff.c: stop leaking context->tempname.
* gdk-pixbuf/io-xpm.c: same as above.
2000-07-26 Michael Meeks <michael@helixcode.com>
* gdk-pixbuf/io-jpeg.c (gdk_pixbuf__jpeg_image_load): make
g_malloc a malloc.
2000-07-21 Larry Ewing <lewing@helixcode.com>
* gdk-pixbuf/io-xpm.c: add a fake progressive loader so that
xpm at least supports the progressive interface like the one in
io-tiff.c. This should be reimplemented as an actual progressive
loader.
2000-07-19 Jonathan Blandford <jrb@redhat.com>
* demo/pixbuf-demo.c (update_timeout): changed scaling level to
make it look better.
* gdk-pixbuf/testpixbuf.c (update_timeout): Patch from michael
meeks to handle errors better.
Diffstat (limited to 'gdk-pixbuf/io-pnm.c')
-rw-r--r-- | gdk-pixbuf/io-pnm.c | 817 |
1 files changed, 415 insertions, 402 deletions
diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c index aa1b193916..c91658cfd4 100644 --- a/gdk-pixbuf/io-pnm.c +++ b/gdk-pixbuf/io-pnm.c @@ -1,20 +1,22 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* GdkPixbuf library - PNM image loader * * Copyright (C) 1999 Red Hat, Inc. * - * Authors: Michael Fulbright <drmike@redhat.com> + * Authors: Jeffrey Stedfast <fejj@helixcode.com> + * Michael Fulbright <drmike@redhat.com> * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * Library General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public + * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. @@ -29,16 +31,15 @@ #include "gdk-pixbuf-private.h" #include "gdk-pixbuf-io.h" - #define PNM_BUF_SIZE 4096 -#define PNM_SUSPEND 0 -#define PNM_OK 1 #define PNM_FATAL_ERR -1 +#define PNM_SUSPEND 0 +#define PNM_OK 1 typedef enum { - PNM_FORMAT_PGM, + PNM_FORMAT_PGM = 1, PNM_FORMAT_PGM_RAW, PNM_FORMAT_PPM, PNM_FORMAT_PPM_RAW, @@ -47,51 +48,54 @@ typedef enum { } PnmFormat; typedef struct { - guchar buffer[PNM_BUF_SIZE]; - guchar *next_byte; - guint bytes_left; + guchar buffer[PNM_BUF_SIZE]; + guchar *byte; + guint nbytes; } PnmIOBuffer; typedef struct { - ModuleUpdatedNotifyFunc updated_func; + ModuleUpdatedNotifyFunc updated_func; ModulePreparedNotifyFunc prepared_func; - gpointer user_data; + gpointer user_data; + + GdkPixbuf *pixbuf; + guchar *pixels; /* incoming pixel data buffer */ + guchar *dptr; /* current position in pixbuf */ + + PnmIOBuffer inbuf; + + guint width; + guint height; + guint maxval; + guint rowstride; + PnmFormat type; + + guint output_row; /* last row to be completed */ + guint output_col; + gboolean did_prescan; /* are we in image data yet? */ + gboolean got_header; /* have we loaded pnm header? */ + + guint scan_state; - GdkPixbuf *pixbuf; - guchar *pixels; /* incoming pixel data buffer */ - guchar *dptr; /* current position in pixbuf */ - - PnmIOBuffer inbuf; - - guint width; - guint height; - guint maxval; - guint rowstride; - PnmFormat type; - - guint output_row; /* last row to be completed */ - guint output_col; - gboolean did_prescan; /* are we in image data yet? */ - gboolean got_header; /* have we loaded jpeg header? */ } PnmLoaderContext; -GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f); -gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func, - ModuleUpdatedNotifyFunc func2, - ModuleFrameDoneNotifyFunc frame_done_func, - ModuleAnimationDoneNotifyFunc anim_done_func, - gpointer user_data); -void gdk_pixbuf__pnm_image_stop_load (gpointer context); -gboolean gdk_pixbuf__pnm_image_load_increment(gpointer context, guchar *buf, guint size); +GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f); +gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func, + ModuleUpdatedNotifyFunc func2, + ModuleFrameDoneNotifyFunc frame_done_func, + ModuleAnimationDoneNotifyFunc anim_done_func, + gpointer user_data); +void gdk_pixbuf__pnm_image_stop_load (gpointer context); +gboolean gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size); -static void explode_bitmap_into_buf (PnmLoaderContext *context); -static void explode_gray_into_buf (PnmLoaderContext *context); +static void explode_bitmap_into_buf (PnmLoaderContext *context); +static void explode_gray_into_buf (PnmLoaderContext *context); /* Destroy notification function for the pixbuf */ static void free_buffer (guchar *pixels, gpointer data) { - free (pixels); + g_free (pixels); } @@ -108,33 +112,32 @@ explode_bitmap_into_buf (PnmLoaderContext *context) gint bit; guchar *dptr; gint wid, x, y; - + g_return_if_fail (context != NULL); g_return_if_fail (context->dptr != NULL); - + /* I'm no clever bit-hacker so I'm sure this can be optimized */ dptr = context->dptr; y = context->output_row; wid = context->width; - - from = dptr + (wid - 1)/8; + + from = dptr + ((wid - 1) / 8); to = dptr + (wid - 1) * 3; /* bit = 7 - (((y+1)*wid-1) % 8); */ - bit = 7 - ((wid-1) % 8); - + bit = 7 - ((wid-1) % 8); + /* get first byte and align properly */ data = from[0]; for (j = 0; j < bit; j++, data >>= 1); - + for (x = wid-1; x >= 0; x--) { - /* g_print ("%c", (data & 1) ? '*' : ' '); */ - - to[0] = to[1] = to[2] = (data & 1) ? 0x00 : 0xff; - + + to[0] = to[1] = to[2] = (data & 0x01) ? 0x00 : 0xff; + to -= 3; bit++; - + if (bit > 7) { from--; data = from[0]; @@ -143,7 +146,7 @@ explode_bitmap_into_buf (PnmLoaderContext *context) data >>= 1; } } - + /* g_print ("\n"); */ } @@ -154,10 +157,10 @@ explode_gray_into_buf (PnmLoaderContext *context) gint j; guchar *from, *to; guint w; - + g_return_if_fail (context != NULL); g_return_if_fail (context->dptr != NULL); - + /* Expand grey->colour. Expand from the end of the * memory down, so we can use the same buffer. */ @@ -173,221 +176,203 @@ explode_gray_into_buf (PnmLoaderContext *context) } } -/* skip over whitespace in file from current pos. */ -/* also skips comments */ -/* returns pointer to first non-whitespace char hit or, or NULL if */ -/* we ran out of data w/o hitting a whitespace */ -/* internal pointer in inbuf isnt moved ahead in this case */ -static guchar * -skip_ahead_whitespace (PnmIOBuffer *inbuf) -{ - gboolean in_comment; - guchar *ptr; - guint num_left; - - g_return_val_if_fail (inbuf != NULL, NULL); - g_return_val_if_fail (inbuf->next_byte != NULL, NULL); - - in_comment = FALSE; - num_left = inbuf->bytes_left; - ptr = inbuf->next_byte; - while (num_left > 0) { - if (in_comment) { - if (*ptr == '\n') - in_comment = FALSE; - } else if (*ptr == '#') { - in_comment = TRUE; - } else if (!isspace (*ptr)) { - inbuf->bytes_left -= (ptr-inbuf->next_byte); - inbuf->next_byte = ptr; - return ptr; - } - ptr ++; - num_left--; - } - return NULL; -} - -/* reads into buffer until we hit whitespace in file from current pos, */ -/* return NULL if ran out of data */ -/* advances inbuf if successful */ -static guchar * -read_til_whitespace (PnmIOBuffer *inbuf, guchar *buf, guint size) +/* skip over whitespace and comments in input buffer */ +static gint +pnm_skip_whitespace (PnmIOBuffer *inbuf) { - guchar *p; - guchar *ptr; - guint num_left; - - g_return_val_if_fail (inbuf != NULL, NULL); - g_return_val_if_fail (inbuf->next_byte != NULL, NULL); - - p = buf; - num_left = inbuf->bytes_left; - ptr = inbuf->next_byte; - while (num_left > 0 && (p-buf)+1 < size) { - if (isspace (*ptr)) { - *p = '\0'; - inbuf->bytes_left = num_left; - inbuf->next_byte = ptr; - return ptr; - } else { - *p = *ptr; - p++; - ptr++; - num_left--; + register guchar *inptr; + guchar *inend; + + g_return_val_if_fail (inbuf != NULL, PNM_FATAL_ERR); + g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR); + + inend = inbuf->byte + inbuf->nbytes; + inptr = inbuf->byte; + + for ( ; inptr < inend; inptr++) { + if (*inptr == '#') { + /* in comment - skip to the end of this line */ + for ( ; *inptr != '\n' && inptr < inend; inptr++); + } else if (!isspace (*inptr)) { + inbuf->byte = inptr; + inbuf->nbytes = (guint) (inend - inptr); + return PNM_OK; } } - return NULL; + + inbuf->byte = inptr; + inbuf->nbytes = (guint) (inend - inptr); + + return PNM_SUSPEND; } -/* read next number from buffer */ -/* -1 if failed, 0 if successful */ +/* read next number from buffer */ static gint -read_next_number (PnmIOBuffer *inbuf, guint *value) +pnm_read_next_value (PnmIOBuffer *inbuf, guint *value) { - guchar *tmpptr; - guchar *old_next_byte; - gchar *errptr; - guint old_bytes_left; - guchar buf[128]; - - g_return_val_if_fail (inbuf != NULL, -1); - g_return_val_if_fail (inbuf->next_byte != NULL, -1); - g_return_val_if_fail (value != NULL, -1); - - old_next_byte = inbuf->next_byte; - old_bytes_left = inbuf->bytes_left; - - if ((tmpptr = skip_ahead_whitespace (inbuf)) == NULL) - return -1; - - if ((tmpptr = read_til_whitespace (inbuf, buf, 128)) == NULL) { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return -1; - } + register guchar *inptr, *word, *p; + guchar *inend, buf[128]; + gchar *endptr; + gint retval; - *value = strtol (buf, &errptr, 10); - - if (*errptr != '\0') { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return -1; - } - - return 0; + g_return_val_if_fail (inbuf != NULL, PNM_FATAL_ERR); + g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR); + g_return_val_if_fail (value != NULL, PNM_FATAL_ERR); + + /* skip white space */ + if ((retval = pnm_skip_whitespace (inbuf)) != PNM_OK) + return retval; + + inend = inbuf->byte + inbuf->nbytes; + inptr = inbuf->byte; + + /* copy this pnm 'word' into a temp buffer */ + for (p = inptr, word = buf; (p < inend) && !isspace (*p) && (p - inptr < 128); p++, word++) + *word = *p; + *word = '\0'; + + /* hmmm, there must be more data to this 'word' */ + if (!isspace (*p)) + return PNM_SUSPEND; + + /* get the value */ + *value = strtol (buf, &endptr, 10); + if (*endptr != '\0') + return PNM_FATAL_ERR; + + inbuf->byte = p; + inbuf->nbytes = (guint) (inend - p); + + return PNM_OK; } /* returns PNM_OK, PNM_SUSPEND, or PNM_FATAL_ERR */ static gint pnm_read_header (PnmLoaderContext *context) { - guchar *old_next_byte; - guint old_bytes_left; PnmIOBuffer *inbuf; - guint w, h; - gint rc; - PnmFormat type; - - g_return_val_if_fail (context != NULL, PNM_FATAL_ERR); - - inbuf = &context->inbuf; - old_bytes_left = inbuf->bytes_left; - old_next_byte = inbuf->next_byte; + gint retval; - /* file must start with a 'P' followed by a numeral */ - /* so loop till we get enough data to determine type*/ - if (inbuf->bytes_left < 2) - return PNM_SUSPEND; + g_return_val_if_fail (context != NULL, PNM_FATAL_ERR); - if (*inbuf->next_byte != 'P') - return PNM_FATAL_ERR; + inbuf = &context->inbuf; - switch (*(inbuf->next_byte+1)) { - case '1': - type = PNM_FORMAT_PBM; - break; - case '2': - type = PNM_FORMAT_PGM; - break; - case '3': - type = PNM_FORMAT_PPM; - break; - case '4': - type = PNM_FORMAT_PBM_RAW; - break; - case '5': - type = PNM_FORMAT_PGM_RAW; - break; - case '6': - type = PNM_FORMAT_PPM_RAW; - break; - default: - return PNM_FATAL_ERR; + if (!context->type) { + /* file must start with a 'P' followed by a numeral */ + /* so loop till we get enough data to determine type */ + if (inbuf->nbytes < 2) + return PNM_SUSPEND; + + if (*inbuf->byte != 'P') + return PNM_FATAL_ERR; + + inbuf->byte++; + inbuf->nbytes--; + + switch (*inbuf->byte) { + case '1': + context->type = PNM_FORMAT_PBM; + break; + case '2': + context->type = PNM_FORMAT_PGM; + break; + case '3': + context->type = PNM_FORMAT_PPM; + break; + case '4': + context->type = PNM_FORMAT_PBM_RAW; + break; + case '5': + context->type = PNM_FORMAT_PGM_RAW; + break; + case '6': + context->type = PNM_FORMAT_PPM_RAW; + break; + default: + return PNM_FATAL_ERR; + } + + if (!inbuf->nbytes) + return PNM_SUSPEND; + + inbuf->byte++; + inbuf->nbytes--; } - context->type = type; - - inbuf->next_byte += 2; - inbuf->bytes_left -= 2; - - /* now read remainder of header */ - if ((rc = read_next_number (inbuf, &w))) { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return PNM_SUSPEND; + if (!context->width) { + /* read the pixmap width */ + guint width = 0; + + retval = pnm_read_next_value (inbuf, &width); + + if (retval != PNM_OK) + return retval; + + if (!width) + return PNM_FATAL_ERR; + + context->width = width; } - if ((rc = read_next_number (inbuf, &h))) { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return PNM_SUSPEND; + if (!context->height) { + /* read the pixmap height */ + guint height = 0; + + retval = pnm_read_next_value (inbuf, &height); + + if (retval != PNM_OK) + return retval; + + if (!height) + return PNM_FATAL_ERR; + + context->height = height; } - context->width = w; - context->height = h; - - switch (type) { + switch (context->type) { case PNM_FORMAT_PPM: case PNM_FORMAT_PPM_RAW: case PNM_FORMAT_PGM: case PNM_FORMAT_PGM_RAW: - if ((rc = read_next_number (inbuf, &context->maxval)) < 0) { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return PNM_SUSPEND; + if (!context->maxval) { + retval = pnm_read_next_value (inbuf, &context->maxval); + + if (retval != PNM_OK) + return retval; + + if (context->maxval == 0) + return PNM_FATAL_ERR; } break; default: break; } - + return PNM_OK; } - static gint pnm_read_raw_scanline (PnmLoaderContext *context) { - guint numpix; - guint numbytes, offset; PnmIOBuffer *inbuf; - + guint numbytes, offset; + guint numpix = 0; + guchar *dest; + guint i; + g_return_val_if_fail (context != NULL, PNM_FATAL_ERR); - -/*G_BREAKPOINT(); */ - + inbuf = &context->inbuf; - + switch (context->type) { case PNM_FORMAT_PBM_RAW: - numpix = inbuf->bytes_left * 8; + numpix = inbuf->nbytes * 8; break; case PNM_FORMAT_PGM_RAW: - numpix = inbuf->bytes_left; + numpix = inbuf->nbytes; break; case PNM_FORMAT_PPM_RAW: - numpix = inbuf->bytes_left/3; + numpix = inbuf->nbytes / 3; break; default: g_warning ("io-pnm.c: Illegal raw pnm type!\n"); @@ -395,79 +380,100 @@ pnm_read_raw_scanline (PnmLoaderContext *context) } numpix = MIN (numpix, context->width - context->output_col); - - if (numpix == 0) + + if (!numpix) return PNM_SUSPEND; - context->dptr = context->pixels + - context->output_row * context->rowstride; + context->dptr = context->pixels + context->output_row * context->rowstride; switch (context->type) { case PNM_FORMAT_PBM_RAW: - numbytes = numpix/8 + ((numpix % 8) ? 1 : 0); - offset = context->output_col/8; + numbytes = (numpix / 8) + ((numpix % 8) ? 1 : 0); + offset = context->output_col / 8; break; case PNM_FORMAT_PGM_RAW: numbytes = numpix; offset = context->output_col; break; case PNM_FORMAT_PPM_RAW: - numbytes = numpix*3; - offset = context->output_col*3; + numbytes = numpix * 3; + offset = context->output_col * 3; break; default: g_warning ("io-pnm.c: Illegal raw pnm type!\n"); return PNM_FATAL_ERR; } - memcpy (context->dptr + offset, inbuf->next_byte, numbytes); - - inbuf->next_byte += numbytes; - inbuf->bytes_left -= numbytes; - + switch (context->type) { + case PNM_FORMAT_PBM_RAW: + dest = context->dptr + offset; + memcpy (dest, inbuf->byte, numbytes); + break; + case PNM_FORMAT_PGM_RAW: + case PNM_FORMAT_PPM_RAW: + dest = context->dptr + offset; + + if (context->maxval == 255) { + /* special-case optimization */ + memcpy (dest, inbuf->byte, numbytes); + } else { + for (i = 0; i < numbytes; i++) { + guchar *byte = inbuf->byte + i; + + /* scale the color to an 8-bit color depth */ + if (*byte > context->maxval) + *dest++ = 255; + else + *dest++ = (guchar) (255 * *byte / context->maxval); + } + } + break; + default: + g_warning ("Invalid raw pnm format!"); + } + + inbuf->byte += numbytes; + inbuf->nbytes -= numbytes; + context->output_col += numpix; if (context->output_col == context->width) { - if ( context->type == PNM_FORMAT_PBM_RAW ) - explode_bitmap_into_buf(context); - else if ( context->type == PNM_FORMAT_PGM_RAW ) + if (context->type == PNM_FORMAT_PBM_RAW) + explode_bitmap_into_buf (context); + else if (context->type == PNM_FORMAT_PGM_RAW) explode_gray_into_buf (context); context->output_col = 0; context->output_row++; - } else { return PNM_SUSPEND; } - + return PNM_OK; } - static gint pnm_read_ascii_scanline (PnmLoaderContext *context) { - guint offset; - gint rc; - guint value, numval, i; + PnmIOBuffer *inbuf; + guint offset; + guint value, numval, i; guchar data; guchar mask; - guchar *old_next_byte, *dptr; - guint old_bytes_left; - PnmIOBuffer *inbuf; - + guchar *dptr; + gint retval; + g_return_val_if_fail (context != NULL, PNM_FATAL_ERR); - + data = mask = 0; - + inbuf = &context->inbuf; - - context->dptr = context->pixels + - context->output_row * context->rowstride; - + + context->dptr = context->pixels + context->output_row * context->rowstride; + switch (context->type) { case PNM_FORMAT_PBM: numval = MIN (8, context->width - context->output_col); - offset = context->output_col/8; + offset = context->output_col / 8; break; case PNM_FORMAT_PGM: numval = 1; @@ -475,32 +481,31 @@ pnm_read_ascii_scanline (PnmLoaderContext *context) break; case PNM_FORMAT_PPM: numval = 3; - offset = context->output_col*3; + offset = context->output_col * 3; break; default: g_warning ("Can't happen\n"); return PNM_FATAL_ERR; } - - dptr = context->dptr + offset; - + + dptr = context->dptr + offset + context->scan_state; + while (TRUE) { if (context->type == PNM_FORMAT_PBM) { mask = 0x80; data = 0; numval = MIN (8, context->width - context->output_col); } - - old_next_byte = inbuf->next_byte; - old_bytes_left = inbuf->bytes_left; - - for (i=0; i<numval; i++) { - if ((rc = read_next_number (inbuf, &value))) { - inbuf->next_byte = old_next_byte; - inbuf->bytes_left = old_bytes_left; - return PNM_SUSPEND; + + for (i = context->scan_state; i < numval; i++) { + retval = pnm_read_next_value (inbuf, &value); + if (retval != PNM_OK) { + /* save state and return */ + context->scan_state = i; + return retval; } + switch (context->type) { case PNM_FORMAT_PBM: if (value) @@ -509,72 +514,73 @@ pnm_read_ascii_scanline (PnmLoaderContext *context) break; case PNM_FORMAT_PGM: - *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval)); - break; case PNM_FORMAT_PPM: - *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval)); + /* scale the color to an 8-bit color depth */ + if (value > context->maxval) + *dptr++ = 255; + else + *dptr++ = (guchar)(255 * value / context->maxval); break; default: - g_warning ("io-pnm.c: Illegal raw pnm type!\n"); + g_warning ("io-pnm.c: Illegal ascii pnm type!\n"); break; } } + context->scan_state = 0; + if (context->type == PNM_FORMAT_PBM) { *dptr++ = data; context->output_col += numval; } else { context->output_col++; } - + if (context->output_col == context->width) { - if ( context->type == PNM_FORMAT_PBM ) - explode_bitmap_into_buf(context); - else if ( context->type == PNM_FORMAT_PGM ) + if (context->type == PNM_FORMAT_PBM) + explode_bitmap_into_buf (context); + else if (context->type == PNM_FORMAT_PGM) explode_gray_into_buf (context); - + context->output_col = 0; context->output_row++; break; } - } - + return PNM_OK; } -/* returns 1 if a scanline was converted, 0 means we ran out of data */ +/* returns 1 if a scanline was converted, 0 means we ran out of data */ static gint pnm_read_scanline (PnmLoaderContext *context) { - gint rc; - + gint retval; + g_return_val_if_fail (context != NULL, PNM_FATAL_ERR); - + /* read in image data */ /* for raw formats this is trivial */ switch (context->type) { case PNM_FORMAT_PBM_RAW: case PNM_FORMAT_PGM_RAW: case PNM_FORMAT_PPM_RAW: - rc = pnm_read_raw_scanline (context); - if (rc == PNM_SUSPEND) - return rc; + retval = pnm_read_raw_scanline (context); + if (retval != PNM_OK) + return retval; break; - case PNM_FORMAT_PBM: case PNM_FORMAT_PGM: case PNM_FORMAT_PPM: - rc = pnm_read_ascii_scanline (context); - if (rc == PNM_SUSPEND) - return rc; + retval = pnm_read_ascii_scanline (context); + if (retval != PNM_OK) + return retval; break; - default: g_warning ("Cannot load these image types (yet)\n"); return PNM_FATAL_ERR; } - + return PNM_OK; } @@ -582,99 +588,104 @@ pnm_read_scanline (PnmLoaderContext *context) GdkPixbuf * gdk_pixbuf__pnm_image_load (FILE *f) { - gint nbytes; - gint rc; - PnmLoaderContext context; PnmIOBuffer *inbuf; - + gint nbytes; + gint retval; + /* pretend to be doing progressive loading */ context.updated_func = NULL; context.prepared_func = NULL; context.user_data = NULL; - context.inbuf.bytes_left = 0; - context.inbuf.next_byte = NULL; + context.type = 0; + context.inbuf.nbytes = 0; + context.inbuf.byte = NULL; + context.width = 0; + context.height = 0; + context.maxval = 0; context.pixels = NULL; context.pixbuf = NULL; - context.got_header = context.did_prescan = FALSE; - + context.got_header = FALSE; + context.did_prescan = FALSE; + context.scan_state = 0; + inbuf = &context.inbuf; - - while (TRUE) { - guint num_to_read; - + + while (!feof (f)) { + guint num_to_read; + /* keep buffer as full as possible */ - num_to_read = PNM_BUF_SIZE - inbuf->bytes_left; - - if (inbuf->next_byte != NULL && inbuf->bytes_left > 0) - memmove (inbuf->buffer, inbuf->next_byte, - inbuf->bytes_left); - - nbytes = fread (inbuf->buffer+inbuf->bytes_left, - 1, num_to_read, f); - inbuf->bytes_left += nbytes; - inbuf->next_byte = inbuf->buffer; - - /* ran out of data and we haven't exited main loop */ - if (inbuf->bytes_left == 0) { + num_to_read = PNM_BUF_SIZE - inbuf->nbytes; + + if (inbuf->byte != NULL && inbuf->nbytes > 0) + memmove (inbuf->buffer, inbuf->byte, inbuf->nbytes); + + nbytes = fread (inbuf->buffer + inbuf->nbytes, 1, num_to_read, f); + + /* error checking */ + if (nbytes == 0 && ferror (f)) { + /* we ran out of data? */ if (context.pixbuf) gdk_pixbuf_unref (context.pixbuf); - g_warning ("io-pnm.c: Ran out of data...\n"); + g_warning ("io-pnm.c: Ran out of data.\n"); return NULL; } - + + inbuf->nbytes += nbytes; + inbuf->byte = inbuf->buffer; + /* get header if needed */ if (!context.got_header) { - - rc = pnm_read_header (&context); - if (rc == PNM_FATAL_ERR) + retval = pnm_read_header (&context); + if (retval == PNM_FATAL_ERR) return NULL; - else if (rc == PNM_SUSPEND) + else if (retval == PNM_SUSPEND) continue; - + context.got_header = TRUE; } - + /* scan until we hit image data */ if (!context.did_prescan) { - - if (skip_ahead_whitespace (inbuf) == NULL) + retval = pnm_skip_whitespace (inbuf); + if (retval == PNM_FATAL_ERR) + return NULL; + else if (retval == PNM_SUSPEND) continue; - + context.did_prescan = TRUE; context.output_row = 0; context.output_col = 0; - + context.rowstride = context.width * 3; - context.pixels = g_malloc (context.height * - context.width * 3); + context.pixels = g_malloc (context.height * context.width * 3); + if (!context.pixels) { /* Failed to allocate memory */ - g_error ("Couldn't allocate pixel buf"); + g_warning ("Couldn't allocate pixel buf"); } } - + /* if we got here we're reading image data */ while (context.output_row < context.height) { - - rc = pnm_read_scanline (&context); - - if (rc == PNM_SUSPEND) { + retval = pnm_read_scanline (&context); + + if (retval == PNM_SUSPEND) { break; - } else if (rc == PNM_FATAL_ERR) { + } else if (retval == PNM_FATAL_ERR) { if (context.pixbuf) gdk_pixbuf_unref (context.pixbuf); g_warning ("io-pnm.c: error reading rows..\n"); return NULL; } } - + if (context.output_row < context.height) continue; else break; } - + return gdk_pixbuf_new_from_data (context.pixels, GDK_COLORSPACE_RGB, FALSE, 8, context.width, context.height, context.width * 3, free_buffer, NULL); @@ -695,19 +706,23 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, gpointer user_data) { PnmLoaderContext *context; - + context = g_new0 (PnmLoaderContext, 1); context->prepared_func = prepared_func; context->updated_func = updated_func; context->user_data = user_data; + context->width = 0; + context->height = 0; + context->maxval = 0; context->pixbuf = NULL; context->pixels = NULL; context->got_header = FALSE; context->did_prescan = FALSE; - - context->inbuf.bytes_left = 0; - context->inbuf.next_byte = NULL; - + context->scan_state = 0; + + context->inbuf.nbytes = 0; + context->inbuf.byte = NULL; + return (gpointer) context; } @@ -720,18 +735,15 @@ void gdk_pixbuf__pnm_image_stop_load (gpointer data) { PnmLoaderContext *context = (PnmLoaderContext *) data; - + g_return_if_fail (context != NULL); - + if (context->pixbuf) gdk_pixbuf_unref (context->pixbuf); - + g_free (context); } - - - /* * context - from image_begin_load * buf - new image data @@ -743,103 +755,104 @@ gboolean gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) { PnmLoaderContext *context = (PnmLoaderContext *)data; - PnmIOBuffer *inbuf; - - guchar *old_next_byte; - guint old_bytes_left; + PnmIOBuffer *inbuf; + guchar *old_byte; + guint old_nbytes; guchar *bufhd; - guint num_left, spinguard; - gint rc; - + guint num_left, spinguard; + gint retval; + g_return_val_if_fail (context != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); - + bufhd = buf; inbuf = &context->inbuf; - old_bytes_left = inbuf->bytes_left; - old_next_byte = inbuf->next_byte; - + old_nbytes = inbuf->nbytes; + old_byte = inbuf->byte; + num_left = size; spinguard = 0; while (TRUE) { guint num_to_copy; - + /* keep buffer as full as possible */ - num_to_copy = MIN (PNM_BUF_SIZE - inbuf->bytes_left, num_left); + num_to_copy = MIN (PNM_BUF_SIZE - inbuf->nbytes, num_left); if (num_to_copy == 0) spinguard++; - + if (spinguard > 1) return TRUE; - - if (inbuf->next_byte != NULL && inbuf->bytes_left > 0) - memmove (inbuf->buffer, inbuf->next_byte, - inbuf->bytes_left); - - memcpy (inbuf->buffer + inbuf->bytes_left, bufhd, num_to_copy); + + if (inbuf->byte != NULL && inbuf->nbytes > 0) + memmove (inbuf->buffer, inbuf->byte, inbuf->nbytes); + + memcpy (inbuf->buffer + inbuf->nbytes, bufhd, num_to_copy); bufhd += num_to_copy; - inbuf->bytes_left += num_to_copy; - inbuf->next_byte = inbuf->buffer; + inbuf->nbytes += num_to_copy; + inbuf->byte = inbuf->buffer; num_left -= num_to_copy; /* ran out of data and we haven't exited main loop */ - if (inbuf->bytes_left == 0) + if (inbuf->nbytes == 0) return TRUE; - + /* get header if needed */ if (!context->got_header) { - rc = pnm_read_header (context); - if (rc == PNM_FATAL_ERR) + retval = pnm_read_header (context); + + if (retval == PNM_FATAL_ERR) return FALSE; - else if (rc == PNM_SUSPEND) + else if (retval == PNM_SUSPEND) continue; - + context->got_header = TRUE; } - + /* scan until we hit image data */ if (!context->did_prescan) { - if (skip_ahead_whitespace (inbuf) == NULL) + retval = pnm_skip_whitespace (inbuf); + + if (retval == PNM_FATAL_ERR) + return FALSE; + else if (retval == PNM_SUSPEND) continue; - + context->did_prescan = TRUE; context->output_row = 0; context->output_col = 0; - - context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - FALSE, - 8, - context->width, - context->height); - + + context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + FALSE, + 8, + context->width, + context->height); + if (context->pixbuf == NULL) { /* Failed to allocate memory */ g_error ("Couldn't allocate gdkpixbuf"); } - + context->pixels = context->pixbuf->pixels; context->rowstride = context->pixbuf->rowstride; - + /* Notify the client that we are ready to go */ (* context->prepared_func) (context->pixbuf, context->user_data); - } - + /* if we got here we're reading image data */ while (context->output_row < context->height) { - rc = pnm_read_scanline (context); - - if (rc == PNM_SUSPEND) { + retval = pnm_read_scanline (context); + + if (retval == PNM_SUSPEND) { break; - } else if (rc == PNM_FATAL_ERR) { + } else if (retval == PNM_FATAL_ERR) { if (context->pixbuf) gdk_pixbuf_unref (context->pixbuf); - g_warning ("io-pnm.c: error reading rows..\n"); + g_warning ("io-pnm.c: error reading rows.\n"); return FALSE; - } else if (rc == PNM_OK) { - + } else if (retval == PNM_OK) { /* send updated signal */ (* context->updated_func) (context->pixbuf, 0, @@ -849,12 +862,12 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size) context->user_data); } } - + if (context->output_row < context->height) continue; else break; } - + return TRUE; } |