1 /* pnmmalias.c - antialias a portable anymap.
2 **
3 ** Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical
4 ** Observatory.
5 **
6 ** Permission to use, copy, modify, and distribute this software and its
7 ** documentation for any purpose and without fee is hereby granted, provided
8 ** that the above copyright notice appear in all copies and that both that
9 ** copyright notice and this permission notice appear in supporting
10 ** documentation.  This software is provided "as is" without express or
11 ** implied warranty.
12 */
13 
14 #include "pnm.h"
15 
16 int
main(int argc,char * argv[])17 main(int argc, char * argv[] ) {
18     FILE* ifp;
19     xel* xelrow[3];
20     xel* newxelrow;
21     pixel bgcolorppm, fgcolorppm;
22     register xel* xpP;
23     register xel* xP;
24     register xel* xnP;
25     register xel* nxP;
26     xel bgcolor, fgcolor;
27     int argn, rows, cols, format, newformat, bgonly, fgonly;
28     int bgalias, fgalias;
29     int row;
30     double fmask[9], weight;
31     xelval maxval;
32     xelval newmaxval;
33     const char* const usage = "[-bgcolor <color>] [-fgcolor <color>] [-bonly] [-fonly] [-balias] [-falias] [-weight <w>] [pnmfile]";
34 
35     pnm_init( &argc, argv );
36 
37     bgonly = fgonly = 0;
38     bgalias = fgalias = 0;
39     weight = 1./3.;
40     argn = 1;
41     PPM_ASSIGN( bgcolorppm, 0, 0, 0);
42     PPM_ASSIGN( fgcolorppm, 0, 0, 0);
43 
44     while ( argn < argc && argv[argn][0] == '-' )
45         {
46         if ( pm_keymatch( argv[argn], "-fgcolor", 3 ) )
47         {
48         if ( ++argn >= argc )
49         pm_usage( usage );
50         else
51         fgcolorppm = ppm_parsecolor( argv[argn], PPM_MAXMAXVAL );
52         }
53         else if ( pm_keymatch( argv[argn], "-bgcolor", 3 ) )
54         {
55         if ( ++argn >= argc )
56         pm_usage( usage );
57         else
58         bgcolorppm = ppm_parsecolor( argv[argn], PPM_MAXMAXVAL );
59         }
60         else if ( pm_keymatch( argv[argn], "-weight", 2 ) )
61         {
62         if ( ++argn >= argc )
63         pm_usage( usage );
64         else if ( sscanf( argv[argn], "%lf", &weight ) != 1 )
65             pm_usage( usage );
66         else if ( weight >= 1. || weight <= 0. )
67         {
68         pm_message( "weight factor w must be 0.0 < w < 1.0" );
69         pm_usage( usage );
70         }
71         }
72     else if ( pm_keymatch( argv[argn], "-bonly", 3 ) )
73         bgonly = 1;
74     else if ( pm_keymatch( argv[argn], "-fonly", 3 ) )
75         fgonly = 1;
76     else if ( pm_keymatch( argv[argn], "-balias", 3 ) )
77         bgalias = 1;
78     else if ( pm_keymatch( argv[argn], "-falias", 3 ) )
79         fgalias = 1;
80     else if ( pm_keymatch( argv[argn], "-bfalias", 3 ) )
81         bgalias = fgalias = 0;
82     else if ( pm_keymatch( argv[argn], "-fbalias", 3 ) )
83         bgalias = fgalias = 0;
84         else
85             pm_usage( usage );
86         ++argn;
87         }
88 
89     if ( argn != argc )
90     {
91     ifp = pm_openr( argv[argn] );
92     ++argn;
93     }
94     else
95     ifp = stdin;
96 
97     if ( argn != argc )
98     pm_usage( usage );
99 
100     /* normalize mask elements */
101     fmask[4] = weight;
102     fmask[0] = fmask[1] = fmask[2] = fmask[3] = ( 1.0 - weight ) / 8.0;
103     fmask[5] = fmask[6] = fmask[7] = fmask[8] = ( 1.0 - weight ) / 8.0;
104 
105     pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
106 
107     xelrow[0] = pnm_allocrow( cols );
108     xelrow[1] = pnm_allocrow( cols );
109     xelrow[2] = pnm_allocrow( cols );
110     newxelrow = pnm_allocrow( cols );
111 
112     /* Promote PBM files to PGM. */
113     if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) {
114         newformat = PGM_TYPE;
115         newmaxval = PGM_MAXMAXVAL;
116         pm_message( "promoting from PBM to PGM" );
117     } else {
118         newformat = format;
119         newmaxval = maxval;
120     }
121 
122     /* Figure out foreground pixel value if none was given */
123     if (PPM_GETR(fgcolorppm) == 0 && PPM_GETG(fgcolorppm) == 0 &&
124         PPM_GETB(fgcolorppm) == 0 ) {
125         if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE )
126             PNM_ASSIGN1( fgcolor, newmaxval );
127         else
128             PPM_ASSIGN( fgcolor, newmaxval, newmaxval, newmaxval );
129     } else {
130         if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE )
131             PNM_ASSIGN1( fgcolor, PPM_GETR( fgcolorppm ) );
132         else
133             fgcolor = fgcolorppm;
134     }
135 
136     if (PPM_GETR(bgcolorppm) != 0 || PPM_GETG(bgcolorppm) != 0 ||
137         PPM_GETB(bgcolorppm) != 0 ) {
138         if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE )
139             PNM_ASSIGN1( bgcolor, PPM_GETR( bgcolorppm) );
140         else
141             bgcolor = bgcolorppm;
142     } else {
143         if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE )
144             PNM_ASSIGN1( bgcolor, 0 );
145         else
146             PPM_ASSIGN( bgcolor, 0, 0, 0 );
147     }
148 
149 
150     pnm_readpnmrow( ifp, xelrow[0], cols, newmaxval, format );
151     pnm_readpnmrow( ifp, xelrow[1], cols, newmaxval, format );
152     pnm_writepnminit( stdout, cols, rows, newmaxval, newformat, 0 );
153     pnm_writepnmrow( stdout, xelrow[0], cols, newmaxval, newformat, 0 );
154 
155     for ( row = 1; row < rows - 1; ++row ) {
156         int col;
157         int value, valuer, valueg, valueb;
158 
159         pnm_readpnmrow( ifp, xelrow[(row+1)%3], cols, newmaxval, format );
160         newxelrow[0] = xelrow[row%3][0];
161 
162         for ( col = 1, xpP = (xelrow[(row-1)%3] + 1), xP = (xelrow[row%3] + 1),
163                   xnP = (xelrow[(row+1)%3] + 1), nxP = (newxelrow+1);
164               col < cols - 1; ++col, ++xpP, ++xP, ++xnP, ++nxP ) {
165 
166             int fgflag, bgflag;
167 
168             /* Reset flags if anti-aliasing is to be done on foreground
169              * or background pixels only */
170             if ( ( bgonly && PNM_EQUAL( *xP, fgcolor ) ) ||
171                  ( fgonly && PNM_EQUAL( *xP, bgcolor ) ) )
172                 bgflag = fgflag = 0;
173             else {
174                 /* Do anti-aliasing here: see if pixel is at the border of a
175                  * background or foreground stepwise side */
176                 bgflag =
177                     (PNM_EQUAL(*xpP,bgcolor) && PNM_EQUAL(*(xP+1),bgcolor)) ||
178                     (PNM_EQUAL(*(xP+1),bgcolor) && PNM_EQUAL(*xnP,bgcolor)) ||
179                     (PNM_EQUAL(*xnP,bgcolor) && PNM_EQUAL(*(xP-1),bgcolor)) ||
180                     (PNM_EQUAL(*(xP-1),bgcolor) && PNM_EQUAL(*xpP,bgcolor));
181                 fgflag =
182                     (PNM_EQUAL(*xpP,fgcolor) && PNM_EQUAL(*(xP+1),fgcolor)) ||
183                     (PNM_EQUAL(*(xP+1),fgcolor) && PNM_EQUAL(*xnP,fgcolor)) ||
184                     (PNM_EQUAL(*xnP,fgcolor) && PNM_EQUAL(*(xP-1),fgcolor)) ||
185                     (PNM_EQUAL(*(xP-1),fgcolor) && PNM_EQUAL(*xpP,fgcolor));
186             }
187             if ( ( bgflag && bgalias ) || ( fgflag && fgalias ) ||
188                  ( bgflag && fgflag ) )
189                 switch( PNM_FORMAT_TYPE( newformat ) ) {
190                 case PGM_TYPE:
191                     value = PNM_GET1(*(xpP-1)) * fmask[0] +
192                         PNM_GET1(*(xpP  )) * fmask[1] +
193                         PNM_GET1(*(xpP+1)) * fmask[2] +
194                         PNM_GET1(*(xP -1)) * fmask[3] +
195                         PNM_GET1(*(xP   )) * fmask[4] +
196                         PNM_GET1(*(xP +1)) * fmask[5] +
197                         PNM_GET1(*(xnP-1)) * fmask[6] +
198                         PNM_GET1(*(xnP  )) * fmask[7] +
199                         PNM_GET1(*(xnP+1)) * fmask[8] +
200                         0.5;
201                     PNM_ASSIGN1( *nxP, value );
202                     break;
203                 default:
204                     valuer= PPM_GETR(*(xpP-1)) * fmask[0] +
205                         PPM_GETR(*(xpP  )) * fmask[1] +
206                         PPM_GETR(*(xpP+1)) * fmask[2] +
207                         PPM_GETR(*(xP -1)) * fmask[3] +
208                         PPM_GETR(*(xP   )) * fmask[4] +
209                         PPM_GETR(*(xP +1)) * fmask[5] +
210                         PPM_GETR(*(xnP-1)) * fmask[6] +
211                         PPM_GETR(*(xnP  )) * fmask[7] +
212                         PPM_GETR(*(xnP+1)) * fmask[8] +
213                         0.5;
214                     valueg= PPM_GETG(*(xpP-1)) * fmask[0] +
215                         PPM_GETG(*(xpP  )) * fmask[1] +
216                         PPM_GETG(*(xpP+1)) * fmask[2] +
217                         PPM_GETG(*(xP -1)) * fmask[3] +
218                         PPM_GETG(*(xP   )) * fmask[4] +
219                         PPM_GETG(*(xP +1)) * fmask[5] +
220                         PPM_GETG(*(xnP-1)) * fmask[6] +
221                         PPM_GETG(*(xnP  )) * fmask[7] +
222                         PPM_GETG(*(xnP+1)) * fmask[8] +
223                         0.5;
224                     valueb= PPM_GETB(*(xpP-1)) * fmask[0] +
225                         PPM_GETB(*(xpP  )) * fmask[1] +
226                         PPM_GETB(*(xpP+1)) * fmask[2] +
227                         PPM_GETB(*(xP -1)) * fmask[3] +
228                         PPM_GETB(*(xP   )) * fmask[4] +
229                         PPM_GETB(*(xP +1)) * fmask[5] +
230                         PPM_GETB(*(xnP-1)) * fmask[6] +
231                         PPM_GETB(*(xnP  )) * fmask[7] +
232                         PPM_GETB(*(xnP+1)) * fmask[8] +
233                         0.5;
234                     PPM_ASSIGN( *nxP, valuer, valueg, valueb );
235                     break;
236                 }
237             else
238                 *nxP = *xP;
239         }
240 
241         newxelrow[cols-1] = xelrow[row%3][cols-1];
242         pnm_writepnmrow( stdout, newxelrow, cols, newmaxval, newformat, 0 );
243     }
244 
245     pnm_writepnmrow( stdout, xelrow[row%3], cols, newmaxval, newformat, 0 );
246 
247     pm_close( ifp );
248     exit ( 0 );
249 }
250 
251