]> git.imager.perl.org - imager.git/blobdiff - pnm.c
- explicitly document there are no PNG specific tags.
[imager.git] / pnm.c
diff --git a/pnm.c b/pnm.c
index b7796a67330712ddb4fc65cdd09647592cc9fa4e..148b887ba7df4731f8bdd543a2050fe5234ab64a 100644 (file)
--- a/pnm.c
+++ b/pnm.c
@@ -1,8 +1,9 @@
 #include "image.h"
-#include "io.h"
 #include "log.h"
+#include "iolayer.h"
 
 #include <stdlib.h>
+#include <errno.h>
 
 
 /*
@@ -28,7 +29,7 @@ or an entire memory mapped buffer.
 
 Some of these functions are internal.
 
-=over 4
+=over
 
 =cut
 */
@@ -81,10 +82,12 @@ gnext(mbuf *mb) {
     mb->cp = 0;
     mb->len = ig->readcb(ig, mb->buf, BSIZ);
     if (mb->len == -1) {
+      i_push_error(errno, "file read error");
       mm_log((1, "i_readpnm: read error\n"));
       return NULL;
     }
     if (mb->len == 0) {
+      i_push_error(errno, "unexpected end of file");
       mm_log((1, "i_readpnm: end of file\n"));
       return NULL;
     }
@@ -112,10 +115,12 @@ gpeek(mbuf *mb) {
     mb->cp = 0;
     mb->len = ig->readcb(ig, mb->buf, BSIZ);
     if (mb->len == -1) {
+      i_push_error(errno, "read error");
       mm_log((1, "i_readpnm: read error\n"));
       return NULL;
     }
     if (mb->len == 0) {
+      i_push_error(0, "unexpected end of file");
       mm_log((1, "i_readpnm: end of file\n"));
       return NULL;
     }
@@ -223,11 +228,13 @@ i_readpnm_wiol(io_glue *ig, int length) {
   int type;
   int x, y, ch;
   int width, height, maxval, channels, pcount;
+  int rounder;
   char *cp;
   unsigned char *uc;
   mbuf buf;
   i_color val;
-  int mult;
+
+  i_clear_error();
 
   /*  char *pp; */
 
@@ -253,6 +260,7 @@ i_readpnm_wiol(io_glue *ig, int length) {
   cp = gnext(&buf);
 
   if (!cp || *cp != 'P') {
+    i_push_error(0, "bad header magic, not a PNM file");
     mm_log((1, "i_readpnm: Could not read header of file\n"));
     return NULL;
   }
@@ -265,6 +273,7 @@ i_readpnm_wiol(io_glue *ig, int length) {
   type = *cp-'0';
 
   if (type < 1 || type > 6) {
+    i_push_error(0, "unknown PNM file type, not a PNM file");
     mm_log((1, "i_readpnm: Not a pnm file\n"));
     return NULL;
   }
@@ -275,6 +284,7 @@ i_readpnm_wiol(io_glue *ig, int length) {
   }
   
   if ( !misspace(*cp) ) {
+    i_push_error(0, "unexpected character, not a PNM file");
     mm_log((1, "i_readpnm: Not a pnm file\n"));
     return NULL;
   }
@@ -285,38 +295,63 @@ i_readpnm_wiol(io_glue *ig, int length) {
   /* Read sizes and such */
 
   if (!skip_comment(&buf)) {
+    i_push_error(0, "while skipping to width");
     mm_log((1, "i_readpnm: error reading before width\n"));
     return NULL;
   }
   
   if (!gnum(&buf, &width)) {
+    i_push_error(0, "could not read image width");
     mm_log((1, "i_readpnm: error reading width\n"));
     return NULL;
   }
 
   if (!skip_comment(&buf)) {
+    i_push_error(0, "while skipping to height");
     mm_log((1, "i_readpnm: error reading before height\n"));
     return NULL;
   }
 
   if (!gnum(&buf, &height)) {
+    i_push_error(0, "could not read image height");
     mm_log((1, "i_readpnm: error reading height\n"));
     return NULL;
   }
   
   if (!(type == 1 || type == 4)) {
     if (!skip_comment(&buf)) {
+      i_push_error(0, "while skipping to maxval");
       mm_log((1, "i_readpnm: error reading before maxval\n"));
       return NULL;
     }
 
     if (!gnum(&buf, &maxval)) {
+      i_push_error(0, "could not read maxval");
       mm_log((1, "i_readpnm: error reading maxval\n"));
       return NULL;
     }
+
+    if (maxval == 0) {
+      i_push_error(0, "maxval is zero - invalid pnm file");
+      mm_log((1, "i_readpnm: maxval is zero, invalid pnm file\n"));
+      return NULL;
+    }
+    else if (maxval > 65535) {
+      i_push_errorf(0, "maxval of %d is over 65535 - invalid pnm file", 
+                   maxval);
+      mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n"));
+      return NULL;
+    }
+    else if (type >= 4 && maxval > 255) {
+      i_push_errorf(0, "maxval of %d is over 255 - not currently supported by Imager for binary pnm", maxval);
+      mm_log((1, "i_readpnm: maxval of %d is over 255 - not currently supported by Imager for binary pnm\n", maxval));
+      return NULL;
+    }
   } else maxval=1;
+  rounder = maxval / 2;
 
   if (!(cp = gnext(&buf)) || !misspace(*cp)) {
+    i_push_error(0, "garbage in header, invalid PNM file");
     mm_log((1, "i_readpnm: garbage in header\n"));
     return NULL;
   }
@@ -328,15 +363,16 @@ i_readpnm_wiol(io_glue *ig, int length) {
   
   im = i_img_empty_ch(NULL, width, height, channels);
 
+  i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0);
+
   switch (type) {
   case 1: /* Ascii types */
   case 2:
   case 3:
-    mult = type == 1 ? 255 : 1;
     for(y=0;y<height;y++) for(x=0; x<width; x++) {
       for(ch=0; ch<channels; ch++) {
        int t;
-       if (gnum(&buf, &t)) val.channel[ch] = t;
+       if (gnum(&buf, &t)) val.channel[ch] = (t * 255 + rounder) / maxval;
        else {
          mm_log((1,"i_readpnm: gnum() returned false in data\n"));
          return im;
@@ -348,7 +384,7 @@ i_readpnm_wiol(io_glue *ig, int length) {
     
   case 4: /* binary pbm */
     for(y=0;y<height;y++) for(x=0; x<width; x+=8) {
-      if ( (uc = gnext(&buf)) ) {
+      if ( (uc = (unsigned char*)gnext(&buf)) ) {
        int xt;
        int pc = width-x < 8 ? width-x : 8;
        /*      mm_log((1,"i_readpnm: y=%d x=%d pc=%d\n", y, x, pc)); */
@@ -367,7 +403,8 @@ i_readpnm_wiol(io_glue *ig, int length) {
   case 6: /* binary ppm */
     for(y=0;y<height;y++) for(x=0; x<width; x++) {
       for(ch=0; ch<channels; ch++) {
-       if ( (uc = gnext(&buf)) ) val.channel[ch] = *uc;
+       if ( (uc = (unsigned char*)gnext(&buf)) ) 
+         val.channel[ch] = (*uc * 255 + rounder) / maxval;
        else {
          mm_log((1,"i_readpnm: gnext() returned false in data\n"));
          return im;
@@ -383,35 +420,118 @@ i_readpnm_wiol(io_glue *ig, int length) {
   return im;
 }
 
+
 undef_int
-i_writeppm(i_img *im,int fd) {
+i_writeppm_wiol(i_img *im, io_glue *ig) {
   char header[255];
   int rc;
+  writep write_func;
 
-  mm_log((1,"i_writeppm(im* 0x%x,fd %d)\n",im,fd));
-  if (im->channels!=3) {
-    mm_log((1,"i_writeppm: ppm is 3 channel only (current image is %d)\n",im->channels));
-    return(0);
+  mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig));
+  i_clear_error();
+
+  /* Add code to get the filename info from the iolayer */
+  /* Also add code to check for mmapped code */
+
+  io_glue_commit_types(ig);
+
+  if (im->channels == 3) {
+    sprintf(header,"P6\n#CREATOR: Imager\n%d %d\n255\n",im->xsize,im->ysize);
+    if (ig->writecb(ig,header,strlen(header))<0) {
+      i_push_error(errno, "could not write ppm header");
+      mm_log((1,"i_writeppm: unable to write ppm header.\n"));
+      return(0);
+    }
+
+    if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
+      rc = ig->writecb(ig,im->idata,im->bytes);
+    }
+    else {
+      unsigned char *data = mymalloc(3 * im->xsize);
+      if (data != NULL) {
+        int y = 0;
+        int x, ch;
+        unsigned char *p;
+        static int rgb_chan[3] = { 0, 1, 2 };
+
+        rc = 0;
+        while (y < im->ysize && rc >= 0) {
+          i_gsamp(im, 0, im->xsize, y, data, rgb_chan, 3);
+          rc = ig->writecb(ig, data, im->xsize * 3);
+          ++y;
+        }
+        myfree(data);
+      }
+      else {
+        i_push_error(0, "Out of memory");
+        return 0;
+      }
+    }
+    if (rc<0) {
+      i_push_error(errno, "could not write ppm data");
+      mm_log((1,"i_writeppm: unable to write ppm data.\n"));
+      return(0);
+    }
   }
-  
-  sprintf(header,"P6\n#CREATOR: Imager\n%d %d\n255\n",im->xsize,im->ysize);
-  
-  if (mywrite(fd,header,strlen(header))<0) {
-    mm_log((1,"i_writeppm: unable to write ppm header.\n"));
-    return(0);
+  else if (im->channels == 1) {
+    sprintf(header, "P5\n#CREATOR: Imager\n%d %d\n255\n",
+           im->xsize, im->ysize);
+    if (ig->writecb(ig,header, strlen(header)) < 0) {
+      i_push_error(errno, "could not write pgm header");
+      mm_log((1,"i_writeppm: unable to write pgm header.\n"));
+      return(0);
+    }
+
+    if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
+      rc=ig->writecb(ig,im->idata,im->bytes);
+    }
+    else {
+      unsigned char *data = mymalloc(im->xsize);
+      if (data != NULL) {
+        int y = 0;
+        int x, ch;
+        int chan = 0;
+        unsigned char *p;
+
+        rc = 0;
+        while (y < im->ysize && rc >= 0) {
+          i_gsamp(im, 0, im->xsize, y, data, &chan, 1);
+          rc = ig->writecb(ig, data, im->xsize);
+          ++y;
+        }
+        myfree(data);
+      }
+      else {
+        i_push_error(0, "Out of memory");
+        return 0;
+      }
+    }
+    if (rc<0) {
+      i_push_error(errno, "could not write pgm data");
+      mm_log((1,"i_writeppm: unable to write pgm data.\n"));
+      return(0);
+    }
   }
-  
-  rc=mywrite(fd,im->data,im->bytes);
-  if (rc<0) {
-    mm_log((1,"i_writeppm: unable to write ppm data.\n"));
+  else {
+    i_push_error(0, "can only save 1 or 3 channel images to pnm");
+    mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));
     return(0);
   }
+  ig->closecb(ig);
+
   return(1);
 }
 
+/*
+=back
 
+=head1 AUTHOR
 
+Arnar M. Hrafnkelsson <addi@umich.edu>
 
+=head1 SEE ALSO
 
+Imager(3)
 
-
+=cut
+*/