Revision: 76094
          http://sourceforge.net/p/brlcad/code/76094
Author:   starseeker
Date:     2020-06-09 20:54:40 +0000 (Tue, 09 Jun 2020)
Log Message:
-----------
Consolidate halftone into a single file and move it to src/util

Modified Paths:
--------------
    brlcad/trunk/src/CMakeLists.txt
    brlcad/trunk/src/util/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/src/util/halftone.c

Removed Paths:
-------------
    brlcad/trunk/src/halftone/

Modified: brlcad/trunk/src/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/CMakeLists.txt     2020-06-09 20:31:44 UTC (rev 76093)
+++ brlcad/trunk/src/CMakeLists.txt     2020-06-09 20:54:40 UTC (rev 76094)
@@ -65,7 +65,6 @@
   fb
   fbserv
   gtools
-  halftone
   nirt
   proc-db
   rt

Modified: brlcad/trunk/src/util/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/util/CMakeLists.txt        2020-06-09 20:31:44 UTC (rev 
76093)
+++ brlcad/trunk/src/util/CMakeLists.txt        2020-06-09 20:54:40 UTC (rev 
76094)
@@ -67,6 +67,7 @@
 BRLCAD_ADDEXEC(double-asc double-asc.c "libfb;libbu")
 BRLCAD_ADDEXEC(dpix-pix dpix-pix.c libbu)
 BRLCAD_ADDEXEC(gencolor gencolor.c libbu)
+BRLCAD_ADDEXEC(halftone2 halftone.c "librt;libfb;libbu")
 
 # This is intended to replace all of the img-img utils eventually
 BRLCAD_ADDEXEC(icv icv.cpp "libicv;libbu")

