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