-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
160 lines (134 loc) · 3.71 KB
/
main.c
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <argp.h>
#include <cairo.h>
#include <cairo-svg.h>
#include "utils.h"
#define DESTFILESIZE 512
#define DEFLINEWIDTH (0.00125)
#define OPT_FORMAT_PNG "png"
#define OPT_FORMAT_SVG "svg"
typedef enum {
PNG = 0,
SVG
} output_format;
typedef struct {
unsigned int width, height;
float rgba_fg[4], rgba_bg[4];
float line_width;
unsigned int depth;
output_format format;
char destfile[DESTFILESIZE];
} cmd_args;
const char * argp_program_version = "0.5";
static error_t sierpinski_argp_parser(int key, char *arg, struct argp_state *s);
int main (int argc, char *argv[]) {
cmd_args args = {
512, 512,
{1.0, 1.0, 1.0, 1.0}, {0.0, 0.0, 0.0, 1.0},
0.00125,
0, PNG, "\0"
};
static struct argp_option options[] = {
{"fg", 'f', "<#RGBA>", 0, "Background color in RGBA format", 1},
{"bg", 'b', "<#RGBA>", 0, "Foreground color in RGBA format", 1},
{"linewidth", 'l', "<0..1>", 0, "Scaling factor of the line width. 0 to 1 float", 2},
{"width", 'w', "<int>", 0, "Width of the output image, in pixels if PNG or points if SVG", 2},
{"height", 'h', "<int>", 0, "Height of the output image, in pixels if PNG or points if SVG", 2},
{"format", 'F', "<[png|svg]>", 0, "Output file format", 3},
{"outputfile", 'o', "<filename>", 0, "Arbitrary output file name", 3},
{0}
};
static struct argp a = {
options,
sierpinski_argp_parser,
"<Depth level>",
"Sierpinski triangle generator."
};
cairo_t *cr;
cairo_surface_t *s = NULL;
argp_parse(&a, argc, argv, 0, NULL, (void*) &args);
if (args.format == PNG) {
s = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, args.width, args.height
);
} else if (args.format == SVG) {
// TO-DO Can a more careful conversion of the width and height
// parameters be done with regard to the point unit? (I guess no.)
s = cairo_svg_surface_create(args.destfile, args.width, args.height);
}
cr = cairo_create(s);
cairo_scale(cr, args.width, args.height);
cairo_set_source_rgba(
cr, args.rgba_bg[0], args.rgba_bg[1], args.rgba_bg[2], args.rgba_bg[3]
);
cairo_paint(cr);
cairo_set_source_rgba(
cr, args.rgba_fg[0], args.rgba_fg[1], args.rgba_fg[2], args.rgba_fg[3]
);
cairo_set_line_width(cr, args.line_width);
cairo_sierpinski_triangle_auto(cr, args.depth);
cairo_stroke(cr);
cairo_surface_write_to_png(s, args.destfile);
cairo_destroy(cr);
cairo_surface_destroy(s);
return 0;
}
static error_t sierpinski_argp_parser(int key, char *arg, struct argp_state *s) {
cmd_args * const a = (cmd_args*) s->input;
switch (key) {
// When the single required non-option argument is present
case ARGP_KEY_ARG:
a->depth = atoi(arg);
break;
case ARGP_KEY_NO_ARGS: // When no non-option argument is present
argp_error(s, "<Depth level>");
break;
case ARGP_KEY_END: // At the end of the parsing process
if (*a->destfile == '\0') {
if (a->format == PNG) {
snprintf(
a->destfile, DESTFILESIZE,
"Sierpinski%d.png", a->depth
);
} else if (a->format == SVG) {
snprintf(
a->destfile, DESTFILESIZE,
"Sierpinski%d.svg", a->depth
);
}
}
break;
case 'f':
std_rgba_to_cairo_rgba(arg, a->rgba_fg);
break;
case 'b':
std_rgba_to_cairo_rgba(arg, a->rgba_bg);
break;
case 'w':
a->width = atoi(arg);
break;
case 'h':
a->height = atoi(arg);
break;
case 'l':
a->line_width = DEFLINEWIDTH * atof(arg);
break;
case 'F':
if (!strcmp(arg, OPT_FORMAT_PNG)) {
a->format = PNG;
} else if (!strcmp(arg, OPT_FORMAT_SVG)) {
a->format = SVG;
} else {
argp_error(s, "-F <[png|svg]>");
}
break;
case 'o':
strncpy(a->destfile, arg, DESTFILESIZE);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}