about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-02 03:34:17 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-02 03:34:17 +0000
commitfd4df4062a13889503c81c002576159ea6316234 (patch)
tree6a93fae22b921d9f1fe00fbc8798a8db5a8a0bcc
parent30666679a17b447cfc80a141ac70e8d6ba2853d6 (diff)
downloadnetpbm-mirror-fd4df4062a13889503c81c002576159ea6316234.tar.gz
netpbm-mirror-fd4df4062a13889503c81c002576159ea6316234.tar.xz
netpbm-mirror-fd4df4062a13889503c81c002576159ea6316234.zip
check for inconsistencies between specified width and height and size of input
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1921 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--converter/ppm/yuvtoppm.c255
-rw-r--r--doc/HISTORY3
2 files changed, 183 insertions, 75 deletions
diff --git a/converter/ppm/yuvtoppm.c b/converter/ppm/yuvtoppm.c
index 2b44c65f..151ff9f9 100644
--- a/converter/ppm/yuvtoppm.c
+++ b/converter/ppm/yuvtoppm.c
@@ -20,96 +20,201 @@
 ** implied warranty.
 */
 
-#include "ppm.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include "ppm.h"
 
-/* x must be signed for the following to work correctly */
-#define limit(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
 
-int
-main(argc, argv)
-	char          **argv;
-{
-	FILE           *ifp;
-	pixel          *pixrow;
-	int             argn, rows, cols, row;
-	const char     * const usage = "<width> <height> [yuvfile]";
-    struct yuv {
-        /* This is an element of a YUV file.  It describes two 
-           side-by-side pixels.
-        */
-        unsigned char u;
-        unsigned char y1;
-        unsigned char v;
-        unsigned char y2;
-    } *yuvbuf;
-
-	ppm_init(&argc, argv);
-
-	argn = 1;
-
-	if (argn + 2 > argc)
-		pm_usage(usage);
-
-	cols = atoi(argv[argn++]);
-	rows = atoi(argv[argn++]);
-	if (cols <= 0 || rows <= 0)
-		pm_usage(usage);
-
-	if (argn < argc) {
-		ifp = pm_openr(argv[argn]);
-		++argn;
-	} else
-		ifp = stdin;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-    if (cols % 2 != 0) {
-        pm_error("Number of columns (%d) is odd.  A YUV image must have an "
-                 "even number of columns.", cols);
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int cols;
+    unsigned int rows;
+    const char * inputFileName;  /* Name of input file */
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options */
+    optStruct3 opt;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    OPTENTINIT;
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 2)
+        pm_error("You need at least two arguments: width and height in "
+                 "pixels.  You specified %u", argc-1);
+    else {
+        int const widthArg  = atoi(argv[1]);
+        int const heightArg = atoi(argv[2]);
+
+        if (widthArg < 0)
+            pm_error("Negative number for width: %d", widthArg);
+        if (heightArg < 0)
+            pm_error("Negative number for height: %d", heightArg);
+
+        cmdlineP->cols = widthArg;
+        cmdlineP->rows = heightArg;
+                 
+        if (cmdlineP->cols % 2 != 0)
+            pm_error("Number of columns (%u) is odd.  "
+                     "A YUV image must have an "
+                     "even number of columns.", cmdlineP->cols);
+
+        if (argc-1 < 3)
+            cmdlineP->inputFileName = "-";
+        else {
+            cmdlineP->inputFileName = argv[3];
+
+            if (argc-1 > 3)
+                pm_error("Too many arguments: %u.  "
+                         "The only possible arguments are "
+                         "width, height, and input file name", argc-1);
+        }
     }
+}
 
-	ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0);
-	pixrow = ppm_allocrow(cols);
-    MALLOCARRAY(yuvbuf, (cols+1)/2);
-    if (yuvbuf == NULL)
-        pm_error("Unable to allocate YUV buffer for %d columns.", cols);
 
