[gimp] file-pnm: Add support for saving PFM (portable floatmap) files in color and gray



commit 51e4491fbf5291d0539b37c8e4f6c3c5c16071b8
Author: Mukund Sivaraman <muks banu com>
Date:   Tue Jan 20 20:14:07 2015 +0530

    file-pnm: Add support for saving PFM (portable floatmap) files in color and gray

 plug-ins/common/file-pnm.c |  325 ++++++++++++++++++++++++++++++--------------
 1 files changed, 223 insertions(+), 102 deletions(-)
---
diff --git a/plug-ins/common/file-pnm.c b/plug-ins/common/file-pnm.c
index 4be4737..f895a1e 100644
--- a/plug-ins/common/file-pnm.c
+++ b/plug-ins/common/file-pnm.c
@@ -44,6 +44,7 @@
 #define PBM_SAVE_PROC  "file-pbm-save"
 #define PGM_SAVE_PROC  "file-pgm-save"
 #define PPM_SAVE_PROC  "file-ppm-save"
+#define PFM_SAVE_PROC  "file-pfm-save"
 #define PLUG_IN_BINARY "file-pnm"
 #define PLUG_IN_ROLE   "gimp-file-pnm"
 
@@ -112,9 +113,6 @@ typedef struct
                                  * by the spec anyways so this shouldn't
                                  * be an issue. */
 
-#define SAVE_COMMENT_STRING "# CREATOR: GIMP PNM Filter Version 1.1\n"
-
-
 /* Declare some local functions.
  */
 static void       query      (void);
@@ -129,6 +127,7 @@ static gint       save_image (GFile            *file,
                               gint32            image_ID,
                               gint32            drawable_ID,
                               gboolean          pbm,
+                              gboolean          float_format,
                               GError          **error);
 
 static gboolean   save_dialog              (void);
@@ -247,6 +246,15 @@ query (void)
     { GIMP_PDB_INT32,    "raw",          "TRUE for raw output, FALSE for ascii output" }
   };
 
