Index: plug-ins/common/pnm.c
===================================================================
RCS file: /cvs/gnome/gimp/plug-ins/common/pnm.c,v
retrieving revision 1.63
diff -u -p -r1.63 pnm.c
--- plug-ins/common/pnm.c	4 Feb 2006 01:02:25 -0000	1.63
+++ plug-ins/common/pnm.c	15 May 2006 11:38:36 -0000
@@ -23,6 +23,8 @@
  * The pnm reading and writing code was written from scratch by Erik Nygren
  * (nygren@mit.edu) based on the specifications in the man pages and
  * does not contain any code from the netpbm or pbmplus distributions.
+ *
+ * 2006: pbm saving written by Martin K Collins (martin@mkcollins.org)
  */
 
 #include "config.h"
@@ -59,6 +61,7 @@
 
 #define LOAD_PROC      "file-pnm-load"
 #define PNM_SAVE_PROC  "file-pnm-save"
+#define PBM_SAVE_PROC  "file-pbm-save"
 #define PGM_SAVE_PROC  "file-pgm-save"
 #define PPM_SAVE_PROC  "file-ppm-save"
 #define PLUG_IN_BINARY "pnm"
@@ -127,7 +130,8 @@ static void   run        (const gchar   
 static gint32 load_image (const gchar      *filename);
 static gint   save_image (const gchar      *filename,
                           gint32            image_ID,
-                          gint32            drawable_ID);
+                          gint32            drawable_ID,
+                          gboolean          pbm);
 
 static gint   save_dialog              (void);
 
@@ -145,6 +149,10 @@ static void   pnmsaverow_ascii         (
                                         guchar     *data);
 static void   pnmsaverow_raw           (PNMRowInfo *ri,
                                         guchar     *data);
+static void   pnmsaverow_raw_pbm       (PNMRowInfo *ri,
+                                        guchar     *data);
+static void   pnmsaverow_ascii_pbm     (PNMRowInfo *ri,
+                                        guchar     *data);
 static void   pnmsaverow_ascii_indexed (PNMRowInfo *ri,
                                         guchar     *data);
 static void   pnmsaverow_raw_indexed   (PNMRowInfo *ri,
@@ -262,6 +270,18 @@ query (void)
                           G_N_ELEMENTS (save_args), 0,
                           save_args, NULL);
 
+  gimp_install_procedure (PBM_SAVE_PROC,
+                          "saves files in the pnm file format",
+                          "PBM saving produces mono images without transparency.",
+                          "Martin K Collins",
+                          "Erik Nygren",
+                          "2006",
+                          N_("PBM image"),
+                          "RGB, GRAY, INDEXED",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (save_args), 0,
+                          save_args, NULL);
+
   gimp_install_procedure (PGM_SAVE_PROC,
                           "saves files in the pnm file format",
                           "PGM saving produces grayscale images without transparency.",
@@ -286,8 +306,10 @@ query (void)
                           G_N_ELEMENTS (save_args), 0,
                           save_args, NULL);
 
+  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_save_handler (PBM_SAVE_PROC, "pbm", "");
   gimp_register_save_handler (PGM_SAVE_PROC, "pgm", "");
   gimp_register_save_handler (PPM_SAVE_PROC, "ppm", "");
 }