-	for (row = 0; row < rows; ++row) {
-		int    col;
 
-		fread(yuvbuf, cols * 2, 1, ifp);
+static int
+limit(int const x) {
 
-		for (col = 0; col < cols; col += 2) {
-            /* Produce two pixels in pixrow[] */
-            int y1, u, v, y2, r, g, b;
+    if (x > 0xffffff)
+        return 0xff;
+    else if (x <= 0xffff)
+        return 0;
+    else
+        return ((x >> 16) & 0xff);
+}
+
+
+
+static int
+nonneg(int const x) {
+/*----------------------------------------------------------------------------
+  Raise 'x' to 0 if negative
+-----------------------------------------------------------------------------*/
+    return x < 0 ? 0 : x;
+}
+
+
+
+struct Yuv {
+/*----------------------------------------------------------------------------
+  This is an element of a YUV file.  It describes two side-by-side pixels.
+
+  This is the actual layout of the data in the file (4 bytes).
+-----------------------------------------------------------------------------*/
+    unsigned char u;
+    unsigned char y1;
+    unsigned char v;
+    unsigned char y2;
+};
 
-			u = yuvbuf[col/2].u-128;
 
-            y1 = yuvbuf[col/2].y1 - 16;
-			if (y1 < 0) y1 = 0;
 
-            v = yuvbuf[col/2].v - 128;
+static void
+readYuv(FILE *       const ifP,
+        struct Yuv * const yuvP) {
 
-            y2 = yuvbuf[col/2].y2 - 16;
-			if (y2 < 0) y2 = 0;
+    size_t readCt;
 
-			r = 104635 * v;
-			g = -25690 * u + -53294 * v;
-			b = 132278 * u;
+    readCt = fread(yuvP, sizeof(*yuvP), 1, ifP);
 
-			y1*=76310; y2*=76310;
+    if (readCt != 1) {
+        if (feof(ifP))
+            pm_error("Premature end of input.");
+        else
+            pm_error("Error reading input.");
+    }
+}
+
+
+
+static void
+yuvtoppm(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         FILE *       const ofP) {
+
+    pixval const maxval = 255;
+
+    pixel * pixrow;
+    unsigned int row;
+
+    ppm_writeppminit(ofP, cols, rows, maxval, 0);
+
+    pixrow = ppm_allocrow(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; col += 2) {
+            /* Produce two pixels in pixrow[] */
+            struct Yuv yuv;
+            int     y1, u, v, y2, r, g, b;
+
+            readYuv(ifP, &yuv);
+
+            u = yuv.u - 128;
+            y1 = nonneg (yuv.y1 - 16);
+            v = yuv.v - 128;
+            y2 = nonneg (yuv.y2 - 16);
+
+            r = 104635 * v;
+            g = -25690 * u + -53294 * v;
+            b = 132278 * u;
+
+            y1 *= 76310;
+            y2 *= 76310;
+
+            PPM_ASSIGN(pixrow[col],
+                       limit(r + y1), limit(g + y1), limit(b + y1));
+            PPM_ASSIGN(pixrow[col + 1],
+                       limit(r + y2), limit(g + y2), limit(b + y2));
+        }
+        ppm_writeppmrow(ofP, pixrow, cols, maxval, 0);
+    }
 
-			PPM_ASSIGN(pixrow[col], limit(r+y1), limit(g+y1), limit(b+y1));
-			PPM_ASSIGN(pixrow[col+1], limit(r+y2), limit(g+y2), limit(b+y2));
-		}
-		ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0);
-	}
-    free(yuvbuf);
     ppm_freerow(pixrow);
-	pm_close(ifp);
-	pm_close(stdout);
 
-	exit(0);
+    if (fgetc(ifP) != EOF)
+        pm_message("Extraneous data at end of image.");
+}
+
+
+
+int
+main (int argc, const char ** argv) {
+
+    FILE * ifP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    yuvtoppm(ifP, cmdline.cols, cmdline.rows, stdout);
+    
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
 }
diff --git a/doc/HISTORY b/doc/HISTORY
index fbcfb122..c512bab4 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -12,6 +12,9 @@ not yet  BJH  Release 10.63.00
               Perl programs: make them shell programs that reinvoke themselves
               as perl so we can get the Perl interpreter from the PATH.
 
+              yuvtoppm: check for inconsistencies between specified
+              width and height and size of input.
+
               pnmtops: Fix bug: only first image gets converted.  Broken in
               Netpbm 10.56 (September 2011).