]> Pileus Git - ~andy/gtk/blobdiff - gdk-pixbuf/io-pnm.c
Updated Bulgarian translation by Alexander Shopov <ash@contact.bg>
[~andy/gtk] / gdk-pixbuf / io-pnm.c
index adf843f33cbe148a7ace3ac74be17ccc0bd06c5d..3af9794c252d994b81ef3682998f839b4a4fb064 100644 (file)
@@ -53,8 +53,9 @@ typedef struct {
 } PnmIOBuffer;
 
 typedef struct {
-       ModuleUpdatedNotifyFunc updated_func;
-       ModulePreparedNotifyFunc prepared_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       GdkPixbufModuleSizeFunc size_func;
        gpointer user_data;
        
        GdkPixbuf *pixbuf;
@@ -81,8 +82,9 @@ typedef struct {
 } 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);
@@ -93,13 +95,6 @@ static gboolean    gdk_pixbuf__pnm_image_load_increment (gpointer 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)
-{
-       g_free (pixels);
-}
-
 
 /* explode bitmap data into rgb components         */
 /* we need to know what the row so we can          */
@@ -197,7 +192,7 @@ pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error)
                        for ( ; *inptr != '\n' && inptr < inend; inptr++)
                                ;
                        
-                       if ( *inptr != '\n' ) {
+                       if ( inptr == inend || *inptr != '\n' ) {
                                /* couldn't read whole comment */
                                return PNM_SUSPEND;
                        }
@@ -217,7 +212,7 @@ pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error)
 
 /* 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];
@@ -229,6 +224,9 @@ pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
        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;
@@ -237,17 +235,17 @@ pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
        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,
@@ -328,7 +326,7 @@ pnm_read_header (PnmLoaderContext *context)
                /* 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) 
@@ -349,7 +347,7 @@ pnm_read_header (PnmLoaderContext *context)
                /* 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)
@@ -372,7 +370,7 @@ pnm_read_header (PnmLoaderContext *context)
        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)
@@ -394,13 +392,6 @@ pnm_read_header (PnmLoaderContext *context)
                                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:
@@ -440,6 +431,8 @@ pnm_read_raw_scanline (PnmLoaderContext *context)
                             _("Raw PNM image type is invalid"));
                return PNM_FATAL_ERR;
        }
+       if(context->maxval>255) 
+               numpix/=2;
        
        numpix = MIN (numpix, context->width - context->output_col);
        
@@ -468,6 +461,8 @@ pnm_read_raw_scanline (PnmLoaderContext *context)
                             _("Raw PNM image type is invalid"));
                return PNM_FATAL_ERR;
        }
+       if(context->maxval>255) 
+               numbytes*=2;                            
        
        switch (context->type) {
        case PNM_FORMAT_PBM_RAW:
@@ -481,6 +476,17 @@ pnm_read_raw_scanline (PnmLoaderContext *context)
                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;
@@ -530,6 +536,7 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
        guchar mask;
        guchar *dptr;
        gint retval;
+       gint max_length;
        
        g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
        
@@ -541,14 +548,17 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
        
        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;
@@ -572,8 +582,8 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
                }
                
                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;
@@ -589,7 +599,7 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
                                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
@@ -764,17 +774,20 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
                        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 */
@@ -797,10 +810,7 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
                        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;
 }
 
 /* 
@@ -810,8 +820,9 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
  */
 
 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)
 {
@@ -825,6 +836,7 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
                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;
@@ -949,6 +961,16 @@ gdk_pixbuf__pnm_image_load_increment (gpointer 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) {
@@ -1001,9 +1023,10 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
                        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 */
@@ -1014,7 +1037,7 @@ gdk_pixbuf__pnm_image_load_increment (gpointer 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, 
@@ -1035,10 +1058,46 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
 }
 
 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";
 }