about summary refs log tree commit diff
path: root/editor/specialty/ppmspread.c
blob: 7b9558e31a16b127d8c79e6a3559eee6b7852758 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*********************************************************************/
/* ppmspread -  randomly displace a PPM's pixels by a certain amount */
/* Frank Neumann, October 1993                                       */
/* V1.1 16.11.1993                                                   */
/*                                                                   */
/* version history:                                                  */
/* V1.0 12.10.1993    first version                                  */
/* V1.1 16.11.1993    Rewritten to be NetPBM.programming conforming  */
/*********************************************************************/

#include <string.h>

#include "nstring.h"
#include "rand.h"
#include "shhopt.h"
#include "ppm.h"


struct CmdlineInfo {
    /* This structure represents all of the information the user
       supplied in the command line but in a form that's easy for the
       program to use.
    */
    const char * inputFilename;  /* '-' if stdin */
    unsigned int spread;
    unsigned int randomseedSpec;
    unsigned int randomseed;
};



static void
parseCommandLine(int argc, const char ** const argv,
                 struct CmdlineInfo * const cmdlineP ) {

    optEntry     * option_def;
        /* Instructions to OptParseOptions3 on how to parse our options */
    optStruct3     opt;
    unsigned int   option_def_index;

    MALLOCARRAY_NOFAIL(option_def, 100);
    option_def_index = 0;          /* Incremented by OPTENTRY */

    OPTENT3(0, "randomseed", OPT_UINT,   &cmdlineP->randomseed,
            &cmdlineP->randomseedSpec, 0);

    opt.opt_table = option_def;
    opt.short_allowed = 0;
    opt.allowNegNum = 1;

    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );

    if (argc-1 < 1)
        pm_error("You must specify the spread factor as an argument");
    else {
        const char * error;
        pm_string_to_uint(argv[1], &cmdlineP->spread, &error);

        if (error)
            pm_error("Spread factor '%s' is not an unsigned integer.  %s",
                     argv[1], error);

        if (argc-1 < 2)
            cmdlineP->inputFilename = "-";
        else {
            cmdlineP->inputFilename = argv[2];
            if (argc-1 >2)
                pm_error("Too many arguments: %u.  "
                         "The only possible arguments are "
                         "the spread factor and the optional input file name",
                         argc-1);
        }
    }
}



static void
spreadRow(pixel **           const srcarray,
          unsigned int       const cols,
          unsigned int       const rows,
          unsigned int       const spread,
          unsigned int       const row,
          pixel **           const destarray,
          struct pm_randSt * const randStP) {

    unsigned int col;

    for (col = 0; col < cols; ++col) {
        pixel const p = srcarray[row][col];

        int const xdis = (pm_rand(randStP) % (spread + 1) )
            - ((spread + 1) / 2);
        int const ydis = (pm_rand(randStP) % (spread + 1))
            - ((spread + 1) / 2);

        int const xnew = col + xdis;
        int const ynew = row + ydis;

        /* only set the displaced pixel if it's within the bounds
           of the image
        */
        if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) {
            /* Displacing a pixel is accomplished by swapping it
               with another pixel in its vicinity.
            */
            pixel const p2 = srcarray[ynew][xnew];
                /* Original value of second pixel */

            /* Set second pixel to new value */
            PPM_ASSIGN(destarray[ynew][xnew],
                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));

            /* Set first pixel to (old) value of second */
            PPM_ASSIGN(destarray[row][col],
                       PPM_GETR(p2), PPM_GETG(p2), PPM_GETB(p2));
        } else {
            /* Displaced pixel is out of bounds; leave the old pixel there.
            */
            PPM_ASSIGN(destarray[row][col],
                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
        }
    }
}



int
main(int          argc,
     const char * argv[]) {

    struct CmdlineInfo cmdline;
    FILE * ifP;
    int rows, cols;
    unsigned int row;
    pixel ** destarray;
    pixel ** srcarray;
    pixval maxval;
    struct pm_randSt randSt;

    pm_proginit(&argc, argv);

    parseCommandLine(argc, argv, &cmdline);

    ifP = pm_openr(cmdline.inputFilename);

    srcarray = ppm_readppm(ifP, &cols, &rows, &maxval);

    destarray = ppm_allocarray(cols, rows);

    pm_randinit(&randSt);
    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);

    /* clear out the buffer */
    for (row = 0; row < rows; ++row)
        memset(destarray[row], 0, cols * sizeof(pixel));

    /* Displace pixels */
    for (row = 0; row < rows; ++row) {
        spreadRow(srcarray, cols, rows, cmdline.spread, row,
                  destarray, &randSt);

    }
    pm_randterm(&randSt);

    ppm_writeppm(stdout, destarray, cols, rows, maxval, 0);

    pm_close(ifP);
    ppm_freearray(srcarray, rows);
    ppm_freearray(destarray, rows);

    return 0;
}