} PnmIOBuffer;
typedef struct {
- ModuleUpdatedNotifyFunc updated_func;
- ModulePreparedNotifyFunc prepared_func;
+ GdkPixbufModuleUpdatedFunc updated_func;
+ GdkPixbufModulePreparedFunc prepared_func;
+ GdkPixbufModuleSizeFunc size_func;
gpointer user_data;
GdkPixbuf *pixbuf;
} PnmLoaderContext;
static GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error);
-static gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func,
- ModuleUpdatedNotifyFunc func2,
+static gpointer gdk_pixbuf__pnm_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+ GdkPixbufModulePreparedFunc func,
+ GdkPixbufModuleUpdatedFunc func2,
gpointer user_data,
GError **error);
static gboolean gdk_pixbuf__pnm_image_stop_load (gpointer context, GError **error);
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)
-{
- g_free (pixels);
-}
-
/* explode bitmap data into rgb components */
/* we need to know what the row so we can */
for ( ; *inptr != '\n' && inptr < inend; inptr++)
;
- if ( *inptr != '\n' ) {
+ if ( inptr == inend || *inptr != '\n' ) {
/* couldn't read whole comment */
return PNM_SUSPEND;
}
/* read next number from buffer */
static gint
-pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
+pnm_read_next_value (PnmIOBuffer *inbuf, gint max_length, guint *value, GError **error)
{
register guchar *inptr, *word, *p;
guchar *inend, buf[129];
g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR);
g_return_val_if_fail (value != NULL, PNM_FATAL_ERR);
+ if (max_length < 0)
+ max_length = 128;
+
/* skip white space */
if ((retval = pnm_skip_whitespace (inbuf, error)) != PNM_OK)
return retval;
inptr = inbuf->byte;
/* copy this pnm 'word' into a temp buffer */
- for (p = inptr, word = buf; (p < inend) && !g_ascii_isspace (*p) && (*p != '#') && (p - inptr < 128); p++, word++)
+ for (p = inptr, word = buf; (p < inend) && !g_ascii_isspace (*p) && (*p != '#') && (p - inptr < max_length); p++, word++)
*word = *p;
*word = '\0';
/* hmmm, there must be more data to this 'word' */
- if (!g_ascii_isspace (*p) && (*p != '#') && (p - inptr < 128))
+ if (p == inend || (!g_ascii_isspace (*p) && (*p != '#') && (p - inptr < max_length)))
return PNM_SUSPEND;
/* get the value */
result = strtol (buf, &endptr, 10);
- if (*endptr != '\0' || result < 0) {
+ if (*endptr != '\0' || result < 0 || result > G_MAXUINT) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
/* read the pixmap width */
guint width = 0;
- retval = pnm_read_next_value (inbuf, &width,
+ retval = pnm_read_next_value (inbuf, -1, &width,
context->error);
if (retval != PNM_OK)
/* read the pixmap height */
guint height = 0;
- retval = pnm_read_next_value (inbuf, &height,
+ retval = pnm_read_next_value (inbuf, -1, &height,
context->error);
if (retval != PNM_OK)
case PNM_FORMAT_PGM:
case PNM_FORMAT_PGM_RAW:
if (!context->maxval) {
- retval = pnm_read_next_value (inbuf, &context->maxval,
+ retval = pnm_read_next_value (inbuf, -1, &context->maxval,
context->error);
if (retval != PNM_OK)
return PNM_FATAL_ERR;
}
- if (context->maxval > 255) {
- g_set_error (context->error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Can't handle PNM files with maximum color values greater than 255"));
- return PNM_FATAL_ERR;
- }
}
break;
default:
_("Raw PNM image type is invalid"));
return PNM_FATAL_ERR;
}
+ if(context->maxval>255)
+ numpix/=2;
numpix = MIN (numpix, context->width - context->output_col);
_("Raw PNM image type is invalid"));
return PNM_FATAL_ERR;
}
+ if(context->maxval>255)
+ numbytes*=2;
switch (context->type) {
case PNM_FORMAT_PBM_RAW:
if (context->maxval == 255) {
/* special-case optimization */
memcpy (dest, inbuf->byte, numbytes);
+ } else if(context->maxval == 65535) {
+ /* optimized version of the next case */
+ for(i=0; i < numbytes ; i+=2) {
+ *dest++=inbuf->byte[i];
+ }
+ } else if(context->maxval > 255) {
+ /* scale down to 256 colors */
+ for(i=0; i < numbytes ; i+=2) {
+ guint v=inbuf->byte[i]*256+inbuf->byte[i+1];
+ *dest++=v*255/context->maxval;
+ }
} else {
for (i = 0; i < numbytes; i++) {
guchar *byte = inbuf->byte + i;
guchar mask;
guchar *dptr;
gint retval;
+ gint max_length;
g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
switch (context->type) {
case PNM_FORMAT_PBM:
+ max_length = 1;
numval = MIN (8, context->width - context->output_col);
offset = context->output_col / 8;
break;
case PNM_FORMAT_PGM:
+ max_length = -1;
numval = 1;
offset = context->output_col;
break;
case PNM_FORMAT_PPM:
+ max_length = -1;
numval = 3;
offset = context->output_col * 3;
break;
}
for (i = context->scan_state; i < numval; i++) {
- retval = pnm_read_next_value (inbuf, &value,
- context->error);
+ retval = pnm_read_next_value (inbuf, max_length,
+ &value, context->error);
if (retval != PNM_OK) {
/* save state and return */
context->scan_state = i;
break;
case PNM_FORMAT_PGM:
case PNM_FORMAT_PPM:
- /* scale the color to an 8-bit color depth */
+ /* scale the color up or down to an 8-bit color depth */
if (value > context->maxval)
*dptr++ = 255;
else
context.output_row = 0;
context.output_col = 0;
- context.rowstride = context.width * 3;
- context.pixels = g_try_malloc (context.height * context.width * 3);
+ context.pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
+ context.width, context.height);
- if (!context.pixels) {
+ if (!context.pixbuf) {
/* Failed to allocate memory */
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Can't allocate memory for loading PNM image"));
+ _("Cannot allocate memory for loading PNM image"));
return NULL;
}
+
+ context.rowstride = context.pixbuf->rowstride;
+ context.pixels = context.pixbuf->pixels;
}
/* if we got here we're reading image data */
break;
}
- return gdk_pixbuf_new_from_data (context.pixels, GDK_COLORSPACE_RGB, FALSE, 8,
- context.width, context.height,
- context.width * 3, free_buffer, NULL);
-
+ return context.pixbuf;
}
/*
*/
static gpointer
-gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
- ModuleUpdatedNotifyFunc updated_func,
+gdk_pixbuf__pnm_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+ GdkPixbufModulePreparedFunc prepared_func,
+ GdkPixbufModuleUpdatedFunc updated_func,
gpointer user_data,
GError **error)
{
return NULL;
}
memset (context, 0, sizeof (PnmLoaderContext));
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
context->got_header = TRUE;
}
+
+ if (context->size_func) {
+ gint w = context->width;
+ gint h = context->height;
+ (*context->size_func) (&w, &h, context->user_data);
+
+ if (w == 0 || h == 0)
+ return FALSE;
+ }
+
/* scan until we hit image data */
if (!context->did_prescan) {
context->rowstride = context->pixbuf->rowstride;
/* Notify the client that we are ready to go */
- (* context->prepared_func) (context->pixbuf,
- NULL,
- context->user_data);
+ if (context->prepared_func)
+ (* context->prepared_func) (context->pixbuf,
+ NULL,
+ context->user_data);
}
/* if we got here we're reading image data */
break;
} else if (retval == PNM_FATAL_ERR) {
return FALSE;
- } else if (retval == PNM_OK) {
+ } else if (retval == PNM_OK && context->updated_func) {
/* send updated signal */
(* context->updated_func) (context->pixbuf,
0,
}
void
-gdk_pixbuf__pnm_fill_vtable (GdkPixbufModule *module)
+MODULE_ENTRY (pnm, fill_vtable) (GdkPixbufModule *module)
+{
+ module->load = gdk_pixbuf__pnm_image_load;
+ module->begin_load = gdk_pixbuf__pnm_image_begin_load;
+ module->stop_load = gdk_pixbuf__pnm_image_stop_load;
+ module->load_increment = gdk_pixbuf__pnm_image_load_increment;
+}
+
+void
+MODULE_ENTRY (pnm, fill_info) (GdkPixbufFormat *info)
{
- module->load = gdk_pixbuf__pnm_image_load;
- module->begin_load = gdk_pixbuf__pnm_image_begin_load;
- module->stop_load = gdk_pixbuf__pnm_image_stop_load;
- module->load_increment = gdk_pixbuf__pnm_image_load_increment;
+ static GdkPixbufModulePattern signature[] = {
+ { "P1", NULL, 100 },
+ { "P2", NULL, 100 },
+ { "P3", NULL, 100 },
+ { "P4", NULL, 100 },
+ { "P5", NULL, 100 },
+ { "P6", NULL, 100 },
+ { NULL, NULL, 0 }
+ };
+ static gchar * mime_types[] = {
+ "image/x-portable-anymap",
+ "image/x-portable-bitmap",
+ "image/x-portable-graymap",
+ "image/x-portable-pixmap",
+ NULL
+ };
+ static gchar * extensions[] = {
+ "pnm",
+ "pbm",
+ "pgm",
+ "ppm",
+ NULL
+ };
+
+ info->name = "pnm";
+ info->signature = signature;
+ info->description = N_("The PNM/PBM/PGM/PPM image format family");
+ info->mime_types = mime_types;
+ info->extensions = extensions;
+ info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+ info->license = "LGPL";
}