about summary refs log tree commit diff
path: root/lib/libpgm2.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /lib/libpgm2.c
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libpgm2.c')
-rw-r--r--lib/libpgm2.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/lib/libpgm2.c b/lib/libpgm2.c
new file mode 100644
index 00000000..7a04f09b
--- /dev/null
+++ b/lib/libpgm2.c
@@ -0,0 +1,226 @@
+/* libpgm2.c - pgm utility library part 2
+**
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <string.h>
+#include <errno.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pgm.h"
+#include "libpgm.h"
+
+
+
+void
+pgm_writepgminit(FILE * const fileP, 
+                 int    const cols, 
+                 int    const rows, 
+                 gray   const maxval, 
+                 int    const forceplain) {
+
+    bool const plainFormat = forceplain || pm_plain_output;
+
+    if (maxval > PGM_OVERALLMAXVAL && !plainFormat) 
+        pm_error("too-large maxval passed to ppm_writepgminit(): %d.\n"
+                 "Maximum allowed by the PGM format is %d.",
+                 maxval, PGM_OVERALLMAXVAL);
+
+    fprintf(fileP, "%c%c\n%d %d\n%d\n", 
+            PGM_MAGIC1, 
+            plainFormat || maxval >= 1<<16 ? PGM_MAGIC2 : RPGM_MAGIC2, 
+            cols, rows, maxval );
+#ifdef VMS
+    if (!plainFormat)
+        set_outfile_binary();
+#endif
+}
+
+
+
+static void
+putus(unsigned short const n, 
+      FILE *         const fileP) {
+
+    if (n >= 10)
+        putus(n / 10, fileP);
+    putc('0' + n % 10, fileP);
+}
+
+
+
+void
+pgm_writerawsample(FILE * const fileP,
+                   gray   const val,
+                   gray   const maxval) {
+
+    if (maxval < 256) {
+        /* Samples fit in one byte, so write just one byte */
+        int rc;
+        rc = putc(val, fileP);
+        if (rc == EOF)
+            pm_error("Error writing single byte sample to file");
+    } else {
+        /* Samples are too big for one byte, so write two */
+        int n_written;
+        unsigned char outval[2];
+        /* We could save a few instructions if we exploited the internal
+           format of a gray, i.e. its endianness.  Then we might be able
+           to skip the shifting and anding.
+           */
+        outval[0] = val >> 8;
+        outval[1] = val & 0xFF;
+        n_written = fwrite(&outval, 2, 1, fileP);
+        if (n_written == 0) 
+            pm_error("Error writing double byte sample to file");
+    }
+}
+
+
+
+static void
+format1bpsRow(const gray *    const grayrow,
+              unsigned int    const cols,
+              unsigned char * const rowBuffer) {
+
+    /* single byte samples. */
+
+    unsigned int col;
+    unsigned int bufferCursor;
+
+    bufferCursor = 0;
+
+    for (col = 0; col < cols; ++col)
+        rowBuffer[bufferCursor++] = grayrow[col];
+}
+
+
+
+
+static void
+format2bpsRow(const gray    * const grayrow,
+              unsigned int    const cols,
+              unsigned char * const rowBuffer) {
+
+    /* two byte samples. */
+
+    unsigned int col;
+    unsigned int bufferCursor;
+
+    bufferCursor = 0;
+
+    for (col = 0; col < cols; ++col) {
+        gray const val = grayrow[col];
+        
+        rowBuffer[bufferCursor++] = val >> 8;
+        rowBuffer[bufferCursor++] = (unsigned char) val;
+    }
+}
+
+
+
+static void
+writepgmrowraw(FILE *       const fileP,
+               const gray * const grayrow,
+               unsigned int const cols,
+               gray         const maxval) {
+
+    unsigned int const bytesPerSample = maxval < 256 ? 1 : 2;
+    unsigned int const bytesPerRow    = cols * bytesPerSample;
+
+    unsigned char * rowBuffer;
+    ssize_t rc;
+
+    MALLOCARRAY(rowBuffer, bytesPerRow);
+
+    if (rowBuffer == NULL)
+        pm_error("Unable to allocate memory for row buffer "
+                 "for %u columns", cols);
+
+    if (maxval < 256)
+        format1bpsRow(grayrow, cols, rowBuffer);
+    else
+        format2bpsRow(grayrow, cols, rowBuffer);
+
+    rc = fwrite(rowBuffer, 1, bytesPerRow, fileP);
+
+    if (rc < 0)
+        pm_error("Error writing row.  fwrite() errno=%d (%s)",
+                 errno, strerror(errno));
+    else if (rc != bytesPerRow)
+        pm_error("Error writing row.  Short write of %u bytes "
+                 "instead of %u", rc, bytesPerRow);
+
+    free(rowBuffer);
+}
+
+
+
+static void
+writepgmrowplain(FILE *       const fileP,
+                 const gray * const grayrow, 
+                 unsigned int const cols, 
+                 gray         const maxval) {
+
+    int col, charcount;
+
+    charcount = 0;
+    for (col = 0; col < cols; ++col) {
+        if (charcount >= 65) {
+            putc('\n', fileP);
+            charcount = 0;
+        } else if (charcount > 0) {
+            putc(' ', fileP);
+            ++charcount;
+        }
+#ifdef DEBUG
+        if (grayrow[col] > maxval)
+            pm_error("value out of bounds (%u > %u)", grayrow[col], maxval);
+#endif /*DEBUG*/
+        putus((unsigned short)grayrow[col], fileP);
+        charcount += 3;
+    }
+    if (charcount > 0)
+        putc('\n', fileP);
+}
+
+
+
+void
+pgm_writepgmrow(FILE *       const fileP, 
+                const gray * const grayrow, 
+                int          const cols, 
+                gray         const maxval, 
+                int          const forceplain) {
+
+    if (forceplain || pm_plain_output || maxval >= 1<<16)
+        writepgmrowplain(fileP, grayrow, cols, maxval);
+    else
+        writepgmrowraw(fileP, grayrow, cols, maxval);
+}
+
+
+
+void
+pgm_writepgm(FILE *  const fileP,
+             gray ** const grays,
+             int     const cols,
+             int     const rows,
+             gray    const maxval,
+             int     const forceplain) {
+
+    unsigned int row;
+
+    pgm_writepgminit(fileP, cols, rows, maxval, forceplain);
+
+    for (row = 0; row < rows; ++row)
+        pgm_writepgmrow(fileP, grays[row], cols, maxval, forceplain);
+}