@@ -305,6 +327,7 @@ run (const gchar      *name,
   gint32            image_ID;
   gint32            drawable_ID;
   GimpExportReturn  export = GIMP_EXPORT_CANCEL;
+  gboolean          pbm = FALSE;  /* flag for PBM output */
 
   run_mode = param[0].data.d_int32;
 
@@ -331,6 +354,7 @@ 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)
     {
@@ -348,6 +372,12 @@ run (const gchar      *name,
                                         (GIMP_EXPORT_CAN_HANDLE_RGB |
                                          GIMP_EXPORT_CAN_HANDLE_GRAY |
                                          GIMP_EXPORT_CAN_HANDLE_INDEXED));
+          else if (strcmp (name, PBM_SAVE_PROC) == 0)
+            {
+              export = gimp_export_image (&image_ID, &drawable_ID, "PBM",
+                                        (GIMP_EXPORT_CAN_HANDLE_BITMAP));
+              pbm = TRUE;  /* gimp has no mono image type so hack it */
+            }
           else if (strcmp (name, PGM_SAVE_PROC) == 0)
             export = gimp_export_image (&image_ID, &drawable_ID, "PGM",
                                         (GIMP_EXPORT_CAN_HANDLE_GRAY));
@@ -399,7 +429,7 @@ run (const gchar      *name,
 
       if (status == GIMP_PDB_SUCCESS)
         {
-          if (save_image (param[3].data.d_string, image_ID, drawable_ID))
+          if (save_image (param[3].data.d_string, image_ID, drawable_ID, pbm))
             {
               /*  Store psvals data  */
               gimp_set_data (name, &psvals, sizeof (PNMSaveVals));
@@ -716,6 +746,63 @@ pnm_load_rawpbm (PNMScanner   *scan,
   g_free (data);
 }
 
+/* Writes out mono raw rows */
+static void
+pnmsaverow_raw_pbm (PNMRowInfo *ri,
+                   guchar     *data)
+{
+  gint    b, i, p = 0;
+  gchar  *rbcur = ri->rowbuf;
+  gint32  len = (int)ceil ((double)(ri->xres)/8.0);
+
+  for (b = 0; b < len; b++) /* each output byte */
+    {
+      *(rbcur+b) = 0;
+      for (i = 0; i < 8; i++) /* each bit in this byte */
+        {
+          if (p >= ri->xres)
+              break;
+
+          if (*(data+p) == 0)
+              *(rbcur+b) |= (char) (1 << (7 - i));
+
+          p++;
+        }
+    }
+
+  write (ri->fd, ri->rowbuf, len);
+}
+
+/* Writes out mono ascii rows */
+static void
+pnmsaverow_ascii_pbm (PNMRowInfo *ri,
+                      guchar     *data)
+{
+  static gint  line_len = 0;  /* ascii pbm lines must be <= 70 chars long */   
+  gint32       len = 0;
+  gint         i;
+  gchar       *rbcur = ri->rowbuf;
+
+  for (i = 0; i < ri->xres; i++)
+    {
+      if (line_len > 69)
+        {
+          *(rbcur+i) = '\n';
+          line_len = 0;
+          len++;
+          rbcur++;
+        }
+      if (*(data+i) == 0)
+          *(rbcur+i) = '1';
+      else
+          *(rbcur+i) = '0';
+      line_len++;
+      len++;
+    }
+
+  write (ri->fd, ri->rowbuf, len);
+}
+
 /* Writes out RGB and greyscale raw rows */
 static void
 pnmsaverow_raw (PNMRowInfo *ri,
@@ -780,7 +867,8 @@ pnmsaverow_ascii_indexed (PNMRowInfo *ri
 static gboolean
 save_image (const gchar *filename,
             gint32       image_ID,
-            gint32       drawable_ID)
+            gint32       drawable_ID,
+            gboolean     pbm)
 {
   GimpPixelRgn   pixel_rgn;
   GimpDrawable  *drawable;
@@ -829,63 +917,87 @@ save_image (const gchar *filename,
 
   /* write out magic number */
   if (psvals.raw == FALSE)
-    switch (drawable_type)
-      {
-      case GIMP_GRAY_IMAGE:
-        write (fd, "P2\n", 3);
-        np = 1;
-        rowbufsize = xres * 4;
-        saverow = pnmsaverow_ascii;
-        break;
-
-      case GIMP_RGB_IMAGE:
-        write (fd, "P3\n", 3);
-        np = 3;
-        rowbufsize = xres * 12;
-        saverow = pnmsaverow_ascii;
-        break;
-
-      case GIMP_INDEXED_IMAGE:
-        write (fd, "P3\n", 3);
-        np = 1;
-        rowbufsize = xres * 12;
-        saverow = pnmsaverow_ascii_indexed;
-        break;
-
-      default:
-        g_warning ("pnm: unknown drawable_type\n");
-        return FALSE;
-      }
+    {
+      if (pbm)
+        {
+          write (fd, "P1\n", 3);
+          np = 0;
+          rowbufsize = xres + (int) (xres / 70) + 1;
+          saverow = pnmsaverow_ascii_pbm;
+        }
+      else
+        {
+          switch (drawable_type)
+            {
+              case GIMP_GRAY_IMAGE:
+                write (fd, "P2\n", 3);
+                np = 1;
+                rowbufsize = xres * 4;
+                saverow = pnmsaverow_ascii;
+                break;
+
+              case GIMP_RGB_IMAGE:
+                write (fd, "P3\n", 3);
+                np = 3;
+                rowbufsize = xres * 12;
+                saverow = pnmsaverow_ascii;
+                break;
+
+              case GIMP_INDEXED_IMAGE:
+                write (fd, "P3\n", 3);
+                np = 1;
+                rowbufsize = xres * 12;
+                saverow = pnmsaverow_ascii_indexed;
+                break;
+
+              default:
+                g_warning ("pnm: unknown drawable_type\n");
+                return FALSE;
+            }
+        }
+    }
   else if (psvals.raw == TRUE)
-    switch (drawable_type)
-      {
-      case GIMP_GRAY_IMAGE:
-        write (fd, "P5\n", 3);
-        np = 1;
-        rowbufsize = xres;
-        saverow = pnmsaverow_raw;
-        break;
-
-      case GIMP_RGB_IMAGE:
-        write (fd, "P6\n", 3);
-        np = 3;
-        rowbufsize = xres * 3;
-        saverow = pnmsaverow_raw;
-        break;
-
-      case GIMP_INDEXED_IMAGE:
-        write (fd, "P6\n", 3);
-        np = 1;
-        rowbufsize = xres * 3;
-        saverow = pnmsaverow_raw_indexed;
-        break;
-
-      default:
-        g_warning ("pnm: unknown drawable_type\n");
-        return FALSE;
+    {
+      if (pbm)
+        {
+          write (fd, "P4\n", 3);
+          np = 0;
+          rowbufsize = (int)ceil ((double)(xres)/8.0);
+          saverow = pnmsaverow_raw_pbm;
+        }
+      else
+        {
+            switch (drawable_type)
+              {
+              case GIMP_GRAY_IMAGE:
+                write (fd, "P5\n", 3);
+                np = 1;
+                rowbufsize = xres;
+                saverow = pnmsaverow_raw;
+                break;
+
+              case GIMP_RGB_IMAGE:
+                write (fd, "P6\n", 3);
+                np = 3;
+                rowbufsize = xres * 3;
+                saverow = pnmsaverow_raw;
+                break;
+
+              case GIMP_INDEXED_IMAGE:
+                write (fd, "P6\n", 3);
+                np = 1;
+                rowbufsize = xres * 3;
+                saverow = pnmsaverow_raw_indexed;
+                break;
+
+              default:
+                g_warning ("pnm: unknown drawable_type\n");
+                return FALSE;
+            }
+        }
     }
 
-  if (drawable_type == GIMP_INDEXED_IMAGE)
+  if (drawable_type == GIMP_INDEXED_IMAGE && !pbm)
     {
       gint    i;
       guchar *cmap;
@@ -912,7 +1024,10 @@ save_image (const gchar *filename,
   write (fd, SAVE_COMMENT_STRING, strlen (SAVE_COMMENT_STRING));
 
   /* write out resolution and maxval */
-  sprintf (buf, "%d %d\n255\n", xres, yres);
+  if (pbm)
+      sprintf (buf, "%d %d\n", xres, yres);
+  else
+      sprintf (buf, "%d %d\n255\n", xres, yres);
   write (fd, buf, strlen(buf));
 
   rowbuf = g_new (gchar, rowbufsize + 1);
@@ -936,7 +1051,7 @@ save_image (const gchar *filename,
         }
 
       (*saverow)(&rowinfo, d);
-      d += xres*np;
+      d += xres * (np ? np : 1);
 
       if ((ypos % 20) == 0)
         gimp_progress_update ((double) ypos / (double) yres);
