Changeset 18 in projects


Ignore:
Timestamp:
Sep 15, 2008, 4:23:39 AM (11 years ago)
Author:
sven
Message:

This is a preview of the new visualisator subsystem: The new LOCHSTREIFEN
files. The CLI interface from cli.c is still the same like before, so it
should be compatible to the old LOCHSTREIFEN interface. All new routines
are still written in Plain C and well explained.

-- Sven @ workstation.

Location:
visualisator
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • visualisator/cli.c

    r9 r18  
    4242
    4343LOCHSTREIFEN *l;
    44 int surface_type = 0; // 0 = PNG, 1 = SVG
     44enum _surface_type {
     45        PNG_SURFACE,
     46        SVG_SURFACE
     47} surface_type;
    4548char *output_file;
    4649int verbosity = 0;
     50int null_bytes_start = 0;
     51int null_bytes_end = 0;
     52enum {
     53        SCALE_BY_LENGTH,
     54        SCALE_BY_WIDTH,
     55        SCALE_BY_CODE_HOLE,
     56} scale_by;
     57// scale_target == 0 implies: no scaling!
     58int scale_target = 0;
    4759
    4860#define DPRINTF(msg...) if(verbosity!=0) fprintf(stderr,msg);
     61
     62error_t parse_option (int key, char *arg, struct argp_state *state);
     63cairo_pattern_t *hex2cairo_pattern(const char *string);
    4964
    5065const char *argp_program_version = "Punch card visualisator - CLI frontend";
     
    6681    {"", 0, 0, OPTION_DOC, "",1},
    6782
    68     {"Empty bytes", 1, 0, OPTION_DOC, "Bytes with value=0 which are not content of files", 1},
     83    {"Empty bytes", 1, 0, OPTION_DOC, "Bytes with value=0x00 which are not content of files", 1},
    6984    {"empty-start", -1, "NUM", 0,        "Set number of empty bytes at beginning (default=0)", 2 },
    7085    {"empty-end",   -2, "NUM", 0,        "Set number of empty bytes at end (default=0)", 2 },
     
    93108};
    94109
    95 char *strtolower(char *string) {
    96     // komisch, ich dachte echt, es gaebe dafuer eine Funktion in C...
    97     int x=0;
    98     for(;string[x];x++) string[x] = tolower(string[x]);
    99 
    100     return string; // ja, ich veraenderte den Ursprungsstring. Egal ;-)
    101 }
    102 
    103 cairo_pattern_t *hex2cairo_pattern(const char *string) {
    104     /** Kriegt aus #RRGGBBAA oder #RGBA eine Cairo-Surface */
    105     char buf[2];   // zum temporaeren Speichern der einzelnen umzuwandelnden Zeichen
    106     buf[1] = '\0'; // nur ein Ein-Zeichen-String also
    107     int len = strlen(string);
    108     unsigned char numbers[8]; // rausgefundende Ziffern
    109     int numbers_count; // wie viele Ziffern rausgefunden
    110     cairo_pattern_t *pattern;
    111 
    112     // erst mal schauen, ob ne schoene Raute da ist und auf Laenge (entsprechendes Format)
    113     if(string[0] != '#' || (len != 4 && len != 5 && len != 7 && len != 9)) {
    114         fprintf(stderr, "Bad color: %s -- colors shall have format #RGB or #RRGGBB or #RGBA or #RRGGBBAA\n", string);
    115         exit(1);
    116     }
    117     string++; // das "#"-Zeichen braucht keiner mehr
    118 
    119     for(numbers_count=0; numbers_count < len-1; numbers_count++) {
    120         buf[0] = string[numbers_count];
    121         numbers[numbers_count] = strtol(buf, NULL, 16);
    122         //printf("Read digit %s = 0x%x\n", buf, numbers[numbers_count]);
    123     }
    124     //numbers_count++; // wir zaehlen ab 1 -- komisch, tud er sowieso schon.
    125 
    126     if(numbers_count == 3 || numbers_count == 4) {
    127         // #RGB oder #RGBA
    128         pattern = cairo_pattern_create_rgba(
    129             (double)numbers[0] / (double)0xF,
    130             (double)numbers[1] / (double)0xF,
    131             (double)numbers[2] / (double)0xF,
    132             (numbers_count == 4) ? (double)numbers[3] / (double)0xF : 1
    133         );
    134     } else {
    135         // #RRGGBB oder #RRGGBBAA
    136         pattern = cairo_pattern_create_rgba(
    137             (double)(numbers[1] + numbers[0]*0x10) / (double)0xFF,
    138             (double)(numbers[3] + numbers[2]*0x10) / (double)0xFF,
    139             (double)(numbers[5] + numbers[4]*0x10) / (double)0xFF,
    140             (numbers_count == 8) ? (double)(numbers[7] + numbers[6]*0x10) / (double)0xFF : 1
    141         );
    142     }
    143     // Fuer Debug-Ausgaben:
    144     { double r,g,b,a; cairo_pattern_get_rgba(pattern, &r, &g, &b, &a);
    145       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)); }
    146       printf("Farbe fertig.\n");
    147     return pattern;
    148 }
    149 
    150 error_t parse_option (int key, char *arg, struct argp_state *state) {
    151     //printf("OPTION %x (%c = %i)...\n", key, key, key);
    152     switch(key) {
    153         case 'v':
    154             verbosity = 1;
    155             break;
    156         case 'o': case 'i':
    157             // Ausgabedatei setzen.
    158             output_file = arg;
    159             break;
    160         case 'w':
    161             // Breite setzen.
    162             lochstreifen_set_d_by_width(l, atoi(arg));
    163             break;
    164         case 'h':
    165             // Hoehe setzen.
    166             lochstreifen_set_d_by_height(l, atoi(arg));
    167             break;
    168         case 'd':
    169             // Durchmesser setzen
    170             lochstreifen_set_d(l, atoi(arg));
    171             break;
    172         case 'f':
    173             // Dateiformat setzen
    174             // keine Lust auf enums
    175             if(strcmp(strtolower(arg), "png") == 0) surface_type = 0;
    176             else if(strcmp(strtolower(arg), "svg") == 0) surface_type = 1;
    177             else argp_error(state, "Only PNG and SVG are supported as file formats.\n");
    178             break;
    179         case -1:
    180             // Emptystart-Bytes
    181             l->empty_start = atoi(arg);
    182             break;
    183         case -2:
    184             // Emptyend-Bytes
    185             l->empty_end = atoi(arg);
    186             break;
    187         case -3:
    188             // hide imagebg
    189             l->hintergrund = NULL;
    190             break;
    191         case -4:
    192             // color imagebg
    193             l->hintergrund = hex2cairo_pattern(arg);
    194             break;
    195         case -5:
    196             // hide tape
    197             l->streifenbg = NULL;
    198             break;
    199         case -6:
    200             // color tapebg
    201             l->streifenbg = hex2cairo_pattern(arg);
    202             break;
    203         case -7:
    204             // hide punched
    205             l->punched = NULL;
    206             break;
    207         case -8:
    208             // color punched
    209             l->punched = hex2cairo_pattern(arg);
    210             break;
    211         case -9:
    212             // hide notpunched
    213             l->notpunched = NULL;
    214             break;
    215         case -10:
    216             // color notpunched
    217             l->notpunched = hex2cairo_pattern(arg);
    218             break;
    219         case -11:
    220             // hide feedholes
    221             l->fuehrung = NULL;
    222             break;
    223         case -12:
    224             // color fuerhung
    225             l->fuehrung = hex2cairo_pattern(arg);
    226             break;
    227         case -13:
    228             // rotation
    229             if(strcmp(arg, "right") == 0) arg = "0";
    230             else if(strcmp(arg, "bottom") == 0) arg = "1";
    231             else if(strcmp(arg, "left") == 0) arg = "2";
    232             else if(strcmp(arg, "top") == 0) arg = "3";
    233             arg[1] = '\0'; // String ist jetzt auf jeden Fall nur ein zeichen lang
    234             lochstreifen_set_direction(l, atoi(arg), -1, -1);
    235             break;
    236         case -14:
    237             // horizontal spiegeln
    238             lochstreifen_set_direction(l, -1, 1, -1);
    239             break;
    240         case -15:
    241             // vertikal spiegeln
    242             lochstreifen_set_direction(l, -1, -1, 1);
    243             break;
    244         //case ARGP_KEY_END:
    245             //printf("bla...");
    246         default:
    247             return ARGP_ERR_UNKNOWN;
    248     } // switch
    249     return 0; // success
    250 }
    251 
    252110static struct argp argp = { options, parse_option, "[FILE TO READ FROM]", // Als Argument in der ersten Zeile
    253111    "This program uses cairo to draw a punched tape as a PNG or SVG file. Any binary " // Hilfe oben
     
    257115}; // static struct argp
    258116
     117
     118error_t parse_option (int key, char *arg, struct argp_state *state) {
     119        //printf("OPTION %x (%c = %i)...\n", key, key, key);
     120        switch(key) {
     121                case 'v':
     122                        verbosity = 1;
     123                        break;
     124                case 'o': case 'i':
     125                        // Ausgabedatei setzen.
     126                        output_file = arg;
     127                        break;
     128                case 'w':
     129                        // set length (yeah, the legacy parameters call this width)
     130                        scale_by = SCALE_BY_LENGTH;
     131                        scale_target = atoi(arg);
     132                        //lochstreifen_set_scaling_by_length(l, atoi(arg));
     133                        break;
     134                case 'h':
     135                        // set width (yeah, the legacy parameters call this height)
     136                        scale_by = SCALE_BY_WIDTH;
     137                        scale_target = atoi(arg);
     138                        //lochstreifen_set_scaling_by_width(l, atoi(arg));
     139                        break;
     140                case 'd':
     141                        // set diameter of code holes
     142                        scale_by = SCALE_BY_CODE_HOLE;
     143                        scale_target = atoi(arg);
     144                        //lochstreifen_set_scaling_by_code_hole(l, atoi(arg));
     145                        break;
     146                case 'f':
     147                        // set file format
     148                        if(strcasecmp(arg, "png") == 0)
     149                                surface_type = PNG_SURFACE;
     150                        else if(strcasecmp(arg, "svg") == 0)
     151                                surface_type = SVG_SURFACE;
     152                        else
     153                                argp_error(state, "Only PNG and SVG are supported as file formats.\n");
     154                        break;
     155                case -1:
     156                        // set empty bytes at start
     157                        null_bytes_start = atoi(arg);
     158                        break;
     159                case -2:
     160                        // set empty bytes at end
     161                        null_bytes_end = atoi(arg);
     162                        break;
     163                case -3:
     164                        // hide imagebg
     165                        l->outer_background_color = NULL;
     166                        break;
     167                case -4:
     168                        // color imagebg
     169                        l->outer_background_color = hex2cairo_pattern(arg);
     170                        break;
     171                case -5:
     172                        // hide tape
     173                        l->papertape_background_color = NULL;
     174                        break;
     175                case -6:
     176                        // color tapebg
     177                        l->papertape_background_color = hex2cairo_pattern(arg);
     178                        break;
     179                case -7:
     180                        // hide punched
     181                        l->one_code_hole_color = NULL;
     182                        break;
     183                case -8:
     184                        // color punched
     185                        l->one_code_hole_color = hex2cairo_pattern(arg);
     186                        break;
     187                case -9:
     188                        // hide notpunched
     189                        l->zero_code_hole_color = NULL;
     190                        break;
     191                case -10:
     192                        // color notpunched
     193                        l->zero_code_hole_color = hex2cairo_pattern(arg);
     194                        break;
     195                case -11:
     196                        // hide feedholes
     197                        l->feed_hole_color = NULL;
     198                        break;
     199                case -12:
     200                        // color fuerhung
     201                        l->feed_hole_color = hex2cairo_pattern(arg);
     202                        break;
     203                case -13:
     204                        // rotation
     205                        if     (strcasecmp(arg, "right" ) == 0) arg = "0";
     206                        else if(strcasecmp(arg, "bottom") == 0) arg = "1";
     207                        else if(strcasecmp(arg, "left"  ) == 0) arg = "2";
     208                        else if(strcasecmp(arg, "top"   ) == 0) arg = "3";
     209                        arg[1] = '\0'; // shorten string to one character
     210                        //lochstreifen_set_direction(l, atoi(arg));
     211                        lochstreifen_set_rotation(l, atoi(arg));
     212                        break;
     213                case -14:
     214                        // horizontal spiegeln
     215                        //lochstreifen_set_direction(l, -1, 1, -1);
     216                        break;
     217                case -15:
     218                        // vertikal spiegeln
     219                        //lochstreifen_set_direction(l, -1, -1, 1);
     220                        break;
     221                //case ARGP_KEY_END:
     222                        //printf("bla...");
     223                default:
     224                        return ARGP_ERR_UNKNOWN;
     225        } // switch
     226        return 0; // success
     227} // function parse_option
     228
     229
     230/**
     231 * Simple helper function to get a SOLID cairo pattern from a hex color string
     232 * with formats like
     233 *   #RGB          for example:   #FF0
     234 *   #RGBA                        #A88F
     235 *   #RRGGBB                      #CD438F
     236 *   #RRGGBBAA                    #CD438FA0
     237 *   RGB                          FF0
     238 *   RGBA                         A88F
     239 *   RRGGBB                       CD438F
     240 *   RRGGBBAA                     CD438FA0
     241 *
     242 * If this method cannot parse the hex color string, it will print an error message
     243 * at stderr and exit the complete program.
     244 *
     245 * @return a dynamically allocated cairo patern
     246 **/
     247cairo_pattern_t *hex2cairo_pattern(const char *string) {
     248        int string_len;        // length of string without "#"
     249        int x, color;          // iterators
     250        long color_value[4]; // interpreted numbers
     251        char *buf = "xy";       // Buffer for strtol <- one color value
     252       
     253        // remove a "#" char if present
     254        if(string[0] == '#')
     255                string++;
     256        string_len = strlen(string);
     257       
     258        // go throught string
     259        for(x=0,color=0; x < string_len && color < 5; x++,color++) {
     260                // copy the current character to buffer, first position
     261                buf[0] = string[x];
     262                // if short notation (shorter than AABBCC), dublicate
     263                // current character to buffer second position, else
     264                // copy next character to second position
     265                buf[1] = string_len < 6 ? string[x] : string[++x];
     266                // parse buffer contents and save them as one color
     267                color_value[color] = strtol(buf, NULL, 16);
     268        }
     269       
     270        DPRINTF("Allocating '%s' as #%x%x%x%x\n", string,
     271                color_value[0], color_value[1], color_value[2], (color == 4) ? color_value[3] : 0xFF);
     272       
     273        return cairo_pattern_create_rgba(
     274                (double) color_value[0] / (double) 0xFF,
     275                (double) color_value[1] / (double) 0xFF,
     276                (double) color_value[2] / (double) 0xFF,
     277                (color == 4) ? (double) color_value[3] / (double) 0xFF : 1
     278        );
     279}
     280
     281/**
     282 * Helper function: Read contents from a stream (e.g. stdin or a file) into
     283 * a byte array.
     284 * Expects: stream (FILE) and a pointer to a pointer (for the target array)
     285 * It will allocate an array whereby you get the pointer back.
     286 * @return length of data array, counting from 1
     287 *
     288 * I've inspired a bit from glib's g_file_get_contents because my first
     289 * version was quite buggy:
     290 *****
     291     * Neugeschrieben nach etwas Inspiration von der glib am 05.04.2008.
     292     * Funktion get_contents_stdio, gfileutils.c im Sourcecode von glib-2.14.3.
     293     * Router natürlich aus (03:11!), aber da sieht man mal wieder den Vorteil von Gentoo:
     294     * Gleich alle Sourcecodes auf der Platte =)
     295 *****
     296 *
     297 **/
     298int file_get_contents(FILE *stream, byte_t **content) {
     299        byte_t buf[4096];
     300        size_t bytes; // gerade eben eingelesene bytes
     301        byte_t *str = NULL;
     302        size_t total_bytes = 0;     // alle bis jetzt eingelesenen bytes
     303        size_t total_allocated = 0;
     304        byte_t *tmp; // fuers realloc
     305
     306        while(!feof(stream)) {
     307                bytes = fread(buf, 1, sizeof(buf), stream);
     308
     309                while( (total_bytes + bytes) > total_allocated) {
     310                        if(str)
     311                                total_allocated *= 2;
     312                        else
     313                                total_allocated = bytes > sizeof(buf) ? bytes : sizeof(buf);
     314
     315                        tmp = realloc(str, total_allocated);
     316
     317                        if(tmp == NULL) {
     318                                fprintf(stderr, "*** file_get_contents ERROR*** Could not reallocate\n");
     319                                //return length; // Fehler - das eingelesene zumindest zurueckgeben.
     320                                // nee, gar nichts zurückgeben. Das geht so nicht.
     321                                return 0;
     322                        }
     323
     324                        str = tmp;
     325                } // while innen
     326
     327                memcpy(str + total_bytes, buf, bytes);
     328                total_bytes += bytes;
     329        } // while
     330
     331        if(total_allocated == 0)
     332                str = malloc(1); // something empty. Just to be not NULL...
     333        //str[total_bytes] = '\0'; // wenns ein string wäre.
     334
     335        *content = str;
     336        return total_bytes;
     337}
     338
     339/**
     340 * Helper function: A simple closure for a cairo_surface_t (PNG and SVG) to write out data
     341 * either to a file or to stdout (given in first parameter)
     342 **/
    259343cairo_status_t lochstreifen_out_closure(void *closure, unsigned char *data, unsigned int length) {
    260     // einfach nur in das uebergebene Dateihandle schreiben
    261     fwrite(data, length, 1, (FILE *)closure);
    262     return CAIRO_STATUS_SUCCESS;
     344        // einfach nur in das uebergebene Dateihandle schreiben
     345        fwrite(data, length, 1, (FILE *)closure);
     346        return CAIRO_STATUS_SUCCESS;
    263347}
    264348
     349/**
     350 * The main routine.
     351 **/
    265352int main(int argc, char *argv[]) {
    266     //unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
    267     /*int x;
    268     unsigned char data[256];
    269     for(x=0;x<256;x++) {
    270         data[x] = (unsigned char) x;
    271     }
    272     draw_lochstreifen(256, data);
    273     return 0;*/
    274     LOCHSTREIFEN *lochstreifen;
    275     cairo_t *cr;
    276     cairo_surface_t *surface;
    277     byte_t *data;
    278     int length; // laenge des *data-Arrays
    279     FILE *out;
    280     int input_argc; // Index der argv-Option, wo die zu handelnden Dateien stehen.
    281     l = lochstreifen_new();
    282     lochstreifen = l;
    283 
    284     // Argumente parsen
    285     argp_parse(&argp, argc, argv, 0, &input_argc, NULL);
    286    
    287     //DPRINTF("Stop.\n");
    288     //return 0;
    289 
    290     // Daten einlesen
    291     if(input_argc < argc) {
    292         FILE *fh;
    293         DPRINTF("Reading from file %s\n", argv[input_argc]);
    294         fh = fopen(argv[input_argc], "r");
    295 
    296         if(fh == NULL) {
    297             perror("opening input file");
    298             exit(1);
    299         }
    300 
    301         length = file_get_contents(fh, &data);
    302         fclose(fh);
    303     } else {
    304         DPRINTF("Reading from stdin, type [STRG]+[D] to generate paper tape from data\n");
    305         length = file_get_contents(stdin, &data);
    306     }
    307     DPRINTF("Read in %d bytes\n", length);
    308 
    309     // Ausgabestream oeffnen
    310     if(output_file != NULL) {
    311         out = fopen(output_file, "w");
    312 
    313         if(out == NULL) {
    314             perror("opening output file");
    315             exit(1);
    316         }
    317         DPRINTF("File %s successfully opened for writing\n", output_file);
    318     } else {
    319         DPRINTF("Writing image data to stdout\n");
    320         out = stdout;
    321     }
    322 
    323     /*int x;
    324     for(x=0; x<length; x++) {
    325         printf("%i von %i: 0x%x (=%c)\n", x, length, data[x], data[x]);
    326     }*/
    327 
    328     lochstreifen_set_data(l, length, data, -1, -1);
    329 
    330     // Surface erstellen
    331     if(surface_type == 0) { // PNG
    332         cairo_status_t status;
    333         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
    334             lochstreifen_get_width(l),
    335             lochstreifen_get_height(l)
    336         );
    337         cr = cairo_create(surface);
    338         lochstreifen_draw(l, cr);
    339 
    340         status = cairo_surface_write_to_png_stream(surface, (cairo_write_func_t)lochstreifen_out_closure, out);
    341         DPRINTF("paper tape PNG generated: %s\n", cairo_status_to_string(status));
    342     } else if(surface_type == 1) { // SVG
    343         surface = (cairo_surface_t *)cairo_svg_surface_create_for_stream(
    344             (cairo_write_func_t)lochstreifen_out_closure, out,
    345             (double)lochstreifen_get_width(l),
    346             (double)lochstreifen_get_height(l));
    347 
    348         cr = cairo_create(surface);
    349         lochstreifen_draw(l, cr);
    350         DPRINTF("paper tape SVG generated: %s\n", cairo_status_to_string(cairo_surface_status(surface)));
    351     } else {
    352         fprintf(stderr, "Bad Surface Type %i", surface_type);
    353         return -42;
    354     } // if surface_type
    355 
    356     return 0;
     353        cairo_t *cr;                ///< A cairo context, given from...
     354        cairo_surface_t *surface;   ///< ...this generic cairo surface
     355        byte_t *data;               ///< the data array, will be filled by file_get_contents
     356        int length;                 ///< the length of that data array
     357        FILE *out;                  ///< an output stream handle (stdout or a file)
     358        int input_argc;             ///< argp: index of argv argument where the filenames are stored
     359       
     360        // now starting...
     361        l = lochstreifen_new();
     362        argp_parse(&argp, argc, argv, 0, &input_argc, NULL);
     363       
     364        // read input data to data array
     365        if(input_argc < argc && argv[input_argc][0] != '-') {
     366                // open a file (which name is not "-", because this shall read from STDIN)
     367                FILE *fh;
     368                DPRINTF("Reading from file %s\n", argv[input_argc]);
     369                fh = fopen(argv[input_argc], "r");
     370
     371                if(fh == NULL) {
     372                        perror("opening input file");
     373                        exit(1);
     374                }
     375
     376                length = file_get_contents(fh, &data);
     377                fclose(fh);
     378        } else {
     379                DPRINTF("Reading from stdin, type [STRG]+[D] to generate paper tape from data\n");
     380                length = file_get_contents(stdin, &data);
     381        }
     382
     383        DPRINTF("Successfully read in %d bytes to RAM\n", length);
     384       
     385        // now after bytes are read in, we can setup the LOCHSTREIFEN
     386        // correctly:
     387        lochstreifen_set_data(l, length, data);
     388        if(scale_target != 0) { // initialized
     389                switch(scale_by) {
     390                        case SCALE_BY_LENGTH:
     391                                lochstreifen_set_scaling_by_length(l, scale_target);
     392                                break;
     393                        case SCALE_BY_WIDTH:
     394                                lochstreifen_set_scaling_by_width(l, scale_target);
     395                                break;
     396                        case SCALE_BY_CODE_HOLE:
     397                                lochstreifen_set_scaling_by_code_hole(l, scale_target);
     398                }
     399        }
     400        // add null bytes
     401        lochstreifen_add_null_bytes(l, null_bytes_start, null_bytes_end);
     402
     403        // open output stream
     404        if(output_file != NULL) { // check if there was an argv argument
     405                out = fopen(output_file, "w");
     406
     407                if(out == NULL) {
     408                        perror("opening output file");
     409                        exit(1);
     410                }
     411                DPRINTF("Opened file '%s' for writing\n", output_file);
     412        } else {
     413                DPRINTF("Writing output data to stdout\n");
     414                out = stdout;
     415        }
     416       
     417        lochstreifen_print_debug(l);
     418        exit(0);
     419
     420        // setting up the surface and painting...
     421        if(surface_type == PNG_SURFACE) {
     422                cairo_status_t status;
     423                surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
     424                        lochstreifen_get_target_width(l),
     425                        lochstreifen_get_target_height(l)
     426                );
     427                cr = cairo_create(surface);
     428                lochstreifen_draw(l, cr);
     429
     430                status = cairo_surface_write_to_png_stream(surface, (cairo_write_func_t)lochstreifen_out_closure, out);
     431                DPRINTF("PNG file generated: %s\n", cairo_status_to_string(status));
     432                return 0;
     433        } else if(surface_type == SVG_SURFACE) {
     434                surface = cairo_svg_surface_create_for_stream(
     435                        (cairo_write_func_t)lochstreifen_out_closure, out,
     436                        lochstreifen_get_target_width(l),
     437                        lochstreifen_get_target_height(l)
     438                );
     439                cr = cairo_create(surface);
     440                lochstreifen_draw(l, cr);
     441
     442                DPRINTF("SVG file generated: %s\n", cairo_status_to_string(cairo_surface_status(surface)));
     443                return 0;
     444        } else {
     445                fprintf(stderr, "This surface is not possible, because surface_typ is an enum.\n");
     446                return -42;
     447        } // if surface_type
    357448} // main
  • visualisator/lochstreifen.c

    r9 r18  
    11/**
    2  * Lochstreifen mit Cairo zeichnen
    3  *
    4  * Diese Datei stellt ein Objekt (LOCHSTREIFEN) zur Verfuegung,
    5  * welches mit Cairo Lochstreifen auf vielfaeltige Weise rendern
    6  * kann. Ueber die zahlreichen Funktionen koennen die Variablen
    7  * eingestellt werden.
    8  *
    9  * Diese Lochstreifenroutinen sind bewusst nur mit Cairo programmiert
    10  * worden (kompilieren mit `pkg-config --cflags --libs cairo`), sie
    11  * benoetigen kein installiertes GTK oder Glib.
    12  *
    13  * Die Variationsmoeglichkeiten fuer die gezeichneten Lochstreifen
    14  * sind sehr vielfaeltig und koennen einzeln voellig frei miteinander
    15  * kombiniert werden. So kann man saemtliche geometrischen Abstaende
    16  * aendern (Abstand der Lochreihen, Lochspalten, Fuehrungloecher,
    17  * Durchmesser der unterschiedlichen Loecher, Abstaende in und um
    18  * den Lochstreifen, usw.) oder verhaeltnissmaessig angeben.
    19  * Ausserdem laesst sich der Lochstreifen sehr leicht in 45°-Schritten
    20  * drehen oder um beide Achsen spiegeln. Saemtliche Farben sind frei
    21  * einstellbar, einzelne Objekte koennen auf Wunsch auch nicht
    22  * gezeichnet werden.
    23  *
    24  * Anzumerken sei auch, dass diese Routinen nur die Zeichenarbeit
    25  * uebernehmen -- das Cairoobjekt muss das Programm stellen. Damit sind
    26  * voellige Freiheiten zur Wahl der Cairo-Surface gegeben (SVG, PNG,
    27  * PDF, ... -- alles moeglich, Cairo eben). Da man bei der Erstellung
    28  * einer Cairosurface ueblicherweise Groessenangaben braucht, kriegt
    29  * man diese aus den aktuellen Parametern berechnet mit
    30  * lochstreifen_get_width und lochstreifen_get_height.
    31  *
    32  * Fuer die Bedeutung der einzelnen Felder der LOCHSTREIFEN-Struktur
    33  * siehe Header-File, fuer genauere Erklaerungen zu den Funktionen
    34  * siehe direkt bei deren Implementierungen (diese Datei).
    35  *
    36  * sven, im November 2007.
    37  *
    38  **/
     2 * The Paper Tape Project -- Visualisation sub project
     3 * lochstreifen.c - Painting Paper Tapes according to ECMA-10, with cairographics.
     4 * $Id$
     5 *
     6 * This is a rewrite from the famous Cairo paper tape drawing routines. This
     7 * c file implements a (simple) object called "LOCHSTREIFEN".
     8 *
     9 *
     10 *
     11 *
     12 *
     13 * (c) Copyright 2007, 2008 Sven Köppel
     14 *
     15 *  This program is free software; you can redistribute
     16 *  it and/or modify it under the terms of the GNU General
     17 *  Public License as published by the Free Software
     18 *  Foundation; either version 3 of the License, or (at
     19 *  your option) any later version.
     20 *
     21 *  This program is distributed in the hope that it will
     22 *  be useful, but WITHOUT ANY WARRANTY; without even the
     23 *  implied warranty of MERCHANTABILITY or FITNESS FOR A
     24 *  PARTICULAR PURPOSE. See the GNU General Public License
     25 *  for more details.
     26 *
     27 *  You should have received a copy of the GNU General
     28 *  Public License along with this program; if not, see
     29 *  http://www.gnu.org/licenses/
     30 *
     31 **/
     32
    3933#include <math.h>
    4034#include <stdio.h>
    4135#include <stdlib.h>
    4236#include <string.h>
    43 
    4437#include "lochstreifen.h"
    4538
    46 #define DEBUG 1
    47 
    48 int file_get_contents(FILE *stream, byte_t **content) {
    49     /**
    50     * Kleine Behelfsfunktion, die den stream (z.B. stdin, eine Datei) als Bytes
    51     * komplett einliest.
    52     * Erwartet: Stream, Zeiger auf Zeiger (für Array)
    53     * Gibt zurück:  Return-value:      Laenge von content, rechnend ab 1
    54     *               Call-by-reference: Content wird alloziiert als Array mit Inhalt
    55     *
    56     * Erzeugt seltsamerweise manchmal komische Fehler,
    57     * g_file_get_contents von Glib funktioniert zuverlaessiger.
    58     **/
    59     // das war meine Version, bevor ich mir alles von g_file_get_contents
    60     // abgeschaut habe. Einen Fehler hab ich zumindest gerade entdeckt:
    61     // realloc gibt ggf. einen neuen Pointer zurück. Das würde erklären, warum auch
    62     // das ganze *mal* ging und *mal* nicht. Offensichtlich kopiert realloc dann auch
    63     // die Daten, wenn es entscheidet, sie woanders auf dem heap abzusieldeln...
    64     /*
    65     // um wie viel Zeichen das dynamische Array jeweils erhoeht werden soll
    66     // ein Kompromiss zwischen Platzverschwendung (zuviel allokatierter aber ungenutzter
    67     // Speicher) und Perfomance beim Einlesen (zu oft das Array erweitern)
    68     #define FILE_GET_CONTENT_STEPSIZE 20
    69 
    70     int length;
    71     int extended = 1; // wie oft bereits erweitert
    72     *content = (byte_t*) malloc(sizeof(byte_t) * FILE_GET_CONTENT_STEPSIZE);
    73     if(*content == NULL) return 0; // schlecht.
    74 
    75     for(length=0;;) {
    76         (*content)[length] = (byte_t)fgetc(stream);
    77         if(feof(stream) != 0) break; // EOF vor dem Einlesen!
    78         printf("%03d. Zeichen eingelesen: 0x%02X (=%c)\n", length+1, (*content)[length], (*content)[length]);
    79         if(extended*FILE_GET_CONTENT_STEPSIZE == ++length) {// Speicherende erreicht?
    80              printf("=> Bereits %d mal den %d-Puffer verwendet, erweitere auf %d...\n", extended, FILE_GET_CONTENT_STEPSIZE, (extended+1)*FILE_GET_CONTENT_STEPSIZE);
    81              if(realloc(*content, sizeof(byte_t)*(++extended)*FILE_GET_CONTENT_STEPSIZE) == NULL) // Speicher vergroessern
    82                  return length; // Fehler - das eingelesene zumindest zurueckgeben.
    83         }
    84     }
    85 
    86     return length; // wir wollen ab 1 zaehlen, das wurde indirekt durch den letzten unnoetigen ++inkrement gemacht
    87     }
    88     int file_get_contents(FILE *stream, byte_t **content) {
    89     */
    90     /**
    91      * Neugeschrieben nach etwas Inspiration von der glib am 05.04.2008.
    92      * Funktion get_contents_stdio, gfileutils.c im Sourcecode von glib-2.14.3.
    93      * Router natürlich aus (03:11!), aber da sieht man mal wieder den Vorteil von Gentoo:
    94      * Gleich alle Sourcecodes auf der Platte =)
    95      *
    96      *
    97      *
    98      **/
    99      // *stream = *f
    100      // *content = **contents
    101      // gsize *length
    102 
    103      byte_t buf[4096];
    104      size_t bytes; // gerade eben eingelesene bytes
    105      byte_t *str = NULL;
    106      size_t total_bytes = 0;     // alle bis jetzt eingelesenen bytes
    107      size_t total_allocated = 0;
    108      byte_t *tmp; // fuers realloc
    109 
    110      while(!feof(stream)) {
    111          bytes = fread(buf, 1, sizeof(buf), stream);
    112 
    113          while( (total_bytes + bytes) > total_allocated) {
    114              if(str)
    115                  total_allocated *= 2;
    116              else
    117                  total_allocated = bytes > sizeof(buf) ? bytes : sizeof(buf);
    118 
    119              tmp = realloc(str, total_allocated);
    120 
    121              if(tmp == NULL) {
    122                  fprintf(stderr, "*** file_get_contents ERROR*** Could not reallocate\n");
    123                  //return length; // Fehler - das eingelesene zumindest zurueckgeben.
    124                  // nee, gar nichts zurückgeben. Das geht so nicht.
    125                  return 0;
    126              }
    127 
    128              str = tmp;
    129         } // while innen
    130 
    131         memcpy(str + total_bytes, buf, bytes);
    132         total_bytes += bytes;
    133      } // while
    134 
    135      if(total_allocated == 0)
    136          str = malloc(1); // ein leerer String halt.
    137 
    138      //str[total_bytes] = '\0'; // wenns ein string wäre.
    139 
    140      *content = str; // WAS: *content = str.
    141 
    142      return total_bytes;
    143 }
    144 
    145 void lochstreifen_set_color(cairo_pattern_t *color, byte_t red, byte_t green, byte_t blue, byte_t alpha) {
    146     /** Kleine Befehlsfunktion, die ein Cairopattern erzeugt. Farbwerte zwischen 0 und 255.
    147         alpha = 255 ist unnoetig => einfach das Patternobjekt auf NULL setzen und die Zeichenfunktion
    148         wird es nicht zeichnen. */
    149     color = cairo_pattern_create_rgba(red/255, green/255, blue/255, alpha/255);
    150 }
    151 
    152 
     39/**
     40 * Create a new LOCHSTREIFEN object and return it. This is a quite light
     41 * object system implementation, as you get a reference to the object.
     42 * You are not supposed to manipulate the elements of the LOCHSTREIFEN
     43 * structure directly.
     44 *
     45 * Btw, the german word "LOCHSTREIFEN" only means "PAPER TAPE".
     46 *
     47 **/
    15348LOCHSTREIFEN *lochstreifen_new() {
    154     /** Neues Lochstreifenobjekt erzeugen */
    155     LOCHSTREIFEN *l = malloc(sizeof(LOCHSTREIFEN));
    156     // Defaultwerte setzen:
    157     l->d = 10;
    158     l->data_length = 0;
    159     l->data = NULL;
    160     l->empty_start = 0;
    161     l->empty_end = 0;
    162     l->debug = 0;
    163     l->hintergrund = NULL; // nicht zeichnen
    164     l->streifenbg = cairo_pattern_create_rgb(0.7,0.7,0.7);
    165     l->punched = cairo_pattern_create_rgb(0,0,0);
    166     l->notpunched = cairo_pattern_create_rgb(0.827, 0.827, 0.827); //220/255, 220/255, 220/255);
    167     l->fuehrung = cairo_pattern_create_rgb(143/255, 175/255, 255/255);
    168     //cairo_matrix_init_identity(&(l->transformation));
    169         //, 1, 0, 0, 1, 0, 0); // Standardmatrix einrichten (keine Drehung)
    170     l->drehung = 0;
    171     l->spiegelung_hor = 0;
    172     l->spiegelung_ver = 0;
    173     l->highlight_byte = 0;
    174     l->highlight_color = NULL;
    175     lochstreifen_flush_only_start_area(l);
    176     return l;
    177 }
    178 
    179 void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end) {
    180     /** Zu druckende Daten eingeben, Anzahl gewuenschter Leerbytes vorne/hinten eingeben,
    181         ist empty_start/empty_end < 0, wird das entsprechende nicht gesetzt */
    182     l->data_length = data_length;
    183     if(l->data != NULL) // unbenutzten Speicher freigeben!
    184         free(l->data);
    185     l->data = data;
    186     if(empty_start >= 0) l->empty_start = empty_start;
    187     if(empty_end >= 0) l->empty_end = empty_end;
    188 }
    189 
    190 void lochstreifen_set_highlight(LOCHSTREIFEN* l, int byte_number) {
    191     l->highlight_byte = byte_number;
    192     if(l->highlight_color == NULL)
    193         l->highlight_color = cairo_pattern_create_rgb(242/255, 255/255, 0);
    194 }
    195 
    196 int lochstreifen_set_only_start_area(LOCHSTREIFEN *l, int x, int y, int width, int height) {
    197     /** Clipping-Rechteck setzen. Damit wird beim naechsten Zeichnen nur in diesem
    198         Bereich gezeichnet. Es handelt sich jedoch um kein exiplites ordentliches
    199         cairo_clipping, sondern eine grobe Naehrung zwecks Perfomance.
    200         Die Koordinaten beziehen sich auf die entgueltige Form (inkl. Drehung, ...)
    201     */
    202     l->only_start_x = x;
    203     l->only_start_y = y;
    204     l->only_width = width;
    205     l->only_height = height;
    206     return 0; // could make void.
    207 }
    208 
    209 int lochstreifen_flush_only_start_area(LOCHSTREIFEN *l) {
    210     /** Clipping-Rechteck loeschen -- beim naechsten Zeichnen alles zeichnen */
    211     l->only_start_x = 0;
    212     l->only_start_y = 0;
    213     l->only_width = 0;
    214     l->only_height = 0;
    215     return 0; // yeah, void would be correct.
    216 }
    217 
    218 void lochstreifen_set_d(LOCHSTREIFEN *l, int d) {
    219     /** Durchmesser eines Loches uebergeben (allgemeine Referenzeinheit fuer Dimensionen) */
    220     l->d = d;
    221     l->bspace = d*0.7/1.9;  // Abstand der Bytes voneinander (Reihen)
    222     l->hspace = d/2;  // Abstand der Loecher in der Bytereihe
    223     l->padding = d; // Abstand Löcher <=> Lochstreifenrand
    224     l->df = d/2; // Durchmesser Lochfuehrungsloch
    225     l->fspace = 1.1*(d+ l->hspace); // Breite der Lochfuehrungs"nut"
    226     l->margin = d*2; // Abstand um Lochstreifen herum (an allen Seiten)
    227     l->abriss = (8*d+6* l->hspace + l->fspace)/2; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
    228 }
    229 
    230 int lochstreifen_get_orientation(LOCHSTREIFEN *l) {
    231     /** Gibt die Orientierung des Lochstreifens zurueck; 1 = horizontal, 0 = vertikal */
    232     return (l->drehung % 2 == 0) ? 1 : 0;
    233 }
    234 
    235 int lochstreifen_get_width(LOCHSTREIFEN *l) {
    236     /** Berechnet aktuelle Breite aus Lochstreifenkonstanten */
    237     // interne Ersetzungen...
    238     #define LOCHSTREIFEN_WIDTH  2*l->abriss + 2*l->margin + \
    239         (l->data_length + l->empty_start + l->empty_end) * (l->d + l->bspace) - l->bspace // ein bspace zuviel am Ende
    240     #define LOCHSTREIFEN_HEIGHT 8*l->d + 6*l->hspace + l->fspace + l->margin*2 + l->padding*2 \
    241                                      //  ^ weil letztes hspace + hspace über fspace unnötig
    242     return (l->drehung % 2 == 0) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
    243 }
    244 
    245 int lochstreifen_get_height(LOCHSTREIFEN *l) {
    246     /** Berechnet aktuelle Hoehe aus Lochstreifenkonstanten */
    247     return (l->drehung % 2 == 1) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
    248 }
    249 
    250 void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width) {
    251     /**
    252      * Umkehrfunktion zu set_d (dort wird die Breite/Hoehe durch d berechnet),
    253      * hier wird d durch die vorgegebene Breite berechnet. Die Hoehe ergibt
    254      * sich dann natuerlich auch automatisch.
    255      * Evventuelle Drehungen werden miteinberechnet, d.h. wenn der Lochstreifen
    256      * z.B. nach oben/unten zeigt, bezieht sich width auf die "echte" Hoehe.
    257      **/
    258     // Gleichung zum Berechnen von LOCHSTREIFEN_WIDTH nach
    259     // d aufgeloest mit MuPad Pro 3.2 ( ;-) )
    260     #define LOCHSTREIFEN_INV_WIDTH  (double) (1 / (6187./380. + 26./19. * (double)(l->data_length + l->empty_start + l->empty_end)))
    261     #define LOCHSTREIFEN_INV_HEIGHT  (double) (1 * 20./373.)
    262     lochstreifen_set_d(l,
    263         (int)rint((double)width * ((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
    264     );
    265     //printf("Width soll %d ==> %d | %d\n", width, lochstreifen_get_width(l), lochstreifen_get_height(l));
    266 }
    267 
    268 void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height) {
    269     /**
    270      * Siehe set_d_by_width, nur wird hier d abhaengig von der gewuenschten Hoehe
    271      * berechnet.
    272      **/
    273     lochstreifen_set_d(l,
    274         (int)rint((double) height * LOCHSTREIFEN_INV_HEIGHT) //((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
    275     );
    276     //printf("Height soll %03d ==> d=%02d | %f, w/h = %03d | %03d\n", height, l->d,
    277     //    (double)height*LOCHSTREIFEN_INV_HEIGHT
    278     //    , lochstreifen_get_width(l), lochstreifen_get_height(l));
    279 }
    280 
    281 void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver) {
    282     /**
    283      * Transformationen der Lochstreifenausrichtung
    284      * drehung: 0 = Kopf nach links
    285      *          1 = oben
    286      *          2 = rechts
    287      *          3 = unten
    288      *         -1 = nicht aendern
    289      *          4 = um 90° im Uhrzeigersinn drehen
    290      *          5 = um 90° gegen Uhrzeigersinn drehen
    291      * Spiegelung horizontal/vertikal: 0 = nein
    292      *                                 1 = ja
    293      *                                 2 = vertauschen
    294      *                                -1 = nicht aendern
    295      **/
    296      if(drehung >= 0) {
    297          // Das "Ausprobieren" zwecks "Autodrehung" mit Aufruf wie
    298          // lochstreifen_set_direction(l, l->drehung++, -1, -1);
    299          //if(drehung > 4) drehung -= 4; // bei zu grossen Werten mal ausprobieren
    300          //if(drehung < 0) drehung += 4; // bei zu kleinen Werten mal ausprobieren
    301          //if(drehung % 4 == 0) drehung = 0; // quasi keine Drehung
    302          if(drehung >= 4) {
    303              if(drehung == 4) l->drehung++;
    304              else if(drehung == 5) l->drehung--;
    305              if(l->drehung >= 4) l->drehung -= 4; // bei zu grossen Werten
    306              if(l->drehung < 0) l->drehung += 4; // bei zu kleinen Werten
    307          } else {
    308              //if(drehung > 0 && drehung < 4) // gute Werte
    309              // normale Drehung mit festem Zielwert
    310              l->drehung = drehung;
    311          }
    312      }
    313      if(spiegelung_hor > -1) {
    314          if(spiegelung_hor == 2) l->spiegelung_hor = l->spiegelung_hor == 0 ? 1 : 0; // negotieren
    315          else l->spiegelung_hor = spiegelung_hor; // normal
    316      }
    317      if(spiegelung_ver > -1) {
    318          if(spiegelung_ver == 2) l->spiegelung_ver = l->spiegelung_ver == 0 ? 1 : 0; // negotieren
    319          else l->spiegelung_ver = spiegelung_ver; // normal
    320      }
    321 }
    322 
    323 /*
    324 void lochstreifen_rotate(LOCHSTREIFEN *l) {
    325     **
    326      * Wird den Lochstreifen beim naechsten Zeichnen um 45° mit dem
    327      * Uhrzeigersinn rotiert anzeigen. Nur mit diesen Funktionen wird
    328      * die Hoehen/Breitenberechnung im Vorhinein noch funktionieren!
    329      **
    330      cairo_matrix_rotate(&(l->transformation), M_PI);
    331      cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0),
    332      l->drehung++; // ...
    333 }
    334 
    335 void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal) {
    336     **
    337      * Spiegelt den Lochstreifen, ist horizontal = 1 dann horizontal,
    338      * sonst vertikal (oder so aehnlich)
    339      **
    340      if(horizontal != 0) { // vertikal
    341          cairo_matrix_scale(&(l->transformation), -1, 1);
    342          cairo_matrix_translate((&l->transformation), 0, lochstreifen_get_height(l));
    343      } else {
    344          cairo_matrix_scale(&(l->transformation), 1, -1);
    345          cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0);
    346      }
    347 }
    348 */
    349 
    350 int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y) {
    351      /**
    352       * Anhand der Koordinaten (x|y) wird der Index des Bytes (fuers Datenarray, ab 1 zaehlend),
    353       * welches damit "erfasst" wird, zurueckgegeben.
    354       * Befindet sich (x|y) nicht im Bereich eines Bytes, dann wird je nach Fall zurueckgegeben:
    355       *    0 = ausserhalb Lochstreifens
    356       *   -1 = in Emptystart/Emptyend-Bytes (die nicht in der Datei existieren)
    357       *        oder in Abrissbereichen
    358       **/
    359     int byte;
    360     // BETRACHTUNG HORIZONTALE AUSRICHTUNG
    361 
    362     if(y <= l->margin || y >= LOCHSTREIFEN_HEIGHT - l->margin) return 0; // ueber/unter Lochstreifen
    363     x -= l->margin; // erst mal Rand abziehen
    364     if(x <= 0) return 0; // links neben dem Lochstreifen.
    365     x -= l->abriss + (l->empty_start)*(l->d + l->bspace); // Emptystart+Abrissbereich
    366     if(x <= 0) return -1; // in diesem Bereich gewesen
    367     // jetzt sind wir im Bytebereich
    368     byte = (int) (x / (l->d + l->bspace)) + 1; // Abrunden: Auf welchem Byte man ist + ab 1 zaehlen.
    369     if(byte > l->data_length + l->empty_start) return 0; // komplett ausserhalb Lochstreifens
    370     else if(byte > l->data_length) return -1; // im Emptyendbereich
    371     else return byte; // im gueltigen Bereich -- Byte gefunden!
    372 }
    373 
    374 int lochstreifen_coordinate_by_byte(LOCHSTREIFEN *l, int byte) {
    375     /**
    376      * Anhang eines Bytes (fuers Datenarray, ab 0 zaehlend) wird -- abhaengig nach aktueller
    377      * Ausrichtung des Lochstreifens -- die Koordinate des Bytes in der Dimension der
    378      * Ausrichtung des Lochstreifens zurueckgegeben..
    379      * Liegt der Lochstreifen horizontal, so wird die x-Koordinate zurueckgegeben. Liegt er
    380      * vertikal, dann die y-Koordinate.
    381      *
    382      **/
    383      int xy;
    384      //if(lochstreifen_get_orientation(l)) { // horizontal = 1 | vertical = 0
    385         xy = l->margin + l->abriss + (l->d + l->bspace) * (byte + l->empty_start);
    386      //}
    387 
    388      return xy;
    389      // TODO! Richtige implementierung!
    390 }
    391 
     49        LOCHSTREIFEN *l = malloc (sizeof(LOCHSTREIFEN));
     50
     51        // set default values:
     52        l->data_length                = 0;
     53        l->data                       = NULL;
     54        l->highlight_region_start     = 0;
     55        l->highlight_region_end       = 0;
     56        l->highlight_region_color     = NULL;
     57        l->highlight_row_number       = 0;
     58        l->highlight_row_color        = NULL;
     59        l->highlight_bit_row          = 0;
     60        l->highlight_bit_track        = 0;
     61        l->highlight_bit_color        = NULL;
     62        l->clip                       = NULL;
     63        l->outer_background_color     = LOCHSTREIFEN_DEFAULT_OUTER_BACKGROUND_COLOR;
     64        l->papertape_background_color = LOCHSTREIFEN_DEFAULT_PAPERTAPE_BACKGROUND_COLOR;
     65        l->one_code_hole_color        = LOCHSTREIFEN_DEFAULT_ONE_CODE_HOLE_COLOR;
     66        l->zero_code_hole_color       = LOCHSTREIFEN_DEFAULT_ZERO_CODE_HOLE_COLOR;
     67        l->feed_hole_color            = LOCHSTREIFEN_DEFAULT_FEED_HOLE_COLOR;
     68        l->matrix                     = malloc (sizeof(cairo_matrix_t));
     69        // default matrix: 1:1 original.
     70        l->matrix->xx = 1;   l->matrix->yx = 0;
     71        l->matrix->xy = 0;   l->matrix->yy = 1;
     72        l->matrix->x0 = 0;   l->matrix->y0 = 0;
     73
     74        return l;
     75}
     76
     77/**
     78 * A small debug function that will print out all fields of the LOCHSTREIFEN
     79 * structure well ordered to stderr.
     80 *
     81 **/
     82void lochstreifen_print_debug(LOCHSTREIFEN* l) {
     83        int x;
     84        #define COLORP(color) if(color == NULL) fprintf(stderr, "   color ist NULL.\n"); \
     85                else if(cairo_pattern_get_type(color) == CAIRO_PATTERN_TYPE_SOLID) {\
     86                double r,g,b,a; cairo_pattern_get_rgba(color, &r, &g, &b, &a); \
     87                fprintf(stderr, "   SOLID: R=%f, G=%f, B=%f, A=%f\n", r, g, b, a); \
     88                } else fprintf(stderr, "    NO SOLID PATTERN (special pattern)\n");
     89        #define COLORP_VERBOSE(color1, name) \
     90                fprintf(stderr, " * "name": %s\n", (color1) != NULL ? "ENABLED" : "disabled");\
     91                COLORP(color1);
     92
     93       
     94        if(l != NULL)
     95                fprintf(stderr, "Debugging papertape at %x:\n", l);
     96        else {
     97                fprintf(stderr, "Cannot debug: Papertape is NULL!\n");
     98                return;
     99        }
     100       
     101        // 1. Point: Print out data.
     102        fprintf(stderr, "1# DATA AND OUTPUT IMAGE SIZE INFORMATION\n");
     103        fprintf(stderr, " * Data: length=%i bytes", l->data_length);
     104        if(l->data_length > 0 && l->data != NULL) {
     105                // there are data
     106                fprintf(stderr, ":\n   { ");
     107                for(x=0;;) {
     108                        fprintf(stderr, "0x%x", l->data[x]);
     109                        if(++x == l->data_length) {
     110                                fprintf(stderr, " };\n");
     111                                break;
     112                        } else if(x == 10) { // magic number: print first 10 bytes.
     113                                fprintf(stderr, ", ... };\n");
     114                                break;
     115                        } else
     116                                fprintf(stderr, ", ");
     117                }
     118        } else if(l->data == NULL) {
     119                fprintf(stderr, " BUT data are NULL!\n");
     120        } else  // data_length == 0.
     121                fprintf(stderr, " (empty data)\n");
     122        fprintf(stderr, " * Unscaled dimensions:\n");
     123        fprintf(stderr, "   width of image (length of papertape) = %f\n", lochstreifen_get_length(l));
     124        fprintf(stderr, "   height of image (width of papertape) = 1\n");
     125       
     126        // 2. Point: Print out colors
     127        fprintf(stderr, "\n2# ELEMENT COLORS\n");
     128        COLORP_VERBOSE(l->outer_background_color, "outer background");
     129        COLORP_VERBOSE(l->papertape_background_color, "papertape background");
     130        COLORP_VERBOSE(l->one_code_hole_color, "one code holes");
     131        COLORP_VERBOSE(l->zero_code_hole_color, "zero code holes");
     132        COLORP_VERBOSE(l->feed_hole_color, "feed holes");
     133       
     134        // 3. Point: Print out highlighted thingies
     135        fprintf(stderr, "\n3# HIGHLIGHT COLORS\n");
     136        fprintf(stderr, l->highlight_region_color != NULL ? " * Highlight region: start=%i end=%i\n"
     137                : " * Highlight region: disabled\n", l->highlight_region_start, l->highlight_region_end);
     138        COLORP(l->highlight_region_color);
     139        fprintf(stderr, l->highlight_row_color != NULL ? " * Highlight row: number=%i\n"
     140                : " * Highlight row: disabled\n", l->highlight_row_number);
     141        COLORP(l->highlight_row_color);
     142        fprintf(stderr, l->highlight_bit_color != NULL ? " * Higlight bit: row=%i track=%i\n"
     143                : " * Highlight bit: disabled\n", l->highlight_bit_row, l->highlight_bit_track);
     144        COLORP(l->highlight_bit_color);
     145       
     146        // 4. Point: Print out information about clippings
     147        fprintf(stderr, "\n4# SPECIAL STRUCTURES\n");
     148        if(l->clip == NULL)
     149                fprintf(stderr, " * Clipping: disabled\n");
     150        else {
     151                fprintf(stderr, " * Clipping: ENABLED\n");
     152                fprintf(stderr, "  x=%f, y=%f, width=%f, height=%f\n",
     153                        l->clip->x, l->clip->y, l->clip->width, l->clip->height);
     154        }
     155       
     156        // 5. Point: Affine Matrix
     157        if(l->matrix == NULL)
     158                fprintf(stderr, " * Matrix: disabled\n");
     159        else {
     160                fprintf(stderr, " * Matrix: ENABLED\n");
     161                fprintf(stderr, "   x_new = [xx=%f]*x + [xy=%f]*y + [x0=%f]\n",
     162                        l->matrix->xx, l->matrix->xy, l->matrix->x0);
     163                fprintf(stderr, "   y_new = [yx=%f]*x + [yy=%f]*y + [y0=%f]\n",
     164                        l->matrix->yx, l->matrix->yy, l->matrix->y0);
     165                fprintf(stderr, "   source dimensions: x_max = %f x y_max = %f\n",
     166                        LOCHSTREIFEN_LENGTH, LOCHSTREIFEN_WIDTH);
     167                fprintf(stderr, "   target dimensions: width = %i x height = %i\n",
     168                        lochstreifen_get_target_width(l),
     169                        lochstreifen_get_target_height(l));
     170        }
     171       
     172        // 6. Point: Debugging
     173        fprintf(stderr, " * Debugging: %s\n", l->debug ? "ENABLED" : "disabled");
     174       
     175        fprintf(stderr, "END OF LOCHSTREIFEN\n");
     176}
     177
     178/**
     179 * Set the data which LOCHSTREIFEN is supposed to punch out. You shall give
     180 * the LOCSTREIFEN object only a copy of your data, never give it a sensible
     181 * data array. The LOCHSTREIFEN object won't write into your data, but afterwards
     182 * it will free them. So it treats the data as it's own.
     183 *
     184 **/
     185void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data) {
     186        l->data_length = data_length;
     187        if(l->data != NULL)
     188                free(l->data);
     189        l->data = data;
     190}
     191
     192/**
     193 * Adds Null Bytes (0x00) at start and/or end of the data array. This dynamically
     194 * increases the data array.
     195 *
     196 *
     197 **/
     198void lochstreifen_add_null_bytes(LOCHSTREIFEN *l, int start, int end) {
     199        byte_t *new_data;
     200
     201        // only to be sure realloc won't decrease the size of the array:
     202        if(start < 0) start = 0;
     203        if(end < 0)   end = 0;
     204       
     205        // make array bigger to contain new start/end chunks
     206        new_data = realloc(l->data, l->data_length + start + end);
     207        // check wheter realloc exited successfully. We don't want segfaults
     208        if(new_data == NULL)
     209                return;
     210        // move data to the middle
     211        memmove(new_data + start, new_data, l->data_length);
     212        // fill new start chunk with zero bytes
     213        memset(new_data, 0x00, start);
     214        // fill new end chunk with zero bytes
     215        memset(new_data + start + l->data_length, 0x00, end);
     216        // that's it.
     217       
     218        // fix the data link. Don't free the old data. Don't know exactly
     219        // how realloc works, sorry ;-)
     220        l->data = new_data;
     221}
     222
     223/**
     224 * Get the length of a LOCHSTREIFEN. It depends on the length of the data array
     225 * and the papertape dimension constants.
     226 *
     227 *
     228 **/
     229double lochstreifen_get_length(LOCHSTREIFEN *l) {
     230        return LOCHSTREIFEN_LENGTH;
     231}
     232
     233
     234/**
     235 * Tell LOCHSTREIFEN to highlight a region of rows. Start counts from 0 and is already
     236 * in the selection, end is no more in selection. Example with start = 2; end = 5:
     237 *
     238 * 0    1     2     3     4     5    6  <- rows
     239 *         |_________________|
     240 *          highlight region
     241 **/
     242void lochstreifen_set_highlight_region(LOCHSTREIFEN *l, int start, int end) {
     243        l->highlight_region_start = start;
     244        l->highlight_region_end   = end;
     245        if(l->highlight_region_color == NULL)
     246                l->highlight_row_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_REGION_COLOR;
     247}
     248
     249/**
     250 * Get the selection bounds of the highlighted rows. Give Links to your variables
     251 * where the function stores the start/end integers.
     252 * @return TRUE if there is an highlight selection, FALSE otherwiese
     253 **/
     254int lochstreifen_get_highlight_region(LOCHSTREIFEN *l, int *start, int *end) {
     255        if(l->highlight_region_color == NULL)
     256                return 0;
     257        if(start != NULL)
     258                *start = l->highlight_region_start;
     259        if(end != NULL)
     260                *end   = l->highlight_region_end;
     261        return 1;
     262}
     263
     264/**
     265 * Remove the highlighted region (that is, make it no more highlighted).
     266 **/
     267void lochstreifen_remove_highlight_region(LOCHSTREIFEN *l) {
     268        l->highlight_region_color = NULL;
     269}
     270
     271/**
     272 * Tell LOCHSTREIFEN to highlight one, only one special row. Starts counting from 0.
     273 * Example with start = 3:
     274 *
     275 * 0   1    2     3     4     5
     276 *             |_____|
     277 *        highlighted row
     278 *
     279 * Principally this is the same feature like lochstreifen_set_highlight_region, having
     280 * (in the above example) start = 3 and end = 4. You can just use another color and
     281 * use both techniques concurrently, whereby the highlighted row will ALWAYS be ABOVE
     282 * the highlighted chunk of rows. An application example is e.g.: The highlighted region
     283 * of rows are selected rows, the highlighted special row is the cursor position row.
     284 * This would be quite usable with an implementation of the GtkEditable interface, like
     285 * GtkPaperTape.
     286 **/
     287void lochstreifen_set_highlight_row(LOCHSTREIFEN *l, int number_of_row) {
     288        l->highlight_row_number = number_of_row;
     289        if(l->highlight_row_color == NULL)
     290                l->highlight_row_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_ROW_COLOR;
     291}
     292
     293/**
     294 * Get the highlighted special row. If there is no highlighted row, it will return a value
     295 * less than zero (e.g. -1).
     296 * @return the number of the special row, counting from zero.
     297 **/
     298int lochstreifen_get_highlight_row(LOCHSTREIFEN *l) {
     299        return (l->highlight_row_color == NULL) ? -1 : l->highlight_row_number;
     300}
     301
     302/**
     303 * Remove the highlight at the special selected row.
     304 **/
     305void lochstreifen_remove_highlight_row(LOCHSTREIFEN *l) {
     306        //l->highlight_row_color = NULL;  /// nein, das ist dumm, weil es den highlight komplett entfernen würde.
     307        l->highlight_row_number = -1; // das ist schlau.
     308}
     309
     310/**
     311 * Tell LOCHSTREIFEN to highlight one special bit on the complete papertape. To identify
     312 * this bit, you give the row and track number (byte id and bit id) for this bit. E.g.
     313 * with row = 3, bit = 5 you'll get something like:
     314 *
     315 * ------- DIRECTION OF MOVEMENT ------->
     316 * track 8     8     8     8     8     8
     317 * track 7     7     7     7     7     7
     318 * track 6     6     6  +-----+  6     6
     319 * track 5     5     5  |  5  |  5     5       (of course the highlight won't affect any
     320 * track 4     4     4  +-----+  4     4        other bit, row 3, track 6 and track 4
     321 * feed  -     -     -     -     -     -        are not visible due to ASCII limitations
     322 * track 3     3     3     3     3     3        ;-) )
     323 * track 2     2     2     2     2     2
     324 * track 1     1     1     1     1     1
     325 *
     326 * row:  0     1     2     3     4     5
     327 *                         ^-- this row
     328 *
     329 * The bit highlight will appear on top of the row highlight and region highlight. You
     330 * can combine the bit highlight with row highlight (e.g. in the example above you can
     331 * highlight row 3, too) and even with the region highlight (e.g. having a region from
     332 * row 2 to row 5).
     333 **/
     334void lochstreifen_set_highlight_bit(LOCHSTREIFEN *l, int number_of_row, int number_of_bit) {
     335        l->highlight_bit_row = number_of_row;
     336        l->highlight_bit_track = number_of_bit;
     337        if(l->highlight_bit_color == NULL)
     338                l->highlight_bit_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_BIT_COLOR;
     339}
     340
     341/**
     342 * Get the highlighted special bit. This works exactly like lochstreifen_get_highlight_region,
     343 * returning FALSE (0) if there's no bit selected.
     344 *
     345 **/
     346int lochstreifen_get_highlight_bit(LOCHSTREIFEN *l, int *number_of_row, int *number_of_bit) {
     347        if(l->highlight_bit_color == NULL)
     348                return 0;
     349        if(number_of_row != NULL)
     350                *number_of_row = l->highlight_bit_row;
     351        if(number_of_bit != NULL)
     352                *number_of_bit = l->highlight_bit_track;
     353        return 1;
     354}
     355
     356/**
     357 * Remove the highlighting of the special bit.
     358 **/
     359void lochstreifen_remove_highlight_bit(LOCHSTREIFEN *l) {
     360        l->highlight_bit_color = NULL;
     361}
     362
     363/**
     364 * If you want LOCHSTREIFEN only to paint a small area from the whole papertape, this
     365 * is the function you can call.
     366 *
     367 **/
     368void lochstreifen_set_clip(LOCHSTREIFEN *l, double x, double y, double width, double height) {
     369        if(l->clip == NULL)
     370                l->clip = malloc(sizeof(cairo_rectangle_t));
     371        l->clip->x = x;
     372        l->clip->y = y;
     373        l->clip->width = width;
     374        l->clip->height = height;
     375}
     376
     377/**
     378 * I fyou want LOCHSTREIFEN no more to paint only a small area but the whole paper tape,
     379 * simply call this function.
     380 **/
     381void lochstreifen_remove_clip(LOCHSTREIFEN *l) {
     382        free(l->clip);
     383        l->clip = NULL; // not neccessary, I suppose.
     384}
     385
     386/**
     387 * Affect the current transformation matrix so the papertape finally has a length of
     388 * exactly the value given in the argument, in pixels. The length depends from the
     389 * number of rows on the papertape, so the length will increase if you increase the
     390 * number of rows after calling lochstreifen_set_scaling_by_length.
     391 **/
     392void lochstreifen_set_scaling_by_length(LOCHSTREIFEN *l, int length) {
     393        double scale_factor = ((double)length) / LOCHSTREIFEN_LENGTH;
     394        printf("Scaling to length=%i, having length=%f, getting %f as scale factor\n",
     395                length, LOCHSTREIFEN_LENGTH, scale_factor);
     396        cairo_matrix_scale(l->matrix, scale_factor, scale_factor);
     397}
     398
     399void lochstreifen_set_scaling_by_width(LOCHSTREIFEN *l, int width) {
     400        double scale_factor = ((double)width) / LOCHSTREIFEN_WIDTH;
     401        cairo_matrix_scale(l->matrix, scale_factor, scale_factor);
     402}
     403
     404void lochstreifen_set_scaling_by_code_hole(LOCHSTREIFEN *l, int diameter) {
     405        double scale_factor = ((double)diameter)/2 / LOCHSTREIFEN_RADIUS_CODE_HOLE;
     406        cairo_matrix_scale(l->matrix, scale_factor, scale_factor);
     407}
     408
     409/**
     410 * Get the dimensions of the paper tape in the output image. Be careful: While
     411 * width/length are well defined in the LOCHSTREIFEN process, hereby width and
     412 * height mean the dimensions of the rectangular surface picture.
     413 * If you need only the value of one dimension, use
     414 * lochstreifen_get_target_width or lochstreifen_get_target_height, respectively.
     415 *
     416 * The calculation of these values is quite expensive, so you do well when
     417 * caching the results.
     418 * @return nothing, because Call-by-Reference.
     419 **/
     420void lochstreifen_get_target_dimensions(LOCHSTREIFEN *l, int *width, int *height) {
     421        int i;
     422        // preset the dimensions to 0
     423        if(width  != NULL)  *width = 0;
     424        if(height != NULL)  *height = 0;
     425        // define the "bounding box" where the papertape resides in
     426        // user space cordinates (like lochstreifen_draw paints)
     427        double x[] = { 0, LOCHSTREIFEN_LENGTH,                  0, LOCHSTREIFEN_LENGTH };
     428        double y[] = { 0,                   0, LOCHSTREIFEN_WIDTH, LOCHSTREIFEN_WIDTH  };
     429        // transform the "bounding box" throught the matrix
     430        for(i=0; i < (sizeof(x) / sizeof(double)); i++) {
     431                cairo_matrix_transform_point(l->matrix, &x[i], &y[i]);
     432                // store biggest x/y values
     433                if(width != NULL && x[i] > *width)
     434                        *width = x[i];
     435                if(height != NULL && y[i] > *height)
     436                        *height = y[i];
     437        }
     438}
     439
     440/**
     441 * Get width of the output picture. This is only a nicer frontend to
     442 * lochstreifen_get_target_dimensions that returns the width value.
     443 **/
     444int lochstreifen_get_target_width(LOCHSTREIFEN *l) {
     445        int width;
     446        lochstreifen_get_target_dimensions(l, &width, NULL);
     447        return width;
     448}
     449
     450/**
     451 * Get height of the output picture. This is only a nicer frontend to
     452 * lochstreifen_get_target_dimensions that returns the height value.
     453 **/
     454int lochstreifen_get_target_height(LOCHSTREIFEN *l) {
     455        int height;
     456        lochstreifen_get_target_dimensions(l, NULL, &height);
     457        return height;
     458}
     459
     460/**
     461 * Get the row number from an x/y target cordinate. That is: At first, translate
     462 * the points with the current translation matrix, afterwards calculate the row
     463 * number for the position.
     464 *
     465 * @returns Row number, counting from zero. Negative value if point not on papertape data chunk.
     466 **/
     467int lochstreifen_get_target_row_from_point(LOCHSTREIFEN* l, double x, double y) {
     468        // transform points
     469        // zunächst ganz blöd: Matrix zur Laufzeit invertieren.
     470        cairo_matrix_t invert = *l->matrix; // copy matrix
     471        if(cairo_matrix_invert(&invert) != CAIRO_STATUS_SUCCESS) { // invert the copy
     472                // there are some matrizes which are not invertable
     473                fprintf(stderr, "lochstreifen_get_target_row_from_point: Matrix is not invertable!\n");
     474                return -1;
     475        }
     476        cairo_matrix_transform_point(&invert, &x, &y); // transform points
     477
     478        // now calculate position.
     479        // check if we are on data:
     480        if(y < 0 || y > LOCHSTREIFEN_WIDTH || x < LOCHSTREIFEN_TEAR_OFF_LENGTH || x > (LOCHSTREIFEN_LENGTH - LOCHSTREIFEN_TEAR_OFF_LENGTH))
     481                return -2;
     482        // getting the row from the x value. This is pretty much the same algorithm
     483        // like used in papertape_draw for checking up the rectangle bounding box (clipping).
     484        return floor (
     485                (x - LOCHSTREIFEN_TEAR_OFF_LENGTH) / LOCHSTREIFEN_ROW_DISTANCE
     486        );
     487       
     488}
     489
     490/**
     491 *
     492 * Just to be sure that there are no misunderstandings: Rotation (wiht cairo)
     493 * principally works like this:
     494 *
     495 *              |  B----D
     496 *                 | V  |
     497 *    180°      |  | V  |
     498 * D--------C      | V  | 270°
     499 * |>>>>>>>>|   |  | V  |
     500 * B--------A      A----C
     501 *              |
     502 *   - - - - - -+------------------------>   x axis
     503 *              |                    .
     504 *      C----A  |  A------------B    .
     505 *      | ^  |  |  |<<<<<<<<<<<<|    .
     506 *  90° | ^  |  |  C------------D    .
     507 *      | ^  |  |     original       .  <- borders of the target surface
     508 *      | ^  |  |....................+
     509 *      D----B  |
     510 *              V
     511 *           y axis
     512 *
     513 * Unfortunately every rotated box would be outside of the target surface
     514 * (e.g. an 200x100px PNG image), thus we must move the matrix inside the
     515 * positive x/y axis intercept.
     516 * This can be performed quite simple
     517 *
     518 **/
     519void lochstreifen_set_rotation(LOCHSTREIFEN *l, enum lochstreifen_direction direction) {
     520        switch(direction) {
     521                case LOCHSTREIFEN_MOVEMENT_TO_LEFT:
     522                        // standard
     523                case LOCHSTREIFEN_MOVEMENT_TO_TOP:
     524                        //cairo_matrix_rotate();
     525                case LOCHSTREIFEN_MOVEMENT_TO_RIGHT:
     526                case LOCHSTREIFEN_MOVEMENT_TO_BOTTOM:
     527                case LOCHSTREIFEN_ROTATION_CLOCKWISE:
     528                case LOCHSTREIFEN_ROTATION_ANTICLOCKWISE:
     529                case LOCHSTREIFEN_MOVEMENT_NONE:
     530                default:
     531                        break;
     532        }
     533}
     534
     535
     536/**
     537 * The very central main function for the LOCHSTREIFEN object: Drawing.
     538 * You are supposed to create an adequate cairo context.
     539 *
     540 * This basic drawing function will draw relative to the width of the
     541 * paper tape, like defined as 1 inch in the ECMA-10 standard. This
     542 * width will have the value "1".
     543 *
     544 * Your cropping/... blub shall treat hereby. blabla.
     545 **/
    392546void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr) {
    393     /**
    394      * Den Lochstreifen auf das uebergebene Cairoobjekt zeichnen.
    395      * Die Funktion zeichnet nach den aktuellen Lochstreifenobjekt-Angaben
    396      * (Groesse/Breite) -- wenn die cairo_image_surface nicht diesen Dimensionen
    397      * entspricht, ist das alt schlecht.
    398      *
    399      **/
    400     int byte,loch,x,y; // temp fuer Schleifen
    401     int height = lochstreifen_get_height(l);
    402     int width = lochstreifen_get_width(l);
    403     // 4 Eckpunkte des Zeichenbereichs bestimmen...
    404     int x1,x2,y1,y2;
    405     x1 = l->only_start_x; y1 = l->only_start_y;
    406     x2 = x1 + width; y2 = y1 + height;
    407 
    408     /*int x1,y1,x2,y2,x3,y3,x4,y4;
    409     x1 = l->only_start_x; y1 = l->only_start_y;
    410     x2 = x1+width; y2 = y1;
    411     x3 = x2; y3 = y2+height;
    412     x4 = x1; y4 = y3;*/
    413 
    414     // Verschiebungsmatrix erst hier berechnen, weil Verschiebungen vorher unklar
    415     // wunderbare affine Abbildungen ;-)
    416     cairo_matrix_t matrix, temp; // temp: Temporaere Matrix zur Matrizenmulitiplikation
    417     cairo_matrix_init_identity(&matrix);
    418     if(l->drehung > 0) {
    419         if(l->drehung == 1) {
    420             cairo_matrix_init(&temp, 0, -1, 1, 0, 0, height);
    421             x = width; width = height; height = x;                // Breiten und Hoehen
    422             x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
    423         } else if(l->drehung == 2) {
    424             cairo_matrix_init(&temp, -1, 0, 0, -1, width, height);
    425         } else if(l->drehung == 3) {
    426             cairo_matrix_init(&temp, 0, 1, -1, 0, width, 0);
    427             x = width; width = height; height = x;                // Breiten und Hoehen
    428             x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
    429         }
    430         cairo_matrix_multiply(&matrix, &matrix, &temp);
    431     }
    432 
    433     if(l->spiegelung_hor != 0) {
    434          cairo_matrix_init(&temp, -1, 0, 0, 1,
    435              l->drehung % 2 == 0 ? width : height, // Default bei Nicht-Drehung: width
    436              0);
    437          cairo_matrix_multiply(&matrix, &matrix, &temp);
    438     }
    439     if(l->spiegelung_ver != 0) {
    440          cairo_matrix_init(&temp, 1, 0, 0, -1, 0,
    441              l->drehung % 2 == 0 ? height: width); // Default bei Nicht-Drehung: height
    442          cairo_matrix_multiply(&matrix, &matrix, &temp);
    443     }
    444 
    445     //if(l->drehung > 0) {
    446         /*cairo_matrix_rotate(&matrix, l->drehung/2 *M_PI);
    447         if(l->drehung == 1) { // 90°, im III. Sektor
    448             //x = width; width = height; height = x;
    449             //cairo_matrix_translate(&matrix, 0, 0);
    450         } else if(l->drehung == 2) { // 180°, im IV Sektor
    451             cairo_matrix_translate(&matrix, width, height);
    452         } else if(l->drehung == 3) { // 270°, im I. Sektor
    453             //x = width; width = height; height = x;
    454             cairo_matrix_translate(&matrix, width, height);
    455         }*/
    456         // 4. Sektor kommt nicht vor
    457     //}
    458     cairo_set_matrix(cr, &matrix);
    459     // -1, 0, 0, 1, width, 0 = spiegelung x-achse
    460 
    461     //cairo_device_to_user(cr, (double*)&(l->only_start_x), (double*)&(l->only_start_y));
    462     cairo_device_to_user(cr, (double*)&(x1), (double*)&(y1));
    463     cairo_device_to_user(cr, (double*)&(x2), (double*)&(y2));
    464 
    465     l->only_start_x = x2 < x1 ? x2 : x1;
    466     l->only_start_y = y2 < y1 ? y2 : y1;
    467 
    468     cairo_set_source(cr, l->fuehrung);
    469     cairo_rectangle(cr, l->only_start_x, l->only_start_y, l->only_width, l->only_height);
    470     //printf("Only: %d|%d, %d * %d\n", l->only_start_x, l->only_start_y, l->only_width, l->only_height);
    471     cairo_paint(cr);
    472 
    473     // Hintergrundfarbe zeichnen.
    474     if(0||l->hintergrund != NULL) {
    475         //l->hintergrund = cairo_pattern_create_rgb(1,1,1);
    476         cairo_set_source(cr, l->hintergrund);
    477         cairo_paint(cr);
    478     }
    479 
    480     // sache zeichnen
    481     cairo_set_source(cr, l->streifenbg);
    482     cairo_rectangle(cr, -10, -10, width+20, height+20);
    483     cairo_stroke(cr);
    484     if(0==1){
    485         double x,y, a,b;
    486         int xx,yy,aa,bb;
    487         x=0;y=0; a=width;b=height;
    488         cairo_matrix_transform_point(&matrix, &x, &y);
    489         cairo_matrix_transform_point(&matrix, &a, &b);
    490         xx=(int)x;yy=(int)y;aa=(int)a;bb=(int)b;
    491         printf("Punkt (0/0)=(%i|%i) und (%i|%i)=(%i/%i)\n", xx, yy, width, height, aa, bb);
    492     }
    493 
    494     // Lochstreifenhintergrund inklusive Abriss vorne/hinten malen
    495     if(l->streifenbg != NULL) {
    496         cairo_set_source(cr, l->streifenbg);
    497 
    498         // Abriss vorne
    499         cairo_move_to(cr, l->margin + l->abriss*0.8, l->margin); // oben rechts
    500         cairo_line_to(cr, l->margin, l->margin + l->padding+ 3*l->d + 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
    501         cairo_line_to(cr, l->margin + l->abriss, height - l->margin); // unten ganz rechts
    502         cairo_line_to(cr, l->margin + l->abriss, l->margin); // nach oben ganz rechts...
    503         cairo_close_path(cr); // schliessen
    504         // normaler Bereich
    505         cairo_rectangle(cr, l->margin + l->abriss, l->margin,
    506             width - 2*l->margin - 2*l->abriss, height - 2*l->margin);
    507         /*printf("Zeichne Rechteck x|y = (%d|%d) width*height = %d * %d\n",
    508             l->margin + l->abriss, l->margin,
    509             width - 2*l->margin - 2*l->abriss, height - 2*l->margin
    510         );*/
    511         // Abriss hinten...
    512         cairo_move_to(cr, width - l->margin - l->abriss*0.2, l->margin); // oben mitte
    513         cairo_line_to(cr, width - l->margin - l->abriss,
    514             l->margin + l->padding + 3*l->d+ 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
    515         cairo_line_to(cr, width - l->margin, height - l->margin); // unten ganz rechts
    516         cairo_line_to(cr, width - l->margin - l->abriss, height - l->margin); // unten ganz links
    517         cairo_line_to(cr, width - l->margin - l->abriss, l->margin); // nach oben zum schliessen
    518         cairo_close_path(cr);
    519 
    520         cairo_fill(cr);
    521     }
    522 
    523 
    524     // Lochstreifenlöcher malen
    525 
    526     /*if(l->only_start_x > 0) {
    527         // nur in bestimmten Bereich zeichnen
    528         int start_byte = l->empty_start + lochstreifen_byte_by_coordinate(l, l->only_start_x, l->only_start_y); // absolut inkl. empty bytes
    529 
    530     } else byte = -l->empty_start; // leere Bytes vorne eingeschlossen
    531     }*/
    532 
    533     // Bytes durchgehen, leere Bytes vorne/hinten mit eingeschlossen
    534     for(byte = -l->empty_start, x=l->margin + l->abriss; byte < l->data_length + l->empty_end; x += l->d + l->bspace, byte++) {
    535         // Clipping: Um unnoetiges Zeichnen zu ersparen, erst ab X-Koordinate zeichnen
    536         if(x < l->only_start_x - (l->d + l->bspace)) continue; // - 1x Loch weniger, damit nicht ein gerade abgeschnittenes nichtgezeichnet wird
    537         // und nur bis zur rechten Begrenzung zeichnen -- dannach genuegt Abbruch.
    538         if(l->only_width != 0 && x > l->only_start_x + l->only_width) break;
    539 
    540         // ggf. Byte hervorheben
    541         if(byte == l->highlight_byte && l->highlight_color != NULL) {
    542             cairo_set_source(cr, l->highlight_color);
    543             cairo_rectangle(cr, x - l->bspace/2, l->margin, l->df*2 + l->bspace, height - 2*l->margin);
    544             cairo_fill(cr);
    545         }
    546 
    547         // Bits des entsprechenden Bytes durchgehen
    548         for(loch=0, y = l->margin + l->padding; loch < 8; y += l->d + l->hspace, loch++) {
    549             // Clipping: Erst ab Y-Koordinate zeichnen (-1xLoch-Korrektur gegen Abschnitt)
    550             if(y < l->only_start_y - (l->d - l->hspace)) continue;
    551             // bis zur unteren Begrenzung -- anschliessend Abbruch
    552             if(l->only_height != 0 && y > l->only_start_y + l->only_height) break;
    553 
    554             // Ggf. Lochstreifenfuehrung zeichnen
    555             if(loch==3 && l->fuehrung != NULL) {
    556                 // Nur vor dem 3. Loch (wenn ueberhaupt)
    557                 y -= l->hspace; // den Abstand vom vorherigen Loch wieder wegnehmen
    558                 cairo_set_source(cr, l->fuehrung);
    559                 cairo_arc(cr, x+l->d/2, y+l->fspace/2, l->df/2, 0., 2*M_PI);
    560                 cairo_fill(cr);
    561                 y += l->fspace;
    562             } else if(loch == 3) // 3. Loch, aber keine Fuehrung zeichnen => Platz freilassen!
    563                 y += l->fspace - l->hspace;
    564 
    565             // Debugausgaben machen?
    566             if(l->debug != 0 && byte >= 0 && byte < l->data_length) {
    567                 if(loch == 0) printf("byte %3i von %3i: 0x%2x = ", byte, l->data_length, l->data[byte]);
    568                 fprintf(stderr, "%c", (((l->data[byte] >> loch) & 0x01) == 0x01) ? '#' : ' ');
    569                 if(loch == 7) printf("\n");
    570             }
    571 
    572             if((byte < 0 || byte >= l->data_length) ||    // wenn ein Nullbyte gezeichnet wird
    573                (((l->data[byte] >> loch) & 0x01) != 0x01) // oder das Bit an der Stelle nicht gesetzt ist
    574                ) {                                        // ist es not-Punched
    575                 if(l->notpunched != NULL) { // notpunched zeichnen? (muss subif sein)
    576                     cairo_set_source(cr, l->notpunched);
    577                     cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
    578                     cairo_fill(cr);
    579                 }
    580             } else if(l->punched != NULL) { // es ist Punched. Zeichnen?
    581                 cairo_set_source(cr, l->punched);
    582                 cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
    583                 cairo_fill(cr);
    584             }
    585             // Die Routine wegen dem Zeichnen?-Ding hervorgehoben.
    586             /*cairo_set_source(cr,
    587                  (byte < 0 || byte >= data_length) ||      // wenn ein Nullbyte gezeichnet wird
    588                  (((data[byte] >> loch) & 0x01) != 0x01) ? // oder das Bit an der Stelle nicht gesetzt ist
    589                  notpunched : punched);                    // dann dies farbig kennzeichnen
    590             cairo_arc(cr, x+d/2, y+d/2, d/2, 0., 2*M_PI);
    591             cairo_fill(cr);*/
    592 
    593             // y+= war hier.
    594         } // for bits (loecher)
    595         // x += war hier.
    596     } // for bytes
    597 
    598     // Lochstreifenfuehrung im vorderen Abriss malen
    599     if(l->fuehrung != NULL) {
    600         cairo_set_source(cr, l->fuehrung);
    601         y = l->margin + l->padding + 3*l->d + 2*l->hspace + l->fspace/2; // fspace-Mitte
    602         x = l->margin + l->abriss - l->d - l->bspace; // Start-x
    603         for(; x > l->margin;) {
    604             cairo_arc(cr, x + l->d/2, y, l->df/2, 0., 2*M_PI);
    605             x -= l->d + l->bspace;
    606         }
    607         cairo_fill(cr);
    608     }
    609 
    610     // fertig mit dem Lochstreifenzeichnen.
    611 } // function draw_lochstreifen
     547        // complete length of paper tape:
     548        double length = LOCHSTREIFEN_LENGTH;
     549
     550        // iterators for the byte/bit loops
     551        int row,track;
     552        // position while iterating
     553        double x,y;
     554        // max positions to iterate to
     555        int row_max, track_min, track_max;
     556
     557        // apply the matrix!
     558        cairo_set_matrix(cr, l->matrix);
     559       
     560
     561        // paint outer background color.
     562        if(l->outer_background_color != NULL) {
     563                cairo_set_source(cr, l->outer_background_color);
     564                cairo_paint(cr);
     565        }
     566
     567        // paint the paper tape outline, including the tear-off
     568        if(l->papertape_background_color != NULL) {
     569                cairo_set_source(cr, l->papertape_background_color);
     570
     571                // tear-off at the beginning (0.5 of paper tape width)
     572                cairo_move_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH * 0.8, 0);
     573                cairo_line_to(cr, 0, 4*LOCHSTREIFEN_TRACK_DISTANCE);
     574                cairo_line_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
     575                cairo_line_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, 0);
     576                cairo_close_path(cr);
     577
     578                // long rectangular area over complete paper tape
     579                cairo_rectangle(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, 0,
     580                        length - 2*LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
     581
     582                // tear-off at the end (0.5 of paper tape width)
     583                cairo_move_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, 0);
     584                cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
     585                cairo_line_to(cr, length, LOCHSTREIFEN_WIDTH);
     586                cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, 4*LOCHSTREIFEN_TRACK_DISTANCE);
     587                cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH * 0.2, 0);
     588                cairo_close_path(cr);
     589
     590                // paper tape background finished.
     591                cairo_fill(cr);
     592        }
     593       
     594        // paint feed holes in the tear-off at the beginning
     595        // only if in clipped area
     596        if( ( l->clip == NULL || (l->clip->x <= LOCHSTREIFEN_TEAR_OFF_LENGTH) )
     597         && (l->feed_hole_color != NULL) ) {
     598                cairo_set_source(cr, l->feed_hole_color);
     599                for(y=4*LOCHSTREIFEN_TRACK_DISTANCE,
     600                    x=LOCHSTREIFEN_TEAR_OFF_LENGTH - LOCHSTREIFEN_ROW_DISTANCE/2;
     601                    x > 0; x -= LOCHSTREIFEN_ROW_DISTANCE)
     602                        cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_FEED_HOLE, 0., 2*M_PI);
     603                cairo_fill(cr);
     604        }
     605
     606       
     607        if(l->clip != NULL) {
     608                // calculate clipping in dimension X (rows, bytes)
     609                // calculation of first row to begin with.
     610                row = floor (
     611                            (l->clip->x - LOCHSTREIFEN_TEAR_OFF_LENGTH - LOCHSTREIFEN_ROW_DISTANCE / 2)
     612                                              / LOCHSTREIFEN_ROW_DISTANCE
     613                );
     614               
     615                // calculation of last row to end with.
     616                row_max = floor(
     617                     (length - (l->clip->x + l->clip->width) - LOCHSTREIFEN_TEAR_OFF_LENGTH - LOCHSTREIFEN_ROW_DISTANCE/2)
     618                                             / LOCHSTREIFEN_ROW_DISTANCE
     619                );
     620
     621                // calculate clipping in dimension Y (tracks, bits)
     622                // calculation of first track to begin with.
     623                track_min = floor( l->clip->y / LOCHSTREIFEN_TRACK_DISTANCE );
     624               
     625                // calculation of last track to end with.
     626                track_max = 8 - floor(
     627                         (LOCHSTREIFEN_WIDTH - (l->clip->y + l->clip->height))
     628                                 / LOCHSTREIFEN_TRACK_DISTANCE
     629                );
     630        } else {
     631                // no clipping. Paint *everything*.
     632                row = 0;
     633                row_max = l->data_length;
     634               
     635                track_min = 0;
     636                track_max = 8;
     637        }
     638       
     639        // loop all the rows (bytes)
     640        // x start: tear off + one half row offset + offset rows * length of row
     641        for(x=LOCHSTREIFEN_TEAR_OFF_LENGTH + LOCHSTREIFEN_TRACK_DISTANCE/2 + row*LOCHSTREIFEN_TRACK_DISTANCE;
     642            row < row_max; row++, x += LOCHSTREIFEN_TRACK_DISTANCE) {
     643       
     644                // highlight region?
     645                if(l->highlight_region_color != NULL &&
     646                    (row >= l->highlight_region_start || row < l->highlight_region_end) ) {
     647                        cairo_set_source(cr, l->highlight_region_color);
     648                        // hier was schlaues schickeres als ein RECHTECK
     649                        // einfallen lassen. Vielleicht mit abgerundetem
     650                        // Rechteck? Wuerde zu den Löchern passen.
     651                        // http://www.cairographics.org/cookbook/roundedrectangles/
     652                        cairo_rectangle(cr, x - LOCHSTREIFEN_TRACK_DISTANCE / 2, 0,
     653                           LOCHSTREIFEN_TRACK_DISTANCE * (l->highlight_region_end - l->highlight_region_start),
     654                           LOCHSTREIFEN_WIDTH);
     655                        cairo_fill(cr);
     656                }
     657               
     658                // highlight (only) this row?
     659                if(l->highlight_row_color != NULL && row == l->highlight_row_number) {
     660                        cairo_set_source(cr, l->highlight_row_color);
     661                        // genauso abgerundetes Rechteck wie bei der region
     662                        // überlegen.
     663                        cairo_rectangle(cr, x - LOCHSTREIFEN_TRACK_DISTANCE/2, 0,
     664                            LOCHSTREIFEN_TRACK_DISTANCE, LOCHSTREIFEN_WIDTH);
     665                        cairo_fill(cr);
     666                }
     667               
     668                // loop all the tracks (bits)
     669                // y start: offset tracks * width of track + one track (to get onto the papertape)
     670                for(track=track_min, y = LOCHSTREIFEN_TRACK_DISTANCE*(track+1);
     671                    track < track_max; track++, y += LOCHSTREIFEN_TRACK_DISTANCE) {
     672                        if(track == 3) {
     673                                // the feed hole is at position 3
     674                                if(l->feed_hole_color != NULL) {
     675                                        // we paint a feed hole :-)
     676                                        cairo_set_source(cr, l->feed_hole_color);
     677                                        cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_FEED_HOLE, 0., 2*M_PI);
     678                                        cairo_fill(cr);
     679                                }
     680                                // jump one track, in every case.
     681                                y += 0.1;
     682                        }
     683                       
     684                        if( ((l->data[row] >> track) & 0x01) != 0x01) {
     685                                // bit is logical ZERO (0)
     686                                if(l->zero_code_hole_color != NULL) {
     687                                        // we want to paint zeros.
     688                                        cairo_set_source(cr, l->zero_code_hole_color);
     689                                        cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
     690                                        cairo_fill(cr);
     691                                }
     692                        } else if(l->one_code_hole_color != NULL) {
     693                                // we want to paint logical ONEs.
     694                                cairo_set_source(cr, l->one_code_hole_color);
     695                                cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
     696                                cairo_fill(cr);
     697                        }
     698                       
     699                        if(l->highlight_bit_row == row && l->highlight_bit_track == track
     700                           && l->highlight_bit_color != NULL) {
     701                                // eigentlich wollen wir hier eine Umrahmung zeichnen,
     702                                // damit der Zustand (0/1) nicht unsichtbar wird. Jetzt
     703                                // erst mal aber die Billigversion mit der dümmlichen
     704                                // Vollfarbe ;-)
     705                                cairo_set_source(cr, l->highlight_bit_color);
     706                                cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
     707                                cairo_stroke(cr); // mal testen :-)
     708                        }
     709                } // for tracks (bits)
     710        } // for rows (bytes)
     711} // function lochstreifen_draw
  • visualisator/lochstreifen.h

    r9 r18  
    1 /*
    2 ** Allgemeine Headerfile fuer das
    3 ** Lochstreifen-Visualisieren-Projekt
    4 */
    51#ifndef __LOCHSTREIFEN_H__
    62#define __LOCHSTREIFEN_H__
    73
    8 #include <cairo-svg.h> // cairo_t unten
     4// if C++ compiling...
     5#ifdef __cplusplus
     6extern "C" {
     7#endif
    98
    10 #define byte_t unsigned char
    11 #define LOCHSTREIFEN struct lochstreifen
     9#include <cairo-svg.h> /* because using cairo_t */
    1210
    13 // Die Lochstreifenstruktur, die alle relevanten Daten enthaelt
     11typedef unsigned char byte_t;
     12typedef struct lochstreifen LOCHSTREIFEN;
     13
    1414struct lochstreifen {
    15     /* Daten, die der Lochstreifen enthaelt: */
    16     int data_length; // Länge des Datenarrays, rechnend ab 1 (wie argc)
    17     byte_t *data;    // Datenarray
     15        /* DATA (not supposed to be set directly) */
     16        /// Length of data array (counting from 1, like argc)
     17        int data_length;
     18        /// data array (the data which LOCHSTREIFEN will print)
     19        byte_t *data;
    1820
    19     int empty_start; // wie viele 0bytes vorne
    20     int empty_end; // wie viele 0bytes hinten
     21        /* COLORS / SWITCHES WHETER PARTS ARE PAINTED */
     22        cairo_pattern_t *outer_background_color;
     23        cairo_pattern_t *papertape_background_color;
     24        cairo_pattern_t *one_code_hole_color;
     25        cairo_pattern_t *zero_code_hole_color;
     26        cairo_pattern_t *feed_hole_color;
    2127
    22     /* Konstanten zum Aussehen des Lochstreifens
    23        Referenzeinheit ist d, daraus wird alles berechnet,
    24        siehe lochstreifen_set_d
    25     */
    26     int d; // Durchmesser eines Loches
    27     int bspace;  // Abstand der Bytes voneinander (Reihen)
    28     int hspace;  // Abstand der Loecher in der Bytereihe
    29     int padding; // Abstand Löcher <=> Lochstreifenrand
    30     int df; // Durchmesser Lochfuehrungsloch
    31     int fspace; // Breite der Lochfuehrungs"nut"
    32     int margin; // Abstand um Lochstreifen herum (an allen Seiten)
    33     int abriss; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
     28        /// Highlighting a (row/byte) region
     29        int highlight_region_start; ///< counting from 0, already in selection
     30        int highlight_region_end;   ///< counting from 0, no more in selection
     31        cairo_pattern_t *highlight_region_color; ///< == NULL => no selection painted
    3432
    35     /* Farben, in denen der Lochstreifen gehalten ist */
    36     cairo_pattern_t *hintergrund, *streifenbg, *punched, *notpunched, *fuehrung;
    37     // Farben um Lochstreifen, Lochstreifen, Loecher, Nicht-Loecher, Fuehrung
    38     // siehe zum Setzen: lochstreifen_set_color oder per Cairo-Funktion fuer
    39     // komplexere Loesungen. Bei NULL wird die Komponente nicht gezeichnet!
     33        /// Highlight one special row
     34        int highlight_row_number;  ///< counting from 0
     35        cairo_pattern_t *highlight_row_color;
    4036
    41     /* Drehungen und co, nicht direkt veraendern, sonst stimmt die vorberechnete
    42        Hoehe/Breite nicht mehr mit den realen Werten ueberein. */
    43     //cairo_matrix_t transformation;
    44     // Das folgende koennte man natuerlich effizienter Speichern, aber egal.
    45     int drehung; // 0-3, jeweils 45°-Schritte im Uhrzeigersinn
    46     int spiegelung_hor; // horizontale Spiegelung != 0 == ja
    47     int spiegelung_ver; // vertikale Spiegelung != 0 == ja
     37        /// Highlight one special bit (not complete track)
     38        int highlight_bit_row;     ///< counting from 0
     39        int highlight_bit_track;   ///< counting from 0
     40        cairo_pattern_t *highlight_bit_color;
    4841
    49     /* Nur bestimmte rechteckige Bereiche zeichnen -- dies wird massgeblich vom
    50        GTK-Interface benutzt */
    51     int only_start_x; // Die angegebenen Punkte
    52     int only_start_y; // spannen ein Rechteck auf. In grober
    53     int only_width;   // Naeherung wird nur in diesem Bereich
    54     int only_height;  // gezeichnet.
     42        /// Perfomant Clipping
     43        cairo_rectangle_t *clip;
     44       
     45        /// Matrix to apply for every paint process
     46        cairo_matrix_t *matrix;
     47
     48        /*<private>*/
     49        /* The following datas are private. */
     50       
     51        /// Make debug output if debug != 0.
     52        byte_t debug;
     53};
     54
     55/// The default color values
     56#define LOCHSTREIFEN_DEFAULT_OUTER_BACKGROUND_COLOR        NULL
     57#define LOCHSTREIFEN_DEFAULT_PAPERTAPE_BACKGROUND_COLOR    cairo_pattern_create_rgb(0.7, 0.7, 0.7)
     58#define LOCHSTREIFEN_DEFAULT_ONE_CODE_HOLE_COLOR           cairo_pattern_create_rgb(0,   0,   0)
     59#define LOCHSTREIFEN_DEFAULT_ZERO_CODE_HOLE_COLOR          NULL
     60#define LOCHSTREIFEN_DEFAULT_FEED_HOLE_COLOR               cairo_pattern_create_rgb(0.5, 0.7, 1)
     61#define LOCHSTREIFEN_DEFAULT_HIGHLIGHT_REGION_COLOR        cairo_pattern_create_rgb(0.95,  1, 0)
     62#define LOCHSTREIFEN_DEFAULT_HIGHLIGHT_ROW_COLOR           cairo_pattern_create_rgb(1,     0, 0)
     63#define LOCHSTREIFEN_DEFAULT_HIGHLIGHT_BIT_COLOR           cairo_pattern_create_rgb(0.4, 0.55, 0.7)
     64
     65/// dimensions of the paper tape after ECMA-10 standard
     66
     67// width of paper tape, according to "PROPERTIES OF UNPUNCHED TAPE", section 1.1.2:
     68// 25.40mm = 1". This is the "base" unit in our vector drawing.
     69#define LOCHSTREIFEN_WIDTH                 1.0
     70
     71// length of tear-off: about the half of the width of a papertape
     72#define LOCHSTREIFEN_TEAR_OFF_LENGTH       ( 0.5 * LOCHSTREIFEN_WIDTH )
     73
     74// Within a row the distance of the centres of the code holes from
     75// the centre of the feed hole shall be 2,54mm (=0.1"), where n is an integer.
     76#define LOCHSTREIFEN_TRACK_DISTANCE        0.1
     77
     78// The distance between two adjacent rows shall be 2,54mm (=0.1") measured
     79// at the feed holes.
     80#define LOCHSTREIFEN_ROW_DISTANCE          0.1
     81
     82// feed hole diameter: 1.170mm
     83#define LOCHSTREIFEN_RADIUS_FEED_HOLE    ( (1.170 / 25.40) / 2)
     84
     85// code hol diameter: 1.83mm
     86#define LOCHSTREIFEN_RADIUS_CODE_HOLE    ( (1.830 / 25.40) / 2)
     87
     88// length of paper tape: Tear off at start and end, data rows + 0.05" offset at start + end spacing
     89#define LOCHSTREIFEN_LENGTH              ( 2 * LOCHSTREIFEN_TEAR_OFF_LENGTH + \
     90                                           LOCHSTREIFEN_ROW_DISTANCE * (l->data_length + 1) )
     91
     92enum lochstreifen_direction {
     93        // special values for compatibility to old implementation
     94        LOCHSTREIFEN_MOVEMENT_TO_LEFT       = 0,
     95        LOCHSTREIFEN_MOVEMENT_TO_TOP        = 1,
     96        LOCHSTREIFEN_MOVEMENT_TO_RIGHT      = 2,
     97        LOCHSTREIFEN_MOVEMENT_TO_BOTTOM     = 3,
     98        LOCHSTREIFEN_MOVEMENT_NONE          = -1,
     99        LOCHSTREIFEN_ROTATION_CLOCKWISE     = 4,
     100        LOCHSTREIFEN_ROTATION_ANTICLOCKWISE = 5
     101};
    55102
    56103
    57     /* Feature: Ein bestimmtes Byte hervorheben */
    58     int highlight_byte; // Nummer des Bytes (von 0)
    59     cairo_pattern_t *highlight_color; // Farben => wenn NULL, kein Highlight
     104// functions
     105LOCHSTREIFEN *lochstreifen_new();
     106void lochstreifen_print_debug(LOCHSTREIFEN* l);
     107void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data);
     108void lochstreifen_add_null_bytes(LOCHSTREIFEN *l, int start, int end);
     109double lochstreifen_get_length(LOCHSTREIFEN *l);
     110void lochstreifen_set_highlight_region(LOCHSTREIFEN *l, int start, int end);
     111int lochstreifen_get_highlight_region(LOCHSTREIFEN *l, int *start, int *end);
     112void lochstreifen_remove_highlight_region(LOCHSTREIFEN *l);
     113void lochstreifen_set_highlight_row(LOCHSTREIFEN *l, int number_of_row);
     114int lochstreifen_get_highlight_row(LOCHSTREIFEN *l);
     115void lochstreifen_remove_highlight_row(LOCHSTREIFEN *l);
     116void lochstreifen_set_highlight_bit(LOCHSTREIFEN *l, int number_of_row, int number_of_bit);
     117int lochstreifen_get_highlight_bit(LOCHSTREIFEN *l, int *number_of_row, int *number_of_bit);
     118void lochstreifen_remove_highlight_bit(LOCHSTREIFEN *l);
     119void lochstreifen_set_clip(LOCHSTREIFEN *l, double x, double y, double width, double height);
     120void lochstreifen_remove_clip(LOCHSTREIFEN *l);
     121void lochstreifen_set_scaling_by_length(LOCHSTREIFEN *l, int length);
     122void lochstreifen_set_scaling_by_width(LOCHSTREIFEN *l, int width);
     123void lochstreifen_set_scaling_by_code_hole(LOCHSTREIFEN *l, int diameter);
     124void lochstreifen_get_target_dimensions(LOCHSTREIFEN *l, int *width, int *height);
     125int lochstreifen_get_target_width(LOCHSTREIFEN *l);
     126int lochstreifen_get_target_height(LOCHSTREIFEN *l);
     127int lochstreifen_get_target_row_from_point(LOCHSTREIFEN* l, double x, double y);
     128void lochstreifen_set_rotation(LOCHSTREIFEN *l, enum lochstreifen_direction direction);
     129void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr);
    60130
    61     /* Debugausgaben machen => wenn debug != 0 ist! */
    62     byte_t debug;
    63 };
     131#ifdef __cplusplus
     132} // extern "C"
     133#endif
    64134
    65 /* lochstreifen.c */
    66 // allgemeine Zusatzfunktion, kein Bezug
    67 int file_get_contents(FILE *stream, byte_t **content);
    68 
    69 // Lochstreifenfunktionen, siehe Dokumentation in c-File
    70 LOCHSTREIFEN *lochstreifen_new();
    71 void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end);
    72 void lochstreifen_set_d(LOCHSTREIFEN *l, int d);
    73 void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width);
    74 void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height);
    75 int lochstreifen_get_width(LOCHSTREIFEN *l);
    76 int lochstreifen_get_height(LOCHSTREIFEN *l);
    77 int lochstreifen_set_draw_only_area(LOCHSTREIFEN *l, int x, int y, int width, int height);
    78 int lochstreifen_flush_draw_only_area(LOCHSTREIFEN *l);
    79 void lochstreifen_set_color(cairo_pattern_t *color, byte_t red, byte_t green, byte_t blue, byte_t alpha);
    80 //void lochstreifen_rotate(LOCHSTREIFEN *l);
    81 //void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal);
    82 void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver);
    83 void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr);
    84 int lochstreifen_get_orientation(LOCHSTREIFEN *l);
    85 int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y);
    86 int lochstreifen_flush_only_start_area(LOCHSTREIFEN *l);
    87 void lochstreifen_set_highlight(LOCHSTREIFEN* l, int byte_number);
    88 int lochstreifen_coordinate_by_byte(LOCHSTREIFEN *l, int byte);
    89 int lochstreifen_set_only_start_area(LOCHSTREIFEN *l, int x, int y, int width, int height);
    90135
    91136#endif /* __LOCHSTREIFEN_H__ */
Note: See TracChangeset for help on using the changeset viewer.
© 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