source: projects/visualisator/create-image.c @ 1

Last change on this file since 1 was 1, checked in by sven, 16 years ago

Erstimport

File size: 12.2 KB
RevLine 
[1]1/**
2 * Vollstaendig konfigurierbares Kommandozeilenfrontend fuer die
3 * Lochstreifenzeichenroutine (Cairo verwendend).
4 * siehe ./programm --help fuer Uebersicht der selbsterklaerenden
5 * Parameter.
6 *
7 * Default ist Einlesen ueber stdin und Ausgabe auf stdout in PNG.
8 *
9 **/
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <argp.h>
15
16#include "lochstreifen.h"
17
18LOCHSTREIFEN *l;
19int surface_type = 0; // 0 = PNG, 1 = SVG
20char *output_file;
21int verbosity = 0;
22
23#define DPRINTF(msg...) if(verbosity!=0) fprintf(stderr,msg);
24
25const char *argp_program_version = "Punch card visualisator - CLI frontend";
26
27static struct argp_option options[] = {
28    {"verbose",     'v',   0,      0,  "Produce verbose output on stderr" },
29    //{"quiet",       'q',   0,      0,  "Don't produce any output" },
30    //{"silent",      's',   0,      OPTION_ALIAS },
31
32    {"output",   'o', "FILE", 0,   "Output to FILE (instead of standard output)" },
33    {"image",    'i', 0, OPTION_ALIAS },
34    {"format",   'f', "SVG|PNG",0,  "Set desired output image format (PNG or SVG)" },
35    {"", 0, 0, OPTION_DOC, ""},
36
37    {"Dimensions", 0, 0, OPTION_DOC, "Dimensions are integers without units"},
38    {"width",    'w', "NUM",      0,  "Set desired width for output image (in px or points, according to output format)", 1 },
39    {"height",   'h', "NUM",      0,  "Set desired height for output image (unit like width argument)", 1 },
40    {"diameter", 'd', "NUM",      0,  "Set dimensions for output image by punched hole diameter (pixel)", 1 },
41    {"", 0, 0, OPTION_DOC, "",1},
42
43    {"Empty bytes", 1, 0, OPTION_DOC, "Bytes with value=0 which are not content of files", 1},
44    {"empty-start", -1, "NUM", 0,        "Set number of empty bytes at beginning (default=0)", 2 },
45    {"empty-end",   -2, "NUM", 0,        "Set number of empty bytes at end (default=0)", 2 },
46    {"", 0, 0, OPTION_DOC, "",2},
47
48    {"Colors", 0, 0, OPTION_DOC, "Color format: #RGB[A], #RRGGBB[AA]", 2 },
49    {"hide-imagebg",    -3, 0, 0, "Make the image background (space around paper tape) transparent", 3 },
50    {"color-imagebg",   -4, "#RGBA", 0, "Set image background color", 3 },
51    {"hide-tapebg",     -5, 0, 0, "Hide the paper tape background", 3 },
52    {"color-tapebg",    -6, "#RGBA", 0, "Set tape background color", 3 },
53    {"hide-punched",    -7, 0, 0, "Hide the holes (only the punched ones)", 3 },
54    {"color-punched",   -8, "#RGBA", 0, "Set color of holes (punched bits)", 3 },
55    {"hide-notpunched", -9, 0, 0, "Hide the holes which aren't punched on real tapes", 3 },
56    {"color-notpunched",-10, "#RGBA", 0, "Set color of bits with boolean value \"false\"", 3 },
57    {"hide-feedholes",  -11, 0, 0, "Hide the feed holes (which means they wouldn't be punched)", 3 },
58    {"color-feedholes", -12, "#RGBA", 0, "Set color of feed holes (the small ones)", 3 },
59    {"", 0, 0, OPTION_DOC, "",3},
60
61    {"Transformations and Rotations", 0, 0, OPTION_DOC, "", 3},
62    {"rotation",       -13, "right|bottom|left|top", 0, "Rotation of punched tape (alternative short notation: 0=right, 1=bottom, 2=left, 3=top)", 4 },
63    {"reflection-byte-direction",  -14, 0, 0, "Enables horizontal reflecion on the data axis (inverts data direction)", 4 },
64    {"reflection-bit-direction",   -15, 0, 0, "Enables vertical reflection on the other axis (inverts bit direction)", 4 },
65    {"", 0, 0, OPTION_DOC, "",-2},
66
67    { 0 }
68};
69
70char *strtolower(char *string) {
71    // komisch, ich dachte echt, es gaebe dafuer eine Funktion in C...
72    int x=0;
73    for(;string[x];x++) string[x] = tolower(string[x]);
74
75    return string; // ja, ich veraenderte den Ursprungsstring. Egal ;-)
76}
77
78cairo_pattern_t *hex2cairo_pattern(const char *string) {
79    /** Kriegt aus #RRGGBBAA oder #RGBA eine Cairo-Surface */
80    char buf[2];   // zum temporaeren Speichern der einzelnen umzuwandelnden Zeichen
81    buf[1] = '\0'; // nur ein Ein-Zeichen-String also
82    int len = strlen(string);
83    unsigned char numbers[8]; // rausgefundende Ziffern
84    int numbers_count; // wie viele Ziffern rausgefunden
85    cairo_pattern_t *pattern;
86
87    // erst mal schauen, ob ne schoene Raute da ist und auf Laenge (entsprechendes Format)
88    if(string[0] != '#' || (len != 4 && len != 5 && len != 7 && len != 9)) {
89        fprintf(stderr, "Bad color: %s -- colors shall have format #RGB or #RRGGBB or #RGBA or #RRGGBBAA\n", string, len);
90        exit(1);
91    }
92    string++; // das "#"-Zeichen braucht keiner mehr
93
94    for(numbers_count=0; numbers_count < len-1; numbers_count++) {
95        buf[0] = string[numbers_count];
96        numbers[numbers_count] = strtol(buf, NULL, 16);
97        //printf("Read digit %s = 0x%x\n", buf, numbers[numbers_count]);
98    }
99    //numbers_count++; // wir zaehlen ab 1 -- komisch, tud er sowieso schon.
100
101    if(numbers_count == 3 || numbers_count == 4) {
102        // #RGB oder #RGBA
103        pattern = cairo_pattern_create_rgba(
104            (double)numbers[0] / (double)0xF,
105            (double)numbers[1] / (double)0xF,
106            (double)numbers[2] / (double)0xF,
107            (numbers_count == 4) ? (double)numbers[3] / (double)0xF : 1
108        );
109    } else {
110        // #RRGGBB oder #RRGGBBAA
111        pattern = cairo_pattern_create_rgba(
112            (double)(numbers[1] + numbers[0]*0x10) / (double)0xFF,
113            (double)(numbers[3] + numbers[2]*0x10) / (double)0xFF,
114            (double)(numbers[5] + numbers[4]*0x10) / (double)0xFF,
115            (numbers_count == 8) ? (double)(numbers[7] + numbers[6]*0x10) / (double)0xFF : 1
116        );
117    }
118    // Fuer Debug-Ausgaben:
119    { double r,g,b,a; cairo_pattern_get_rgba(pattern, &r, &g, &b, &a);
120      printf("Allocated color #%s as #%x%x%x, opacity %x\n", string, (unsigned int)(r*256), (unsigned int)(g*256), (unsigned int)(b*256), (unsigned int)(a*256)); }
121      printf("Farbe fertig.\n");
122    return pattern;
123}
124
125error_t parse_option (int key, char *arg, struct argp_state *state) {
126    //printf("OPTION %x (%c = %i)...\n", key, key, key);
127    switch(key) {
128        case 'v':
129            verbosity = 1;
130            break;
131        case 'o': case 'i':
132            // Ausgabedatei setzen.
133            output_file = arg;
134            break;
135        case 'w':
136            // Breite setzen.
137            lochstreifen_set_d_by_width(l, atoi(arg));
138            break;
139        case 'h':
140            // Hoehe setzen.
141            lochstreifen_set_d_by_height(l, atoi(arg));
142            break;
143        case 'd':
144            // Durchmesser setzen
145            lochstreifen_set_d(l, atoi(arg));
146            break;
147        case 'f':
148            // Dateiformat setzen
149            // keine Lust auf enums
150            if(strcmp(strtolower(arg), "png") == 0) surface_type = 0;
151            else if(strcmp(strtolower(arg), "svg") == 0) surface_type = 1;
152            else argp_error(state, "Only PNG and SVG are supported as file formats.\n");
153            break;
154        case -1:
155            // Emptystart-Bytes
156            l->empty_start = atoi(arg);
157            break;
158        case -2:
159            // Emptyend-Bytes
160            l->empty_end = atoi(arg);
161            break;
162        case -3:
163            // hide imagebg
164            l->hintergrund = NULL;
165            break;
166        case -4:
167            // color imagebg
168            l->hintergrund = hex2cairo_pattern(arg);
169            break;
170        case -5:
171            // hide tape
172            l->streifenbg = NULL;
173            break;
174        case -6:
175            // color tapebg
176            l->streifenbg = hex2cairo_pattern(arg);
177            break;
178        case -7:
179            // hide punched
180            l->punched = NULL;
181            break;
182        case -8:
183            // color punched
184            l->punched = hex2cairo_pattern(arg);
185            break;
186        case -9:
187            // hide notpunched
188            l->notpunched = NULL;
189            break;
190        case -10:
191            // color notpunched
192            l->notpunched = hex2cairo_pattern(arg);
193            break;
194        case -11:
195            // hide feedholes
196            l->fuehrung = NULL;
197            break;
198        case -12:
199            // color fuerhung
200            l->fuehrung = hex2cairo_pattern(arg);
201            break;
202        case -13:
203            // rotation
204            if(strcmp(arg, "right") == 0) arg = "0";
205            else if(strcmp(arg, "bottom") == 0) arg = "1";
206            else if(strcmp(arg, "left") == 0) arg = "2";
207            else if(strcmp(arg, "top") == 0) arg = "3";
208            arg[1] = '\0'; // String ist jetzt auf jeden Fall nur ein zeichen lang
209            lochstreifen_set_direction(l, atoi(arg), -1, -1);
210            break;
211        case -14:
212            // horizontal spiegeln
213            lochstreifen_set_direction(l, -1, 1, -1);
214            break;
215        case -15:
216            // vertikal spiegeln
217            lochstreifen_set_direction(l, -1, -1, 1);
218            break;
219        //case ARGP_KEY_END:
220            //printf("bla...");
221        default:
222            return ARGP_ERR_UNKNOWN;
223    } // switch
224    return 0; // success
225}
226
227static struct argp argp = { options, parse_option, "[FILE TO READ FROM]", // Als Argument in der ersten Zeile
228    "This program uses cairo to draw a punched tape as a PNG or SVG file. Any binary " // Hilfe oben
229    "data are accepted via stdin or read in from the file given as argument. "
230    "The produced image is written into stdout or in the filename given by -o."
231    // mit \v danach koennte man ausfuehrliche Hilfe unten anzeigen.
232}; // static struct argp
233
234cairo_status_t* lochstreifen_out_closure(void *closure, unsigned char *data, unsigned int length) {
235    // einfach nur in das uebergebene Dateihandle schreiben
236    fwrite(data, length, 1, (FILE *)closure);
237    return CAIRO_STATUS_SUCCESS;
238}
239
240int main(int argc, char *argv[]) {
241    //unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
242    /*int x;
243    unsigned char data[256];
244    for(x=0;x<256;x++) {
245        data[x] = (unsigned char) x;
246    }
247    draw_lochstreifen(256, data);
248    return 0;*/
249    LOCHSTREIFEN *lochstreifen;
250    cairo_t *cr;
251    cairo_surface_t *surface;
252    byte_t *data;
253    int length; // laenge des *data-Arrays
254    FILE *out;
255    int input_argc; // Index der argv-Option, wo die zu handelnden Dateien stehen.
256    l = lochstreifen_new();
257    lochstreifen = l;
258
259    // Argumente parsen
260    argp_parse(&argp, argc, argv, 0, &input_argc, NULL);
261   
262    //DPRINTF("Stop.\n");
263    //return 0;
264
265    // Daten einlesen
266    if(input_argc < argc) {
267        FILE *fh;
268        DPRINTF("Reading from file %s\n", argv[input_argc]);
269        fh = fopen(argv[input_argc], "r");
270
271        if(fh == NULL) {
272            perror("opening input file");
273            exit(1);
274        }
275
276        length = file_get_contents(fh, &data);
277        fclose(fh);
278    } else {
279        DPRINTF("Reading from stdin, type [STRG]+[D] to generate paper tape from data\n");
280        length = file_get_contents(stdin, &data);
281    }
282    DPRINTF("Read in %d bytes\n", length);
283
284    // Ausgabestream oeffnen
285    if(output_file != NULL) {
286        out = fopen(output_file, "w");
287
288        if(out == NULL) {
289            perror("opening output file");
290            exit(1);
291        }
292        DPRINTF("File %s successfully opened for writing\n", output_file);
293    } else {
294        DPRINTF("Writing image data to stdout\n");
295        out = stdout;
296    }
297
298    /*int x;
299    for(x=0; x<length; x++) {
300        printf("%i von %i: 0x%x (=%c)\n", x, length, data[x], data[x]);
301    }*/
302
303    lochstreifen_set_data(l, length, data, -1, -1);
304
305    // Surface erstellen
306    if(surface_type == 0) { // PNG
307        cairo_status_t status;
308        surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
309            lochstreifen_get_width(l),
310            lochstreifen_get_height(l)
311        );
312        cr = cairo_create(surface);
313        lochstreifen_draw(l, cr);
314
315        status = cairo_surface_write_to_png_stream(surface, (cairo_write_func_t)lochstreifen_out_closure, out);
316        DPRINTF("paper tape PNG generated: %s\n", cairo_status_to_string(status));
317    } else if(surface_type == 1) { // SVG
318        surface = (cairo_surface_t *)cairo_svg_surface_create_for_stream(
319            lochstreifen_out_closure, out,
320            (double)lochstreifen_get_width(l),
321            (double)lochstreifen_get_height(l));
322
323        cr = cairo_create(surface);
324        lochstreifen_draw(l, cr);
325        DPRINTF("paper tape SVG generated: %s\n", cairo_status_to_string(cairo_surface_status(surface)));
326    } else {
327        fprintf(stderr, "Bad Surface Type %i", surface_type); 
328        return -42;
329    } // if surface_type
330
331    return 0;
332} // main
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License