+  static const GimpParamDef pfm_save_args[] =
+  {
+    { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_IMAGE,    "image",        "Input image"                  },
+    { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save"             },
+    { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
+    { GIMP_PDB_STRING,   "raw-filename", "The name of the file to save the image in" }
+  };
+
   gimp_install_procedure (LOAD_PROC,
                           "Loads files in the PNM file format",
                           "This plug-in loads files in the various Netpbm portable file formats.",
@@ -317,20 +325,35 @@ query (void)
                           G_N_ELEMENTS (save_args), 0,
                           save_args, NULL);
 
+  gimp_install_procedure (PFM_SAVE_PROC,
+                          "Saves files in the PFM file format",
+                          "PFM saving handles all images without transparency.",
+                          "Mukund Sivaraman",
+                          "Mukund Sivaraman",
+                          "2015",
+                          N_("PFM image"),
+                          "RGB, GRAY, INDEXED",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (pfm_save_args), 0,
+                          pfm_save_args, NULL);
+
   gimp_register_file_handler_mime (PNM_SAVE_PROC, "image/x-portable-anymap");
   gimp_register_file_handler_mime (PBM_SAVE_PROC, "image/x-portable-bitmap");
   gimp_register_file_handler_mime (PGM_SAVE_PROC, "image/x-portable-graymap");
   gimp_register_file_handler_mime (PPM_SAVE_PROC, "image/x-portable-pixmap");
+  gimp_register_file_handler_mime (PPM_SAVE_PROC, "image/x-portable-floatmap");
 
   gimp_register_file_handler_uri (PNM_SAVE_PROC);
   gimp_register_file_handler_uri (PBM_SAVE_PROC);
   gimp_register_file_handler_uri (PGM_SAVE_PROC);
   gimp_register_file_handler_uri (PPM_SAVE_PROC);
+  gimp_register_file_handler_uri (PFM_SAVE_PROC);
 
   gimp_register_save_handler (PNM_SAVE_PROC, "pnm", "");
   gimp_register_save_handler (PBM_SAVE_PROC, "pbm", "");
   gimp_register_save_handler (PGM_SAVE_PROC, "pgm", "");
   gimp_register_save_handler (PPM_SAVE_PROC, "ppm", "");
+  gimp_register_save_handler (PFM_SAVE_PROC, "pfm", "");
 }
 
 static void
@@ -342,12 +365,13 @@ run (const gchar      *name,
 {
   static GimpParam   values[2];
   GimpRunMode        run_mode;
-  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+  GimpPDBStatusType  status       = GIMP_PDB_SUCCESS;
   gint32             image_ID;
   gint32             drawable_ID;
-  GimpExportReturn   export = GIMP_EXPORT_CANCEL;
-  GError            *error  = NULL;
-  gboolean           pbm    = FALSE;  /* flag for PBM output */
+  GimpExportReturn   export       = GIMP_EXPORT_CANCEL;
+  GError            *error        = NULL;
+  gboolean           pbm          = FALSE;  /* flag for PBM output */
+  gboolean           float_format = FALSE;  /* flag for PFM output */
 
   INIT_I18N ();
   gegl_init (NULL, NULL);
@@ -378,7 +402,8 @@ run (const gchar      *name,
   else if (strcmp (name, PNM_SAVE_PROC) == 0 ||
            strcmp (name, PBM_SAVE_PROC) == 0 ||
            strcmp (name, PGM_SAVE_PROC) == 0 ||
-           strcmp (name, PPM_SAVE_PROC) == 0)
+           strcmp (name, PPM_SAVE_PROC) == 0 ||
+           strcmp (name, PFM_SAVE_PROC) == 0)
     {
       image_ID    = param[1].data.d_int32;
       drawable_ID = param[2].data.d_int32;
@@ -408,12 +433,19 @@ run (const gchar      *name,
               export = gimp_export_image (&image_ID, &drawable_ID, "PGM",
                                           GIMP_EXPORT_CAN_HANDLE_GRAY);
             }
-          else
+          else if (strcmp (name, PPM_SAVE_PROC) == 0)
             {
               export = gimp_export_image (&image_ID, &drawable_ID, "PPM",
                                           GIMP_EXPORT_CAN_HANDLE_RGB |
                                           GIMP_EXPORT_CAN_HANDLE_INDEXED);
             }
+          else
+            {
+              export = gimp_export_image (&image_ID, &drawable_ID, "PFM",
+                                          GIMP_EXPORT_CAN_HANDLE_RGB |
+                                          GIMP_EXPORT_CAN_HANDLE_GRAY);
+              float_format = TRUE;
+            }
 
           if (export == GIMP_EXPORT_CANCEL)
             {
@@ -426,47 +458,69 @@ run (const gchar      *name,
           break;
         }
 
-      switch (run_mode)
+      if (strcmp (name, PFM_SAVE_PROC) != 0)
         {
-        case GIMP_RUN_INTERACTIVE:
-          /*  Possibly retrieve data  */
-          gimp_get_data (name, &psvals);
+          switch (run_mode)
+            {
+            case GIMP_RUN_INTERACTIVE:
+              /*  Possibly retrieve data  */
+              gimp_get_data (name, &psvals);
 
-          /*  First acquire information with a dialog  */
-          if (! save_dialog ())
-            status = GIMP_PDB_CANCEL;
-          break;
+              /*  First acquire information with a dialog  */
+              if (! save_dialog ())
+                status = GIMP_PDB_CANCEL;
+              break;
 
-        case GIMP_RUN_NONINTERACTIVE:
-          /*  Make sure all the arguments are there!  */
-          if (nparams != 6)
-            {
-              status = GIMP_PDB_CALLING_ERROR;
+            case GIMP_RUN_NONINTERACTIVE:
+              /*  Make sure all the arguments are there!  */
+              if (nparams != 6)
+                {
+                  status = GIMP_PDB_CALLING_ERROR;
+                }
+              else
+                {
+                  psvals.raw = (param[5].data.d_int32) ? TRUE : FALSE;
+                  pbm = (strcmp (name, PBM_SAVE_PROC) == 0);
+                }
+              break;
+
+            case GIMP_RUN_WITH_LAST_VALS:
+              /*  Possibly retrieve data  */
+              gimp_get_data (name, &psvals);
+              break;
+
+            default:
+              break;
             }
-          else
+        }
+      else
+        {
+          switch (run_mode)
             {
-              psvals.raw = (param[5].data.d_int32) ? TRUE : FALSE;
-              pbm = (strcmp (name, PBM_SAVE_PROC) == 0);
-            }
-          break;
-
-        case GIMP_RUN_WITH_LAST_VALS:
-          /*  Possibly retrieve data  */
-          gimp_get_data (name, &psvals);
-          break;
+            case GIMP_RUN_NONINTERACTIVE:
+              /*  Make sure all the arguments are there!  */
+              if (nparams != 5)
+                {
+                  status = GIMP_PDB_CALLING_ERROR;
+                }
+              break;
 
-        default:
-          break;
+            default:
+              break;
+            }
         }
 
       if (status == GIMP_PDB_SUCCESS)
         {
           if (save_image (g_file_new_for_uri (param[3].data.d_string),
-                          image_ID, drawable_ID, pbm,
+                          image_ID, drawable_ID, pbm, float_format,
                           &error))
             {
-              /*  Store psvals data  */
-              gimp_set_data (name, &psvals, sizeof (PNMSaveVals));
+              if (strcmp (name, PFM_SAVE_PROC) != 0)
+                {
+                  /*  Store psvals data  */
+                  gimp_set_data (name, &psvals, sizeof (PNMSaveVals));
+                }
             }
           else
             {
@@ -1044,6 +1098,17 @@ pnmsaverow_raw (PNMRowInfo    *ri,
   return output_write (ri->output, data, ri->xres * ri->np, error);
 }
 
+/* Writes out RGB and grayscale float rows */
+static gboolean
+pnmsaverow_float (PNMRowInfo    *ri,
+                  const float   *data,
+                  GError       **error)
+{
+  return output_write (ri->output, data,
+                       ri->xres * ri->np * sizeof (float),
+                       error);
+}
+
 /* Writes out indexed raw rows */
 static gboolean
 pnmsaverow_raw_indexed (PNMRowInfo    *ri,
@@ -1110,10 +1175,12 @@ save_image (GFile     *file,
             gint32     image_ID,
             gint32     drawable_ID,
             gboolean   pbm,
+            gboolean   float_format,
             GError   **error)
 {
-  GOutputStream *output;
-  GeglBuffer    *buffer;
+  gboolean       status = FALSE;
+  GOutputStream *output = NULL;
+  GeglBuffer    *buffer = NULL;
   const Babl    *format;
   const gchar   *header_string = NULL;
   GimpImageType  drawable_type;
@@ -1122,20 +1189,18 @@ save_image (GFile     *file,
   guchar         red[256];
   guchar         grn[256];
   guchar         blu[256];
-  guchar        *data;
-  guchar        *d;
-  gchar         *rowbuf;
   gchar          buf[BUFLEN];
   gint           np = 0;
   gint           xres, yres;
   gint           ypos, yend;
   gint           rowbufsize = 0;
+  gchar         *comment = NULL;
 
   /*  Make sure we're not saving an image with an alpha channel  */
   if (gimp_drawable_has_alpha (drawable_ID))
     {
       g_message (_("Cannot save images with alpha channel."));
-      return FALSE;
+      goto out;
     }
 
   gimp_progress_init_printf (_("Saving '%s'"),
@@ -1146,7 +1211,7 @@ save_image (GFile     *file,
                                             NULL, FALSE, G_FILE_CREATE_NONE,
                                             NULL, error));
   if (! output)
-    return FALSE;
+    goto out;
 
   buffer = gimp_drawable_get_buffer (drawable_ID);
 
@@ -1156,7 +1221,7 @@ save_image (GFile     *file,
   drawable_type = gimp_drawable_type (drawable_ID);
 
   /* write out magic number */
-  if (!psvals.raw)
+  if (!float_format && !psvals.raw)
     {
       if (pbm)
         {
@@ -1196,11 +1261,11 @@ save_image (GFile     *file,
 
             default:
               g_warning ("PNM: Unknown drawable_type\n");
-              return FALSE;
+              goto out;
             }
         }
     }
-  else
+  else if (!float_format)
     {
       if (pbm)
         {
@@ -1240,18 +1305,35 @@ save_image (GFile     *file,
 
             default:
               g_warning ("PNM: Unknown drawable_type\n");
-              return FALSE;
+              goto out;
             }
         }
     }
-
-  if (! output_write (output, header_string, strlen (header_string), error))
+  else
     {
-      g_object_unref (output);
-      g_object_unref (buffer);
-      return FALSE;
+      switch (drawable_type)
+        {
+        case GIMP_GRAY_IMAGE:
+          header_string = "Pf\n";
+          format = babl_format ("Y float");
+          np = 1;
+          break;
+
+        case GIMP_RGB_IMAGE:
+          header_string = "PF\n";
+          format = babl_format ("RGB float");
+          np = 3;
+          break;
+
+        default:
+          g_warning ("PFM: Unknown drawable_type\n");
+          goto out;
+        }
     }
 
+  if (! output_write (output, header_string, strlen (header_string), error))
+    goto out;
+
   rowinfo.zero_is_black = FALSE;
 
   if (drawable_type == GIMP_INDEXED_IMAGE)
@@ -1307,81 +1389,120 @@ save_image (GFile     *file,
     }
 
   /* write out comment string */
-  if (! output_write (output, SAVE_COMMENT_STRING, strlen (SAVE_COMMENT_STRING),
-                      error))
-    {
-      g_object_unref (output);
-      g_object_unref (buffer);
-      return FALSE;
-    }
+  comment = g_strdup_printf("# Created by GIMP version %s PNM plug-in\n",
+                            GIMP_VERSION);
+
+  if (! output_write (output, comment, strlen (comment), error))
+      goto out;
 
   /* write out resolution and maxval */
   if (pbm)
     g_snprintf (buf, sizeof (buf), "%d %d\n", xres, yres);
-  else
+  else if (!float_format)
     g_snprintf (buf, sizeof (buf), "%d %d\n255\n", xres, yres);
+  else
+    g_snprintf (buf, sizeof (buf), "%d %d\n%f\n", xres, yres,
+                G_BYTE_ORDER == G_BIG_ENDIAN ? 1.0f : -1.0f);
 
   if (! output_write (output, buf, strlen (buf), error))
+    goto out;
+
+  if (!float_format)
     {
-      g_object_unref (output);
-      g_object_unref (buffer);
-      return FALSE;
-    }
+      guchar *data;
+      guchar *d;
+      gchar  *rowbuf = NULL;
 
-  /* allocate a buffer for retrieving information from the pixel region  */
-  data = g_new (guchar,
-                gimp_tile_height () * xres *
-                babl_format_get_bytes_per_pixel (format));
+      /* allocate a buffer for retrieving information from the pixel region  */
+      data = g_new (guchar,
+                    gimp_tile_height () * xres *
+                    babl_format_get_bytes_per_pixel (format));
 
-  rowbuf = g_new (gchar, rowbufsize + 1);
+      rowbuf = g_new (gchar, rowbufsize + 1);
 
-  rowinfo.output = output;
-  rowinfo.rowbuf = rowbuf;
-  rowinfo.xres   = xres;
-  rowinfo.np     = np;
+      rowinfo.output = output;
+      rowinfo.rowbuf = rowbuf;
+      rowinfo.xres   = xres;
+      rowinfo.np     = np;
 
-  d = NULL; /* only to please the compiler */
+      d = NULL; /* only to please the compiler */
 
-  /* Write the body out */
-  for (ypos = 0; ypos < yres; ypos++)
-    {
-      if ((ypos % gimp_tile_height ()) == 0)
+      /* Write the body out */
+      for (ypos = 0; ypos < yres; ypos++)
         {
-          yend = ypos + gimp_tile_height ();
-          yend = MIN (yend, yres);
+          if ((ypos % gimp_tile_height ()) == 0)
+            {
+              yend = ypos + gimp_tile_height ();
+              yend = MIN (yend, yres);
+
+              gegl_buffer_get (buffer,
+                               GEGL_RECTANGLE (0, ypos, xres, yend - ypos), 1.0,
+                               format, data,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+              d = data;
+            }
+
+          if (! saverow (&rowinfo, d, error))
+            {
+              g_free (rowbuf);
+              g_free (data);
+              goto out;
+            }
+
+          d += xres * (np ? np : 1);
+
+          if (ypos % 32 == 0)
+            gimp_progress_update ((double) ypos / (double) yres);
+        }
+
+      g_free (rowbuf);
+      g_free (data);
+    }
+  else
+    {
+      /* allocate a buffer for retrieving information from the pixel
+         region */
+      gfloat *data = g_new (gfloat, xres * np);
+
+      rowinfo.output = output;
+      rowinfo.rowbuf = NULL;
+      rowinfo.xres   = xres;
+      rowinfo.np     = np;
 
+      /* Write the body out in reverse row order */
+      for (ypos = yres - 1; ypos >= 0; ypos--)
+        {
           gegl_buffer_get (buffer,
-                           GEGL_RECTANGLE (0, ypos, xres, yend - ypos), 1.0,
+                           GEGL_RECTANGLE (0, ypos, xres, 1), 1.0,
                            format, data,
                            GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
 
-          d = data;
-        }
+          if (! pnmsaverow_float (&rowinfo, data, error))
+            {
+              g_free (data);
+              goto out;
+            }
 
-      if (! saverow (&rowinfo, d, error))
-        {
-          g_free (rowbuf);
-          g_free (data);
-          g_object_unref (output);
-          g_object_unref (buffer);
-          return FALSE;
+          if (ypos % 32 == 0)
+            gimp_progress_update ((double) (yres - ypos) / (double) yres);
         }
 
-      d += xres * (np ? np : 1);
-
-      if (ypos % 32 == 0)
-        gimp_progress_update ((double) ypos / (double) yres);
+      g_free (data);
     }
 
-  g_free (rowbuf);
-  g_free (data);
-
-  g_object_unref (buffer);
-  g_object_unref (output);
-
   gimp_progress_update (1.0);
+  status = TRUE;
+
+ out:
+  if (comment)
+    g_free (comment);
+  if (buffer)
+    g_object_unref (buffer);
+  if (output)
+    g_object_unref (output);
 
-  return TRUE;
+  return status;
 }
 
 static gboolean


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]