Added: brlcad/trunk/src/util/halftone.c
===================================================================
--- brlcad/trunk/src/util/halftone.c                            (rev 0)
+++ brlcad/trunk/src/util/halftone.c    2020-06-09 20:54:40 UTC (rev 76094)
@@ -0,0 +1,1026 @@
+/*                      H A L F T O N E . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2004-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file halftone.c
+ *
+ * given a bw file, generate a ht file.
+ *
+ * Usage:
+ *     halftone
+ *             -s      square size
+ *             -n      number of lines
+ *             -w      width
+ *             -a      Automatic bw file sizing.
+ *             -B      Beta for sharpening
+ *             -I      number of intensity levels
+ *             -M      method
+ *                     0 Floyd-Steinberg
+ *                     1 45-degree classical halftone screen
+ *                     2 Threshold
+ *                     3 0-degree dispersed halftone screen
+ *             -R      Add some noise.
+ *             -S      Surpent flag (set back to 0 if method is not 
Floyd-Steinberg)
+ *             -T      tonescale points
+ *             -D      debug level
+ *
+ * Exit:
+ *     writes a ht(bw) file.
+ *             an ht file is a bw file with a limited set of values
+ *             ranging from 0 to -I(n) as integers.
+ *
+ * Uses:
+ *     None.
+ *
+ * Calls:
+ *     sharpen()       - get a line from the file that has been sharpened
+ *     tone_simple()   - Threshold halftone.
+ *     tone_floyd()    - Floyd-Steinberg halftone.
+ *     tone_folly()    - 0 degree halftone screen (from Folly and Van Dam)
+ *     tone_classic()  - 45 degree classical halftone screen.
+ *     tonescale()     - Generates a tone scale map default is 0, 0 to 255, 255
+ *     cubic_init()    - Generates "cubics" for tonescale for a set of points.
+ *
+ * Method:
+ *     Fairly simple.  Most of the algorithms are inspired by
+ *             Digital Halftoning by Robert Ulichney
+ *
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "bio.h"
+
+#include "bu/app.h"
+#include "bu/exit.h"
+#include "bu/getopt.h"
+#include "vmath.h"
+#include "raytrace.h"
+#include "fb.h"
+
+#define        DLEVEL  1
+#define THRESHOLD      127
+
+long int width=512;    /* width of picture */
+long int height=512;   /* height of picture */
+double Beta=0.0;       /* Beta for sharpening */
+
+#define        M_FLOYD 0
+#define        M_CLASSIC 1
+#define        M_THRESH 2
+#define        M_FOLLY 3
+int Method=M_FLOYD;    /* Method of halftoning */
+
+int Surpent=0;         /* use serpentine scan lines */
+int Levels=1;          /* Number of levels */
+int Debug=0;
+struct bn_unif *RandomFlag=0;  /* Use random numbers ? */
+
+#if 0
+void cubic_init(int n, int *x, int *y);
+void tonescale(unsigned char *map, float Slope, float B, int (*eqptr)() );
+int sharpen(unsigned char *buf, int size, int num, FILE *file, unsigned char 
*Map);
+int tone_floyd(int pix, int x, int y, int nx, int ny, int newrow);
+int tone_folly(int pix, int x, int y, int nx, int ny, int newrow);
+int tone_simple(int pix, int x, int y, int nx, int ny, int newrow);
+int tone_classic(int pix, int x, int y, int nx, int ny, int newrow);
+#endif
+
+
+/**
+ * return a sharpened tone mapped buffer.
+ *
+ * Entry:
+ *     buf     - buffer to place bytes.
+ *     size    - size of element
+ *     num     - number of elements to read.
+ *     file    - file to read from.
+ *     Map     - tone scale mapping.
+ *
+ * Exit:
+ *     returns 0 on EOF
+ *             number of byes read otherwise.
+ *
+ * Uses:
+ *     Debug   - Current debug level.
+ *     Beta    - sharpening value.
+ *
+ * Calls:
+ *     None.
+ *
+ * Method:
+ *     if no sharpening just read a line tone scale and return.
+ *     if first time called get space for processing and do setup.
+ *     if first line then
+ *             only use cur and next lines
+ *     else if last line then
+ *             only use cur and last lines
+ *     else
+ *             use last cur and next lines
+ *     endif
+ *
+ */
+int
+sharpen(unsigned char *buf, int size, int num, FILE *file, unsigned char *Map)
+{
+    static unsigned char *last, *cur=0, *next;
+    static int linelen;
+    size_t result;
+    int newvalue;
+    int i, value;
+    int idx;
+
+/*
+ *     if no sharpening going on then just read from the file and exit.
+ */
+    if (ZERO(Beta)) {
+       result = fread(buf, size, num, file);
+       if (!result)
+           return result;
+       for (i=0; i<size*num; i++) {
+           idx = buf[i];
+           CLAMP(idx, 0, size*num);
+           buf[i] = Map[idx];
+       }
+       return result;
+    }
+
+/*
+ *     if we are sharpening we depend on the pixel size being one char.
+ */
+    if (size != 1) {
+       fprintf(stderr, "sharpen: size != 1.\n");
+       bu_exit(2, NULL);
+    }
+
+/*
+ *     if this is the first time we have been called then get some
+ *     space to load pixels into and read first and second line of
+ *     the file.
+ */
+    if (!cur) {
+       linelen=num;
+       last = 0;
+       cur  = (unsigned char *)malloc(linelen);
+       next = (unsigned char *)malloc(linelen);
+       result = fread(cur, 1, linelen, file);
+       for (i=0; i<linelen;i++) {
+           idx = cur[i];
+           CLAMP(idx, 0, size*num);
+           cur[i] = Map[idx];
+       }
+       if (!result)
+           return result;      /* nothing there! */
+       result = fread(next, 1, linelen, file);
+       if (!result) {
+           free(next);
+           next = 0;
+       } else {
+           for (i=0; i<linelen;i++) {
+               idx = cur[i];
+               CLAMP(idx, 0, size*num);
+               cur[i] = Map[idx];
+           }
+       }
+    } else {
+       unsigned char *tmp;
+
+       if (linelen != num) {
+           fprintf(stderr, "sharpen: buffer size changed!\n");
+           bu_exit(2, NULL);
+       }
+/*
+ *             rotate the buffers.
+ */
+       tmp=last;
+       last=cur;
+       cur=next;
+       next=tmp;
+       result=fread(next, 1, linelen, file);
+/*
+ *             if at EOF then free up a buffer and set next to NULL
+ *             to flag EOF for the next time we are called.
+ */
+       if (!result) {
+           free(next);
+           next = 0;
+       } else {
+           for (i=0; i<linelen;i++) {
+               idx = cur[i];
+               CLAMP(idx, 0, size*num);
+               cur[i] = Map[idx];
+           }
+       }
+    }
+/*
+ *     if cur is NULL then we are at EOF.  Memory leak here as
+ *     we don't free last.
+ */
+    if (!cur) return 0;
+
+/*
+ * Value is the following Laplacian filter kernel:
+ *             0.25
+ *     0.25    -1.0    0.25
+ *             0.25
+ *
+ * Thus value is zero in constant value areas and none zero on
+ * edges.
+ *
+ * Page 335 of Digital Halftoning defines
+ *     J     [n] = J[n] - Beta*Laplacian_filter[n]*J[n]
+ *      sharp
+ *
+ * J, J, Laplacian_filter[n] are all in the range 0.0 to 1.0
+ *     sharp
+ *
+ * The following is done in mostly integer mode, there is only one
+ * floating point multiply done.
+ */
+
+/*
+ *     if first line
+ */
+    if (!last) {
+       i=0;
+       value=next[i] + cur[i+1] - cur[i]*2;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*2);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+       for (; i < linelen-1; i++) {
+           value = next[i] + cur[i-1] + cur[i+1] - cur[i]*3;
+           newvalue = cur[i] - Beta*value*((int)cur[i])/(255*3);
+           buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+               255: newvalue;
+       }
+       value=next[i] + cur[i-1] - cur[i]*2;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*2);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+
+/*
+ *             first time through so we will need this buffer space
+ *             the next time through.
+ */
+       last  = (unsigned char *)malloc(linelen);
+/*
+ *     if last line
+ */
+    } else if (!next) {
+       i=0;
+       value=last[i] + cur[i+1] - cur[i]*2;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*2);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+       for (; i < linelen-1; i++) {
+           value = last[i] + cur[i-1] + cur[i+1] - cur[i]*3;
+           newvalue = cur[i] - Beta*value*((int)cur[i])/(255*3);
+           buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+               255: newvalue;
+       }
+       value=last[i] + cur[i-1] - cur[i]*2;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*2);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+/*
+ *     all other lines.
+ */
+    } else {
+       i=0;
+       value=last[i] + next[i] + cur[i+1] - cur[i]*3;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*3);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+       for (; i < linelen-1; i++) {
+           value = last[i] + next[i] + cur[i-1] + cur[i+1]
+               - cur[i]*4;
+           newvalue = cur[i] - Beta*value*((int)cur[i])/(255*4);
+           buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+               255: newvalue;
+       }
+       value=last[i] + next[i] + cur[i-1] - cur[i]*3;
+       newvalue = cur[i] - Beta*value*((int)cur[i])/(255*3);
+       buf[i] = (newvalue < 0) ? 0 : (newvalue > 255) ?
+           255: newvalue;
+    }
+    return linelen;
+}
+
+/*
+ * Clustered-Dot ordered dither at 45 degrees.
+ *     Page 86 of Digital Halftoning.
+ */
+static unsigned char   classic_ordered[6][6] = {
+    {5, 4, 3, 14, 15, 16},
+    {6, 1, 2, 13, 18, 17},
+    {9, 7, 8, 10, 12, 11},
+    {14, 15, 16, 5, 4, 3},
+    {13, 18, 17, 6, 1, 2},
+    {10, 12, 11, 9, 7, 8}};
+
+/**
+ * tone_classic - classic diagonal clustered halftones.
+ *
+ * Entry:
+ *     Pix     Pixel value     0-255
+ * The following are not used but are here for consistency with
+ * other halftoning methods.
+ *     X       Current column
+ *     Y       Current row
+ *     NX      Next column
+ *     NY      Next row
+ *     New     New row flag.
+ *
+ * Exit:
+ *     returns 0-Levels
+ *
+ * Uses:
+ *     Debug   - Global Debug value
+ *     Levels  - Number of Intensity Levels
+ *     RandomFlag - Show we toss random numbers?
+ *
+ * Author:
+ *     Christopher T. Johnson  - 90/03/21
+ */
+int
+tone_classic(int pix, int x, int y, int UNUSED(nx), int UNUSED(ny), int 
UNUSED(newrow))
+{
+    int threshold = 14*classic_ordered[( x + 3) % 6][ y % 6];
+    if (RandomFlag) {
+       threshold += BN_UNIF_DOUBLE(RandomFlag)*63;
+    }
+    return ((pix*Levels + threshold)/255);
+}
+
+
+/*     tone_floyd      floyd-steinberg dispersed error method.
+ *
+ * Entry:
+ *     pix     Pixel value     0-255
+ *     x       Current column
+ *     y       Current row
+ *     nx      Next column
+ *     ny      Next row
+ *     newrow  New row flag.
+ *
+ * Exit:
+ *     returns 0 - Levels
+ *
+ * Uses:
+ *     Debug   - Current debug level
+ *     Levels  - Number of intensity levels.
+ *     width   - width of bw file.
+ *     RandomFlag - Should we toss random numbers?
+ *
+ * Calls:
+ *     BN_UNIF_DOUBLE()        Returns a random double between -0.5 and 0.5.
+ *
+ * Author:
+ *     Christopher T. Johnson  - 90/03/21
+ */
+int
+tone_floyd(int pix, int x, int UNUSED(y), int nx, int UNUSED(ny), int newrow)
+{
+    static int *error = 0;
+    static int *thisline;
+    int diff, value;
+    int Dir = nx-x;
+    double w1, w3, w5, w7;
+
+    if (RandomFlag) {
+       double val;
+       val = BN_UNIF_DOUBLE(RandomFlag)*1.0/16.0; /* slowest */
+       w1 = 1.0/16.0 + val;
+       w3 = 3.0/16.0 - val;
+       val = BN_UNIF_DOUBLE(RandomFlag)*5.0/16.0; /* slowest */
+       w5 = 5.0/16.0 + val;
+       w7 = 7.0/16.0 - val;
+    } else {
+       w1 = 1.0/16.0;
+       w3 = 3.0/16.0;
+       w5 = 5.0/16.0;
+       w7 = 7.0/16.0;
+    }
+
+/*
+ *     is this the first time through?
+ */
+    if (!error) {
+       error = (int *) bu_calloc(width, sizeof(int), "error");
+       thisline = (int *) bu_calloc(width, sizeof(int), "thisline");
+    }
+/*
+ *     if this is a new line then trade error for thisline.
+ */
+    if (newrow) {
+       int *p;
+       p = error;
+       error = thisline;
+       thisline = p;
+    }
+
+    pix += thisline[x];
+    thisline[x] = 0;
+
+    value = (pix*Levels + 127) / 255;
+    diff =  pix - (value * 255 /Levels);
+
+    if (x+Dir < width && x+Dir >= 0) {
+       thisline[x+Dir] += diff*w7;     /* slow */
+       error[x+Dir] += diff*w1;
+    }
+    error[x] += diff*w5;                       /* slow */
+    if (x-Dir < width && x-Dir >= 0) {
+       error[x-Dir] += diff*w3;
+    }
+    return value;
+}
+
+/*
+ * Dispersed-Dot ordered Dither at 0 degrees (n=4)
+ *     From page 135 of Digital Halftoning.
+ */
+static unsigned char   folly_ordered[4][4] = {
+    {2, 16, 3, 13},
+    {12, 8, 9, 5},
+    {4, 14, 1, 15},
+    {10, 6, 11, 7}};
+
+/*     tone_folly      4x4 square ordered dither dispersed (folly and van dam)
+ *
+ * Entry:
+ *     pix     Pixel value     0-255
+ *     x       Current column
+ *     y       Current row
+ *     nx      Next column
+ *     ny      Next row
+ *     newrow  New row flag.
+ *
+ * Exit:
+ *     returns 0 to Levels
+ *
+ * Uses:
+ *     Debug   - Current debug level.
+ *     Levels  - Number of intensity levels.
+ *     RandomFlag - should we toss some random numbers?
+ *
+ * Calls:
+ *     BN_UNIF_DOUBLE() - to get random numbers from -0.5 to 0.5
+ *
+ *  Author -
+ *     Christopher T. Johnson  - 90/03/21
+ */
+int
+tone_folly(int pix, int x, int y, int UNUSED(nx), int UNUSED(ny), int 
UNUSED(newrow))
+{
+    int threshold = 16*folly_ordered[ x % 4][ y % 4];
+
+    if (RandomFlag) {
+       threshold += BN_UNIF_DOUBLE(RandomFlag)*63;
+    }
+    return ((pix*Levels + threshold)/255);
+}
+
+/**
+ * tonescale
+ *
+ * Given a raw pixel value, return a scaled value.
+ *
+ * This is normally used to map the output devices characteristics to
+ * the input intensities.  There can be a different map for each color.
+ *
+ * Entry:
+ *     map     pointer to a 256 byte map
+ *     Slope   Slope of a line
+ *     B       offset of line.
+ *     eqptr   Null or the pointer to a equation for generating a curve
+ *
+ * Exit:
+ *     map     is filled using eqptr
+ *
+ * Uses:
+ *     EqCubics        x, A, B, C, D of a set of cubics for a curve
+ *
+ * Calls:
+ *     eq_line given x return y; requires EqLineSlope and EqLineB
+ *     eqptr   if not null.
+ *
+ * Method:
+ *     straight-forward.
+ *
+ * Author:
+ *     Christopher T. Johnson  - 90/03/22
+ *
+ * Change History:
+ *     ctj 90/04/04 - change to use a standard cubic line format for the
+ *     tone scale.  If eqptr is null then Set EqCubic to evaluate to a line.
+ */
+typedef struct Cubic {
+    double     x, A, B, C, D;
+} C;
+static struct Cubic    *EqCubics=0;
+int eq_cubic(int x);
+
+void
+tonescale(unsigned char *map, float Slope, float B, int (*eqptr) (/* ??? */))
+{
+    int i, result;
+
+/*
+ *     Is there a function we should be using?
+ * N.B.        This code has not been tested with a function being passed in.
+ */
+    if (!eqptr ) eqptr=eq_cubic;
+
+/*
+ *     If there is no defined Cubics then set a straight line.
+ */
+    if (!EqCubics) {
+/*
+ *             We need an extra cubic to make eq_cubic processing
+ *             easier.
+ */
+       EqCubics = (struct Cubic *)malloc(2*sizeof(struct Cubic));
+       EqCubics[0].x = 0.0;
+       EqCubics[0].A = B;
+       EqCubics[0].B = Slope;
+       EqCubics[1].x = 256.0;
+       EqCubics[0].C = EqCubics[0].D = EqCubics[1].A =
+           EqCubics[1].B = EqCubics[1].C = EqCubics[1].D = 0.0;
+    }
+
+    for (i=0;i<256;i++) {
+       result=eqptr(i);
+       if (result<0) {
+           if (Debug >= DLEVEL) {
+               fprintf(stderr, "tonescale: y=%d, x=%d\n",
+                       result, i);
+           }
+           result=0;
+       } else if (result > 255) {
+           if (Debug >= DLEVEL) {
+               fprintf(stderr, "tonescale: y=%d, x=%d\n",
+                       result, i);
+           }
+           result=255;
+       }
+
+       map[i] = result;
+    }
+}
+
+/* eq_cubic    default tone scale algorithm
+ *
+ * implement
+ *     y = A+B*(X-x)+C*(X-x)^2+D*(X-x)^3
+ * as a default tonescale algorithm;
+ *
+ * Entry:
+ *     x       x value for equation.
+ *
+ * Exit:
+ *     returns y in the range 0-255  requires clipping.
+ *
+ * Calls:
+ *     none.
+ *
+ * Uses:
+ *     EqCubic         list of Cubic equations.
+ *
+ * Method:
+ *     straight-forward.
+ *
+ * Author:
+ *     Christopher T. Johnson - 90/03/22
+ */
+int
+eq_cubic(int x)
+{
+    int y;
+    struct Cubic *p = EqCubics;
+
+    if (!p) {
+       fprintf(stderr, "eq_cubic called with no cubics!\n");
+       return x;
+    }
+    while (x >= (p+1)->x) p++;
+
+    y = ((p->D * (x - p->x) + p->C) * (x - p->x) + p->B)
+       * (x - p->x) + p->A;
+
+    CLAMP(y, 0, 255);
+    return y;
+}
+
+/* cubic_init  initialize a cubic list given a set of points.
+ *
+ * Entry:
+ *     n       number of points
+ *     x       list of x points.
+ *     y       list of y points.
+ *
+ * Exit:
+ *     EqCubic is set to a list of cubics
+ *
+ * Calls:
+ *     none.
+ *
+ * Uses:
+ *     none.
+ *
+ * Method:
+ *     Cubic Spline Interpolation
+ *     Taken from page 107 of:
+ *             Numerical Analysis 2nd Edition by
+ *             Richard L. Burden, J. Douglas Faires and
+ *                 Albert C. Reynalds.
+ *
+ * I.e.  I don't have a clue to what is going on...... :-(
+ *
+ */
+void
+cubic_init(int n, int *x, int *y)
+{
+    int i;
+    double *h, *alpha, *mi, *z, *l;
+
+    h = (double *) malloc(n*sizeof(double));
+    alpha = (double *) malloc(n*sizeof(double));
+    mi = (double *) malloc(n*sizeof(double));
+    z = (double *) malloc(n*sizeof(double));
+    l = (double *) malloc(n*sizeof(double));
+
+    EqCubics = (struct Cubic *) malloc(n*sizeof(struct Cubic));
+
+    for (i=0; i<n-1; i++) {
+       h[i] = x[i+1] - x[i];
+       EqCubics[i].x = x[i];
+       EqCubics[i].A = y[i];
+    }
+
+    EqCubics[i].x = x[i];
+    EqCubics[i].A = y[i];
+
+    for (i=1; i<n-1; i++) {
+       alpha[i] = 3.0*(y[i+1]*h[i-1] - y[i]*(x[i+1]-x[i-1]) +
+                       y[i-1]*h[i]) / (h[i-1]*h[i]);
+    }
+
+    z[0] = 0;
+    mi[0] = 0;
+
+    for (i=1; i<n-1; i++) {
+       l[i] = 2.0*(x[i+1] - x[i-1]) - h[i-1]*mi[i-1];
+       mi[i] = h[i]/l[i];
+       z[i] = (alpha[i]-h[i-1]*z[i-1]) / l[i];
+    }
+
+    l[i] = 1.0;
+    z[i] = 0.0;
+    EqCubics[i].C = z[i];
+
+    for (i=n-2; i>=0; i--) {
+       EqCubics[i].C = z[i] - mi[i]*EqCubics[i+1].C;
+       EqCubics[i].B = (y[i+1] - y[i])/h[i] -
+           h[i]*(EqCubics[i+1].C + 2.0*EqCubics[i].C)/3.0;
+       EqCubics[i].D = (EqCubics[i+1].C - EqCubics[i].C)/(3.0*h[i]);
+    }
+
+    free(h);
+    free(alpha);
+    free(mi);
+    free(z);
+    free(l);
+    if (Debug>1) {
+       for (i=0;i<n;i++) {
+           fprintf(stderr, "x=%g, A=%g, B=%g, C=%g, D=%g\n",
+                   EqCubics[i].x, EqCubics[i].A, EqCubics[i].B,
+                   EqCubics[i].C, EqCubics[i].D);
+       }
+    }
+}
+
+/*     tone_simple     thresh hold method
+ *
+ * Entry:
+ *     pix     Pixel value     0-255
+ *     x       Current column
+ *     y       Current row
+ *     nx      Next column
+ *     ny      Next row
+ *     newrow  New row flag.
+ *
+ * Exit:
+ *     returns 0 or 1
+ *
+ * Uses:
+ *     Debug   - Debug level (currently not used.)
+ *     Levels  - Number of intensity levels.
+ *     RandomFlag - Use random threshold flag.
+ *
+ * Calls:
+ *     BN_UNIF_DOUBLE  - return a random number between -0.5 and 0.5;
+ *
+ * Author:
+ *     Christopher T. Johnson  - 90/03/21
+ */
+int
+tone_simple(int pix, int UNUSED(x), int UNUSED(y), int UNUSED(nx), int 
UNUSED(ny), int UNUSED(newrow))
+{
+    int threshold;
+    if (RandomFlag) {
+       threshold = THRESHOLD + BN_UNIF_DOUBLE(RandomFlag)*127;
+    } else {
+       threshold = THRESHOLD;
+    }
+    return ((pix*Levels + threshold) / 256 );
+}
+
+
+static const char usage[] = "\
+Usage: halftone [-R -S -a] [-D Debug_Level]\n\
+       [-s squarefilesize] [-w file_width] [-n file_height]\n\
+       [-B contrast] [-I #_of_intensity_levels] [-T x y ... (tone curve)]\n\
+       [-M Method] [file.bw]\n\
+       where Method is chosen from:\n\
+           0  Floyd-Steinberg\n\
+           1  45-Degree Classic Screen\n\
+           2  Thresholding\n\
+           3  0-Degree Dispersed Screen\n\
+       (stdin used with '<' construct if file.bw not supplied)\n";
+
+/*
+ * process parameters and setup working environment
+ *
+ * Entry:
+ *     argc    - number of arguments.
+ *     argv    - the arguments.
+ *
+ * Exit:
+ *     parameters have been set.
+ *     if there is a fatal error, exit non-zero
+ *
+ * Uses:
+ *     width   - width of picture
+ *     height  - height of picture
+ *     Beta    - sharpening value
+ *     surpent - to surpenten rasters?
+ *     Levels  - number of intensity levels
+ *     Debug   - debug level
+ *     RandomFlag - Add noise to processes.
+ *
+ * Calls:
+ *     cubic_init - setup for tonescale.
+ *
+ * Method:
+ *     straight-forward.
+ */
+void
+setup(int argc, char **argv)
+{
+    int c;
+    int i, j;
+    int *Xlist, *Ylist;
+    int        autosize = 0;
+
+    while ((c = bu_getopt(argc, argv, "D:s:an:w:B:M:RSI:T:h?")) != -1) {
+       switch (c) {
+           case 's':
+               width = height = atol(bu_optarg);
+               break;
+           case 'n':
+               height = atol(bu_optarg);
+               break;
+           case 'w':
+               width = atol(bu_optarg);
+               break;
+           case 'a':
+               autosize = 1;
+               break;
+           case 'B':
+               Beta = atof(bu_optarg);
+               break;
+           case 'M':
+               Method = atoi(bu_optarg);
+               if (Method <0 || Method >3) {
+                       fprintf(stderr,"halftone: Method must be 0,1,2,3; set 
to default (0)\n");
+                       Method = 0;
+               }
+               break;
+           case 'R':
+               RandomFlag = bn_unif_init(1, 0);
+               break;
+           case 'S':
+               Surpent = 1;
+               break;
+           case 'I':
+               Levels = atoi(bu_optarg)-1;
+               V_MAX(Levels, 1);
+               break;
+/*
+ * Tone scale processing is a little strange.  The -T option is followed
+ * by a list of points.  The points are collected and one point is added
+ * at 1024, 1024 to let tonescale be stupid.  Cubic_init takes the list
+ * of points and generates "cubics" for tonescale to use in generating
+ * curve to use for the tone map.  If tonescale is called with no cubics
+ * defined tonescale will generate a straight-line (generally from 0, 0 to
+ * 255, 255).
+ */
+           case 'T':
+               --bu_optind;
+               for (i=bu_optind; i < argc && (isdigit((int)*argv[i]) ||
+                                              (*argv[i] == '-' && 
isdigit((int)(*(argv[i]+1))))); i++);
+               if ((c=i-bu_optind) % 2) {
+                   fprintf(stderr, "Missing Y coordinate for tone map.\n");
+                   bu_exit(1, NULL);
+               }
+               Xlist = (int *) bu_malloc((c+2)*sizeof(int), "Xlist");
+               Ylist = (int *) bu_malloc((c+2)*sizeof(int), "Ylist");
+
+               for (j=0;bu_optind < i; ) {
+                   Xlist[j] = atoi(argv[bu_optind++]);
+                   Ylist[j] = atoi(argv[bu_optind++]);
+                   j++;
+               }
+               Xlist[j] = 1024;
+               Ylist[j] = 1024;
+               if (Debug>6) fprintf(stderr, "Number points=%d\n", j+1);
+               (void) cubic_init(j+1, Xlist, Ylist);
+               bu_free(Xlist, "Xlist");
+               bu_free(Ylist, "Ylist");
+               break;
+/*
+ * Debug is not well used at this point a value of 9 will get all
+ * debug statements.  Debug is a level indicator NOT a bit flag.
+ */
+           case 'D':
+               Debug = atoi(bu_optarg);
+               break;
+           default:
+               bu_exit(1, usage);
+       }
+    }
+/*
+ *     if there are no extra arguments and stdin is a tty then
+ *     the user has given us no input file.  Spit a usage message
+ *     at them and exit.
+ */
+    if (bu_optind >= argc) {
+       if ( isatty(fileno(stdin)) ) {
+           bu_exit(1, usage);
+       }
+       if (autosize) {
+           (void) fprintf(stderr, "%s", usage);
+           bu_exit(1, "Automatic sizing can not be used with pipes.\n");
+       }
+    } else {
+       char *ifname = bu_file_realpath(argv[bu_optind], NULL);
+       if (freopen(ifname, "r", stdin) == NULL ) {
+           bu_free(ifname,"ifname alloc from bu_file_realpath");
+           bu_exit(1, "halftone: cannot open \"%s\" for reading.\n", 
argv[bu_optind]);
+       }
+       bu_free(ifname,"ifname alloc from bu_file_realpath");
+       if (autosize) {
+           if ( !fb_common_file_size((size_t *)&width, (size_t *)&height, 
argv[bu_optind], 1)) {
+               (void) fprintf(stderr, "halftone: unable to autosize.\n");
+           }
+       }
+    }
+
+    if ( argc > ++bu_optind) {
+       (void) fprintf(stderr, "halftone: excess argument(s) ignored.\n");
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    int pixel, x, y, i;
+    unsigned char *Line, *Out;
+    int NewFlag = 1;
+    int Scale;
+    unsigned char Map[256];
+    size_t ret;
+
+    bu_setprogname(argv[0]);
+/*
+ *     parameter processing.
+ */
+    setup(argc, argv);
+/*
+ *     Get a tone map.  Map is the result.  1.0 is slope, 0.0 is
+ *     the Y intercept (y=mx+b). 0 is the address of a function to
+ *     do a x to y mapping, 0 means use the default function.
+ */
+    (void) tonescale(Map, 1.0, 0.0, 0);
+
+/*
+ * Currently the halftone file is scaled from 0 to 255 on output to
+ * ease display via bw-fb.  In the future there might be flag to
+ * set Scale to 1 to get a unscaled output.
+ */
+    Scale = 255/Levels;
+
+    if (Debug) {
+       fprintf(stderr, "Debug = %d, Scale = %d\n", Debug, Scale);
+    }
+
+    if (Debug>2) {
+       for (i=0;i<256;i++) fprintf(stderr, "%d ", Map[i]);
+       fprintf(stderr, "\n");
+    }
+
+    Line = (unsigned char *) bu_malloc(width, "Line");
+    Out = (unsigned char *) bu_malloc(width, "Out");
+/*
+ * should be a test here to make sure we got the memory requested.
+ */
+
+/*
+ *     Currently only the Floyd-Steinberg method uses the surpent flag
+ *     so we make things easy with in the 'y' loop by resetting surpent
+ *     for all other methods to "No Surpent".
+ */
+    if (Method != M_FLOYD) Surpent = 0;
+
+    for (y=0; y<height; y++) {
+       int NextX;
+/*
+ *             A few of the methods benefit by knowing when a new line is
+ *             started.
+ */
+       NewFlag = 1;
+       (void) sharpen(Line, 1, width, stdin, Map);
+/*
+ *             Only M_FLOYD will have Surpent != 0.
+ */
+       if (Surpent && y % 2) {
+           for (x=width-1; x>=0; x--) {
+               pixel = Line[x];
+               Out[x] = Scale*tone_floyd(pixel, x, y, x-1,
+                                         y+1, NewFlag);
+               NewFlag = 0;
+           }
+       } else {
+           for (x=0; x<width; x++) {
+               NextX = x+1;
+               pixel = Line[x];
+               switch (Method) {
+                   case M_FOLLY:
+                       Out[x] = Scale*tone_folly(pixel, x, y,
+                                                 NextX, y+1, NewFlag);
+                       break;
+                   case M_FLOYD:
+                       Out[x] = Scale*tone_floyd(pixel, x, y,
+                                                 NextX, y+1, NewFlag);
+                       break;
+                   case M_THRESH:
+                       Out[x]=Scale*tone_simple(pixel, x, y,
+                                                NextX, y+1, NewFlag);
+                       break;
+                   case M_CLASSIC:
+                       Out[x]=Scale*tone_classic(pixel, x, y,
+                                                 NextX, y+1, NewFlag);
+                       break;
+               }
+               NewFlag=0;
+           }
+       }
+       ret = fwrite(Out, 1, width, stdout);
+       if ( ret < (size_t)width)
+           perror("fwrite");
+    }
+    bu_free(Line, "Line");
+    bu_free(Out, "Out");
+    return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */


Property changes on: brlcad/trunk/src/util/halftone.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to