source: trunk/third/xscreensaver/hacks/barcode.c @ 20148

Revision 20148, 47.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* barcode, draw some barcodes
2 * by Dan Bornstein, danfuzz@milk.com
3 * Copyright (c) 2003 Dan Bornstein. All rights reserved.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation.  No representations are made about the suitability of this
10 * software for any purpose.  It is provided "as is" without express or
11 * implied warranty.
12 *
13 * See the included man page for more details.
14 */
15
16#include <ctype.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <math.h>
21#include "screenhack.h"
22#include <X11/Xutil.h>
23
24#include <time.h>
25#include <sys/time.h>
26#include <ctype.h>
27
28
29/* parameters that are user configurable */
30
31/* delay (usec) between iterations */
32static int delay;
33
34
35/* non-user-modifiable immutable definitions */
36
37#define FLOAT double
38
39/* random float in the range (0..1) */
40#define RAND_FLOAT_01 \
41        (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000))
42
43#define BARCODE_WIDTH (164)
44#define BARCODE_HEIGHT (69)
45#define MAX_MAG (7)
46
47/* width and height of the window */
48static int windowWidth;
49static int windowHeight;
50
51static Display *display;        /* the display to draw on */
52static Window window;           /* the window to draw on */
53static Visual *visual;          /* the visual to use */
54static Screen *screen;          /* the screen to draw on */
55static Colormap cmap;           /* the colormap of the window */
56
57static GC theGC;                /* GC for drawing */
58unsigned long fg_pixel;
59static Bool button_down_p;
60
61
62
63/* simple bitmap structure */
64
65typedef struct
66{
67    int width;
68    int height;
69    int widthBytes;
70    char *buf;
71}
72Bitmap;
73
74
75
76/* the model */
77
78typedef struct
79{
80    int x;          /* x coordinate of the left of the barcode */
81    int y;          /* y coordinate of the left of the barcode */
82    int mag;        /* magnfication factor */
83    Bitmap *bitmap; /* the bitmap */
84    char code[128]; /* the barcode string */
85    unsigned long pixel;  /* the color */
86}
87Barcode;
88
89static Barcode *barcodes; /* array of barcodes */
90static int barcode_count; /* how many barcodes are currently active */
91static int barcode_max;   /* the maximum number of active barcodes */
92
93static XImage *theImage;  /* ginormo image for drawing */
94static Bitmap *theBitmap; /* ginormo bitmap for drawing */
95
96static enum { BC_SCROLL, BC_GRID, BC_CLOCK12, BC_CLOCK24 } mode;
97
98/* a bunch of words */
99static char *words[] =
100{
101  "abdomen",
102  "abeyance",
103  "abhorrence",
104  "abrasion",
105  "abstraction",
106  "acid",
107  "addiction",
108  "alertness",
109  "Algeria",
110  "anxiety",
111  "aorta",
112  "argyle socks",
113  "attrition",
114  "axis of evil",
115  "bamboo",
116  "bangle",
117  "bankruptcy",
118  "baptism",
119  "beer",
120  "bellicosity",
121  "bells",
122  "belly",
123  "bliss",
124  "bogosity",
125  "boobies",
126  "boobs",
127  "booty",
128  "bread",
129  "bubba",
130  "burrito",
131  "California",
132  "capybara",
133  "cardinality",
134  "caribou",
135  "carnage",
136  "children",
137  "chocolate",
138  "CLONE",
139  "cock",
140  "constriction",
141  "contrition",
142  "cop",
143  "corpse",
144  "cowboy",
145  "crabapple",
146  "craziness",
147  "cthulhu",
148  "Death",
149  "decepticon",
150  "deception",
151  "Decker",
152  "decoder",
153  "decoy",
154  "defenestration",
155  "democracy",
156  "dependency",
157  "despair",
158  "desperation",
159  "disease",
160  "disease",
161  "doberman",
162  "DOOM",
163  "dreams",
164  "dreams",
165  "drugs",
166  "easy",
167  "ebony",
168  "election",
169  "eloquence",
170  "emergency",
171  "eureka",
172  "excommunication",
173  "fat",
174  "fatherland",
175  "Faust",
176  "fear",
177  "fever",
178  "filth",
179  "flatulence",
180  "fluff",
181  "fnord",
182  "freedom",
183  "fruit",
184  "fruit",
185  "futility",
186  "gerbils",
187  "GOD",
188  "goggles",
189  "goobers",
190  "gorilla",
191  "halibut",
192  "handmaid",
193  "happiness",
194  "hate",
195  "helplessness",
196  "hemorrhoid",
197  "hermaphrodite",
198  "heroin",
199  "heroine",
200  "hope",
201  "hysteria",
202  "icepick",
203  "identity",
204  "ignorance",
205  "importance",
206  "individuality",
207  "inkling",
208  "insurrection",
209  "intoxicant",
210  "ire",
211  "irritant",
212  "jade",
213  "jaundice",
214  "Joyce",
215  "kidney stone",
216  "kitchenette",
217  "kiwi",
218  "lathe",
219  "lattice",
220  "lawyer",
221  "lemming",
222  "liquidation",
223  "lobbyist",
224  "love",
225  "lozenge",
226  "magazine",
227  "magnesium",
228  "malfunction",
229  "marmot",
230  "marshmallow",
231  "merit",
232  "merkin",
233  "mescaline",
234  "milk",
235  "mischief",
236  "mistrust",
237  "money",
238  "monkey",
239  "monkeybutter",
240  "nationalism",
241  "nature",
242  "neuron",
243  "noise",
244  "nomenclature",
245  "nutria",
246  "OBEY",
247  "ocelot",
248  "offspring",
249  "overseer",
250  "pain",
251  "pajamas",
252  "passenger",
253  "passion",
254  "Passover",
255  "peace",
256  "penance",
257  "persimmon",
258  "petticoat",
259  "pharmacist",
260  "PhD",
261  "pitchfork",
262  "plague",
263  "Poindexter",
264  "politician",
265  "pony",
266  "presidency",
267  "prison",
268  "prophecy",
269  "Prozac",
270  "punishment",
271  "punk rock",
272  "punk",
273  "pussy",
274  "quagmire",
275  "quarantine",
276  "quartz",
277  "rabies",
278  "radish",
279  "rage",
280  "readout",
281  "reality",
282  "rectum",
283  "reject",
284  "rejection",
285  "respect",
286  "revolution",
287  "roadrunner",
288  "rule",
289  "savor",
290  "scab",
291  "scalar",
292  "Scandinavia",
293  "schadenfreude",
294  "security",
295  "sediment",
296  "self worth",
297  "sickness",
298  "silicone",
299  "slack",
300  "slander",
301  "slavery",
302  "sledgehammer",
303  "smegma",
304  "smelly socks",
305  "sorrow",
306  "space program",
307  "stamen",
308  "standardization",
309  "stench",
310  "subculture",
311  "subversion",
312  "suffering",
313  "surrender",
314  "surveillance",
315  "synthesis",
316  "television",
317  "tenant",
318  "tendril",
319  "terror",
320  "terrorism",
321  "terrorist",
322  "the impossible",
323  "the unknown",
324  "toast",
325  "topography",
326  "truism",
327  "turgid",
328  "underbrush",
329  "underling",
330  "unguent",
331  "unusual",
332  "uplink",
333  "urge",
334  "valor",
335  "variance",
336  "vaudeville",
337  "vector",
338  "vegetarian",
339  "venom",
340  "verifiability",
341  "viagra",
342  "vibrator",
343  "victim",
344  "vignette",
345  "villainy",
346  "W.A.S.T.E.",
347  "wagon",
348  "waiver",
349  "warehouse",
350  "waste",
351  "waveform",
352  "whiffle ball",
353  "whorl",
354  "windmill",
355  "words",
356  "worm",
357  "worship",
358  "worship",
359  "Xanax",
360  "Xerxes",
361  "Xhosa",
362  "xylophone",
363  "yellow",
364  "yesterday",
365  "your nose",
366  "Zanzibar",
367  "zeal",
368  "zebra",
369  "zest",
370  "zinc"
371};
372
373#define WORD_COUNT (sizeof(words) / sizeof(char *))
374
375
376
377/* ----------------------------------------------------------------------------
378 * bitmap manipulation
379 */
380
381/* construct a new bitmap */
382Bitmap *makeBitmap (int width, int height)
383{
384    Bitmap *result = malloc (sizeof (Bitmap));
385    result->width = width;
386    result->height = height;
387    result->widthBytes = (width + 7) / 8;
388    result->buf = calloc (1, height * result->widthBytes);
389    return result;
390}
391
392/* clear a bitmap */
393void bitmapClear (Bitmap *b)
394{
395    memset (b->buf, 0, b->widthBytes * b->height);
396}
397
398/* free a bitmap */
399void bitmapFree (Bitmap *b)
400{
401    free (b->buf);
402    free (b);
403}
404
405/* get the byte value at the given byte-offset coordinates in the given
406 * bitmap */
407int bitmapGetByte (Bitmap *b, int xByte, int y)
408{
409    if ((xByte < 0) ||
410        (xByte >= b->widthBytes) ||
411        (y < 0) ||
412        (y >= b->height))
413    {
414        /* out-of-range get returns 0 */
415        return 0;
416    }
417
418    return b->buf[b->widthBytes * y + xByte];
419}
420
421/* get the bit value at the given coordinates in the given bitmap */
422int bitmapGet (Bitmap *b, int x, int y)
423{
424    int xbyte = x >> 3;
425    int xbit = x & 0x7;
426    int byteValue = bitmapGetByte (b, xbyte, y);
427
428    return (byteValue & (1 << xbit)) >> xbit;
429}
430
431/* set the bit value at the given coordinates in the given bitmap */
432void bitmapSet (Bitmap *b, int x, int y, int value)
433{
434    int xbyte = x >> 3;
435    int xbit = x & 0x7;
436
437    if ((x < 0) ||
438        (x >= b->width) ||
439        (y < 0) ||
440        (y >= b->height))
441    {
442        /* ignore out-of-range set */
443        return;
444    }
445
446    if (value)
447    {
448        b->buf[b->widthBytes * y + xbyte] |= 1 << xbit;
449    }
450    else
451    {
452        b->buf[b->widthBytes * y + xbyte] &= ~(1 << xbit);
453    }
454}
455
456/* copy the given rectangle to the given destination from the given source. */
457void bitmapCopyRect (Bitmap *dest, int dx, int dy,
458                     Bitmap *src, int sx, int sy, int width, int height)
459{
460    int x, y;
461
462    for (y = 0; y < height; y++)
463    {
464        for (x = 0; x < width; x++)
465        {
466            bitmapSet (dest, x + dx, y + dy, bitmapGet (src, x + sx, y + sy));
467        }
468    }
469}
470
471/* draw a vertical line in the given bitmap */
472void bitmapVlin (Bitmap *b, int x, int y1, int y2)
473{
474    while (y1 <= y2)
475    {
476        bitmapSet (b, x, y1, 1);
477        y1++;
478    }
479}
480
481/* scale a bitmap into another bitmap */
482void bitmapScale (Bitmap *dest, Bitmap *src, int mag)
483{
484    int x, y, x2, y2;
485
486    for (y = 0; y < src->height; y++)
487    {
488        for (x = 0; x < src->width; x++)
489        {
490            int v = bitmapGet (src, x, y);
491            for (x2 = 0; x2 < mag; x2++)
492            {
493                for (y2 = 0; y2 < mag; y2++)
494                {
495                    bitmapSet (dest, x * mag + x2, y * mag + y2, v);
496                }
497            }
498        }
499    }
500}
501
502
503/* ----------------------------------------------------------------------------
504 * character generation
505 */
506
507static unsigned char font5x8Buf[] =
508{
509   0x1e, 0x01, 0x06, 0x01, 0x1e, 0x00, 0x1e, 0x01, 0x06, 0x01, 0x1e, 0x00,
510   0x1e, 0x01, 0x1e, 0x01, 0x1e, 0x00, 0x01, 0x00, 0x1f, 0x08, 0x04, 0x08,
511   0x1f, 0x00, 0x11, 0x1f, 0x11, 0x00, 0x1f, 0x01, 0x01, 0x00, 0x1f, 0x04,
512   0x0a, 0x11, 0x00, 0x01, 0x00, 0x0e, 0x11, 0x11, 0x00, 0x0e, 0x11, 0x11,
513   0x0e, 0x00, 0x1f, 0x08, 0x04, 0x08, 0x1f, 0x00, 0x44, 0x41, 0x4e, 0x20,
514   0x42, 0x4f, 0x52, 0x4e, 0x53, 0x54, 0x45, 0x49, 0x4e, 0x21, 0x21, 0x00,
515   0x66, 0x6e, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
516   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
517   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
518   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
519   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
520   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
521   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
522   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
523   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
524   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
525   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
526   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
527   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
528   0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00,
529   0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
530   0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
531   0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x05, 0x05, 0x00,
532   0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x00,
533   0x02, 0x0f, 0x01, 0x0f, 0x08, 0x0f, 0x04, 0x00, 0x0b, 0x0b, 0x08, 0x06,
534   0x01, 0x0d, 0x0d, 0x00, 0x03, 0x05, 0x02, 0x05, 0x0d, 0x05, 0x0b, 0x00,
535   0x04, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02,
536   0x02, 0x02, 0x04, 0x00, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00,
537   0x00, 0x09, 0x06, 0x0f, 0x06, 0x09, 0x00, 0x00, 0x00, 0x02, 0x02, 0x07,
538   0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x06, 0x00,
539   0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540   0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x04, 0x06, 0x02, 0x01, 0x01, 0x00,
541   0x0f, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x06, 0x04, 0x04, 0x04,
542   0x04, 0x04, 0x0f, 0x00, 0x0f, 0x09, 0x08, 0x0f, 0x01, 0x09, 0x0f, 0x00,
543   0x0f, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x0f, 0x00, 0x09, 0x09, 0x09, 0x0f,
544   0x08, 0x08, 0x08, 0x00, 0x0f, 0x09, 0x01, 0x0f, 0x08, 0x09, 0x0f, 0x00,
545   0x03, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0c,
546   0x04, 0x04, 0x04, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x0f, 0x00,
547   0x0f, 0x09, 0x09, 0x0f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00,
548   0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x04, 0x06, 0x00,
549   0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00,
550   0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x04, 0x02, 0x01, 0x00,
551   0x0f, 0x09, 0x08, 0x0e, 0x02, 0x00, 0x02, 0x00, 0x0f, 0x09, 0x0d, 0x0d,
552   0x0d, 0x01, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00,
553   0x07, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07, 0x00, 0x0f, 0x01, 0x01, 0x01,
554   0x01, 0x01, 0x0f, 0x00, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07, 0x00,
555   0x0f, 0x01, 0x01, 0x0f, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x01, 0x0f,
556   0x01, 0x01, 0x01, 0x00, 0x0f, 0x01, 0x01, 0x0d, 0x09, 0x09, 0x0f, 0x00,
557   0x09, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07, 0x02, 0x02, 0x02,
558   0x02, 0x02, 0x07, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x00,
559   0x09, 0x09, 0x09, 0x07, 0x09, 0x09, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01,
560   0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09, 0x00,
561   0x09, 0x0b, 0x0d, 0x09, 0x09, 0x09, 0x09, 0x00, 0x0f, 0x09, 0x09, 0x09,
562   0x09, 0x09, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x01, 0x01, 0x01, 0x00,
563   0x0f, 0x09, 0x09, 0x09, 0x0b, 0x05, 0x0b, 0x00, 0x07, 0x09, 0x09, 0x07,
564   0x09, 0x09, 0x09, 0x00, 0x0f, 0x01, 0x01, 0x0f, 0x08, 0x08, 0x0f, 0x00,
565   0x0f, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09,
566   0x09, 0x09, 0x0f, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x05, 0x02, 0x00,
567   0x09, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x05, 0x06,
568   0x0a, 0x09, 0x09, 0x00, 0x09, 0x09, 0x09, 0x0f, 0x08, 0x08, 0x0f, 0x00,
569   0x0f, 0x08, 0x08, 0x06, 0x01, 0x01, 0x0f, 0x00, 0x0e, 0x02, 0x02, 0x02,
570   0x02, 0x02, 0x0e, 0x00, 0x01, 0x01, 0x02, 0x06, 0x04, 0x08, 0x08, 0x00,
571   0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x00, 0x02, 0x05, 0x05, 0x00,
572   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
573   0x02, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08,
574   0x0f, 0x09, 0x0f, 0x00, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x09, 0x0f, 0x00,
575   0x00, 0x00, 0x0f, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x08, 0x08, 0x0f, 0x09,
576   0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x09, 0x0f, 0x01, 0x0f, 0x00,
577   0x0e, 0x02, 0x0f, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x09,
578   0x09, 0x0f, 0x08, 0x0c, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x00,
579   0x02, 0x00, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04,
580   0x04, 0x04, 0x05, 0x07, 0x01, 0x01, 0x09, 0x05, 0x03, 0x05, 0x09, 0x00,
581   0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x09, 0x0f,
582   0x0f, 0x09, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x00,
583   0x00, 0x00, 0x0f, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x09,
584   0x09, 0x0f, 0x01, 0x01, 0x00, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x08, 0x08,
585   0x00, 0x00, 0x0f, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x01,
586   0x0f, 0x08, 0x0f, 0x00, 0x00, 0x02, 0x0f, 0x02, 0x02, 0x02, 0x0e, 0x00,
587   0x00, 0x00, 0x09, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x09,
588   0x09, 0x05, 0x02, 0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00,
589   0x00, 0x00, 0x09, 0x09, 0x06, 0x09, 0x09, 0x00, 0x00, 0x00, 0x09, 0x09,
590   0x09, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x0f, 0x08, 0x06, 0x01, 0x0f, 0x00,
591   0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x02, 0x02, 0x02, 0x02,
592   0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x04, 0x02, 0x02, 0x01, 0x00,
593   0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f,
594   0x0f, 0x0f, 0x0f, 0x00
595};
596
597static Bitmap font5x8 = { 8, 1024, 1, (char *) font5x8Buf };
598
599/* draw the given 5x8 character at the given coordinates */
600void bitmapDrawChar5x8 (Bitmap *b, int x, int y, char c)
601{
602    bitmapCopyRect (b, x, y, &font5x8, 0, c * 8, 5, 8);
603}
604
605/* draw a string of 5x8 characters at the given coordinates */
606void bitmapDrawString5x8 (Bitmap *b, int x, int y, char *str)
607{
608    int origx = x;
609
610    while (*str != '\0')
611    {
612        char c = *str;
613        if (c == '\n')
614        {
615            x = origx;
616            y += 8;
617        }
618        else
619        {
620            if (c < ' ')
621            {
622                c = ' ';
623            }
624
625            bitmapDrawChar5x8 (b, x, y, c);
626            x += 5;
627        }
628        str++;
629    }
630}
631
632
633
634/* ----------------------------------------------------------------------------
635 * upc/ean symbologies
636 */
637
638/* A quick lesson in UPC and EAN barcodes:
639 *
640 * Each digit consists of 2 bars and 2 spaces, taking a total width of 7
641 * times the width of the thinnest possible bar or space. There are three
642 * different possible representations for each digit, used depending on
643 * what side of a two-sided barcode the digit is used on, and to encode
644 * checksum or other information in some cases. The three forms are
645 * related. Taking as the "base" form the pattern as seen on the right-hand
646 * side of a UPC-A barcode, the other forms are the inverse of the base
647 * (that is, bar becomes space and vice versa) and the mirror image of the
648 * base. Still confused? Here's a complete table, where 0 means space and 1
649 * means bar:
650 *
651 *      Left-A   Left-B   Right
652 *      -------  -------  -------
653 *   0  0001101  0100111  1110010
654 *   1  0011001  0110011  1100110
655 *   2  0010011  0011011  1101100
656 *   3  0111101  0100001  1000010
657 *   4  0100011  0011101  1011100
658 *   5  0110001  0111001  1001110
659 *   6  0101111  0000101  1010000
660 *   7  0111011  0010001  1000100
661 *   8  0110111  0001001  1001000
662 *   9  0001011  0010111  1110100
663 *
664 * A UPC-A barcode consists of 6 patterns from Left-A on the left-hand side,
665 * 6 patterns from Right on the right-hand side, a guard pattern of 01010
666 * in the middle, and a guard pattern of 101 on each end. The 12th digit
667 * checksum is calculated as follows: Take the 1st, 3rd, ... 11th digits,
668 * sum them and multiplying by 3, and add that to the sum of the other digits.
669 * Subtract the final digit from 10, and that is the checksum digit. (If
670 * the last digit of the sum is 0, then the check digit is 0.)
671 *
672 * An EAN-13 barcode is just like a UPC-A barcode, except that the characters
673 * on the left-hand side have a pattern of Left-A and Left-B that encodes
674 * an extra first digit. Note that an EAN-13 barcode with the first digit
675 * of 0 is exactly the same as the UPC-A barcode of the rightmost 12 digits.
676 * The patterns to encode the first digit are as follows:
677 *
678 *      Left-Hand
679 *      Digit Position
680 *      1 2 3 4 5 6
681 *      - - - - - -
682 *   0  a a a a a a
683 *   1  a a b a b b
684 *   2  a a b b a b
685 *   3  a a b b b a
686 *   4  a b a a b b
687 *   5  a b b a a b
688 *   6  a b b b a a
689 *   7  a b a b a b
690 *   8  a b a b b a
691 *   9  a b b a b a
692 *
693 * The checksum for EAN-13 is just like UPC-A, except the 2nd, 4th, ... 12th
694 * digits are multiplied by 3 instead of the other way around.
695 *
696 * An EAN-8 barcode is just like a UPC-A barcode, except there are only 4
697 * digits in each half. Unlike EAN-13, there's no nonsense about different
698 * left-hand side patterns, either.
699 *
700 * A UPC-E barcode contains 6 explicit characters between a guard of 101
701 * on the left and 010101 on the right. The explicit characters are the
702 * middle six characters of the code. The first and last characters are
703 * encoded in the parity pattern of the six characters. There are two
704 * sets of parity patterns, one to use if the first digit of the number
705 * is 0, and another if it is 1. (UPC-E barcodes may only start with a 0
706 * or 1.) The patterns are as follows:
707 *
708 *      First digit 0     First digit 1
709 *      Explicit Digit    Explicit Digit
710 *      Position          Position
711 *      1 2 3 4 5 6       1 2 3 4 5 6
712 *      - - - - - -       - - - - - -
713 *   0  b b b a a a       a a a b b b
714 *   1  b b a b a a       a a b a b b
715 *   2  b b a a b a       a a b b a b
716 *   3  b b a a a b       a a b b b a
717 *   4  b a b b a a       a b a a b b
718 *   5  b a a b b a       a b b a a b
719 *   6  b a a a b b       a b b b a a
720 *   7  b a b a b a       a b a b a b
721 *   8  b a b a a b       a b a b b a
722 *   9  b a a b a b       a b b a b a
723 *
724 * (Note that the two sets are the complements of each other. Also note
725 * that the first digit 1 patterns are mostly the same as the EAN-13
726 * first digit patterns.) The UPC-E check digit (the final digit encoded in
727 * the parity pattern) is the same as the UPC-A check digit for the
728 * expanded form of the UPC-E number. The expanstion is as follows, based
729 * on the last explicit digit (the second to last digit) in the encoded
730 * number:
731 *
732 *               Corresponding
733 *   UPC-E form  UPC-A form
734 *   ----------  -------------
735 *   XABCDE0Y    XAB00000CDEY
736 *   XABCDE1Y    XAB10000CDEY
737 *   XABCDE2Y    XAB20000CDEY
738 *   XABCDE3Y    XABC00000DEY
739 *   XABCDE4Y    XABCD00000EY
740 *   XABCDE5Y    XABCDE00005Y
741 *   XABCDE6Y    XABCDE00006Y
742 *   XABCDE7Y    XABCDE00007Y
743 *   XABCDE8Y    XABCDE00008Y
744 *   XABCDE9Y    XABCDE00009Y
745 *
746 * All UPC/EAN barcodes may have an additional 2- or 5-digit supplemental
747 * code just to the right of the main barcode. The supplement starts about
748 * one digit-length (that is about 7 times the width of the thinnest bar)
749 * to the right of the main code, beginning with the guard pattern 1011.
750 * After that comes each digit, with a guard pattern of 01 between each,
751 * but not at the end. The digits are encoded using the left A and B
752 * characters to encode a parity pattern.
753 *
754 * For 2-digit supplements, the parity pattern is determined by the
755 * lower two bits of the numeric value of the code (e.g., 42 would use
756 * pattern 2):
757 *
758 *   Lower 2 bits  Parity Pattern
759 *   ------------  --------------
760 *   0 (bin 00)    a a
761 *   1 (bin 01)    a b
762 *   2 (bin 10)    b a
763 *   3 (bin 11)    b b
764 *
765 * For 5-digit supplements, the parity pattern is calculated in a similar
766 * manner to check digit calculation: The first, third, and fifth digits
767 * are summed and multiplied by 3; the second and fourth digits are summed
768 * and multiplied by nine; the parity digit is the sum of those two numbers,
769 * modulo 10. The parity pattern is then the last five patterns from the
770 * UPC-E final digit 0 table for the corresponding digit.
771 */
772
773/* enum to indicate which pattern set to use */
774typedef enum
775{
776    UPC_LEFT_A, UPC_LEFT_B, UPC_RIGHT
777}
778UpcSet;
779
780/* the Left A patterns */
781unsigned int upcLeftA[] = {
782    0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b
783};
784
785/* the Left B patterns */
786unsigned int upcLeftB[] = {
787    0x27, 0x33, 0x1b, 0x21, 0x1d, 0x39, 0x05, 0x11, 0x09, 0x17
788};
789
790/* the Right patterns */
791unsigned int upcRight[] = {
792    0x72, 0x66, 0x6c, 0x42, 0x5c, 0x4e, 0x50, 0x44, 0x48, 0x74
793};
794
795/* the EAN-13 first-digit patterns */
796unsigned int ean13FirstDigit[] = {
797    0x00, 0x0b, 0x0d, 0x0e, 0x13, 0x19, 0x1c, 0x15, 0x16, 0x1a
798};
799
800/* the UPC-E last-digit patterns for first digit 0 (complement for
801 * digit 1); also used for 5-digit supplemental check patterns */
802unsigned int upcELastDigit[] = {
803    0x38, 0x34, 0x32, 0x31, 0x2c, 0x26, 0x23, 0x2a, 0x29, 0x25
804};
805
806/* turn a character into an int representing its digit value; return
807 * 0 for things not in the range '0'-'9' */
808int charToDigit (char c)
809{
810    if ((c >= '0') && (c <= '9'))
811    {
812        return c - '0';
813    }
814    else
815    {
816        return 0;
817    }
818}
819
820/* draw the given digit character at the given coordinates; a '0' is
821 * used in place of any non-digit character */
822void drawDigitChar (Bitmap *b, int x, int y, char c)
823{
824  if (mode != BC_CLOCK24 &&
825      mode != BC_CLOCK12)
826    if ((c < '0') || (c > '9'))
827      c = '0';
828
829    bitmapDrawChar5x8 (b, x, y, c);
830}
831
832/* draw a upc/ean digit at the given coordinates */
833void drawUpcEanDigit (Bitmap *upcBitmap, int x, int y1, int y2, char n,
834                      UpcSet set)
835{
836    unsigned int bits;
837    int i;
838   
839    n = charToDigit (n);
840    switch (set)
841    {
842        case UPC_LEFT_A:
843            bits = upcLeftA[(int) n];
844            break;
845        case UPC_LEFT_B:
846            bits = upcLeftB[(int) n];
847            break;
848        default /* case UPC_RIGHT */:
849            bits = upcRight[(int) n];
850            break;
851    }
852
853    for (i = 6; i >=0; i--)
854    {
855        if (bits & (1 << i))
856        {
857            bitmapVlin (upcBitmap, x, y1, y2);
858        }
859        x++;
860    }
861}
862
863/* report the width of the given supplemental code or 0 if it is a bad
864 * supplement form */
865int upcEanSupplementWidth (char *digits)
866{
867    switch (strlen (digits))
868    {
869        case 2: return 28; /* 8 + 4 + 2*7 + 1*2 */
870        case 5: return 55; /* 8 + 4 + 5*7 + 4*2 */
871        default: return 0;
872    }
873}
874
875/* draw the given supplemental barcode, including the textual digits */
876void drawUpcEanSupplementalBars (Bitmap *upcBitmap, char *digits,
877                                 int x, int y, int y2, int textAbove)
878{
879    int len = strlen (digits);
880    int i;
881    int parity;
882    int textY;
883    int textX;
884
885    if (textAbove)
886    {
887        textY = y;
888        y += 8;
889    }
890    else
891    {
892        y2 -= 8;
893        textY = y2 + 2;
894    }
895
896    x += 8; /* skip the space between the main and supplemental */
897
898    switch (len)
899    {
900        case 2:
901        {
902            textX = x + 5;
903            parity = (charToDigit (digits[0]) * 10 +
904                      charToDigit (digits[1])) & 0x3;
905            break;
906        }
907        case 5:
908        {
909            textX = x + 10;
910            parity =
911                ((charToDigit (digits[0]) + charToDigit (digits[2]) +
912                  charToDigit (digits[4])) * 3
913                 + (charToDigit (digits[1]) + charToDigit (digits[3])) * 9)
914                % 10;
915            parity = upcELastDigit[parity];
916            break;
917        }
918        default:
919        {
920            fprintf (stderr, "%s: bad supplement (%d digits)\n",
921                     progname, len);
922            exit(1);
923            break;
924        }
925    }
926
927    /* header */
928    bitmapVlin (upcBitmap, x, y, y2);
929    bitmapVlin (upcBitmap, x + 2, y, y2);
930    bitmapVlin (upcBitmap, x + 3, y, y2);
931
932    for (i = 0; i < len; i++)
933    {
934        UpcSet lset =
935            (parity & (1 << (len - 1 - i))) ? UPC_LEFT_B : UPC_LEFT_A;
936        int baseX = x + 2 + i * 9;
937
938        /* separator / end of header */
939        if (i == 0)
940        {
941            bitmapVlin (upcBitmap, baseX, y, y2);
942        }
943        bitmapVlin (upcBitmap, baseX + 1, y, y2);
944
945        drawUpcEanDigit (upcBitmap,
946                         baseX + 2,
947                         y,
948                         y2,
949                         digits[i],
950                         lset);
951
952        drawDigitChar (upcBitmap, textX + i*6, textY, digits[i]);
953    }
954}
955
956/* draw the actual barcode part of a UPC-A barcode */
957void drawUpcABars (Bitmap *upcBitmap, char *digits, int x, int y,
958                   int barY2, int guardY2)
959{
960    int i;
961
962    /* header */
963    bitmapVlin (upcBitmap, x, y, guardY2);
964    bitmapVlin (upcBitmap, x + 2, y, guardY2);
965
966    /* center marker */
967    bitmapVlin (upcBitmap, x + 46, y, guardY2);
968    bitmapVlin (upcBitmap, x + 48, y, guardY2);
969
970    /* trailer */
971    bitmapVlin (upcBitmap, x + 92, y, guardY2);
972    bitmapVlin (upcBitmap, x + 94, y, guardY2);
973
974    for (i = 0; i < 6; i++)
975    {
976        drawUpcEanDigit (upcBitmap,
977                         x + 3 + i*7,
978                         y,
979                         (i == 0) ? guardY2 : barY2,
980                         digits[i],
981                         UPC_LEFT_A);
982        drawUpcEanDigit (upcBitmap,
983                         x + 50 + i*7,
984                         y,
985                         (i == 5) ? guardY2 : barY2,
986                         digits[i+6],
987                         UPC_RIGHT);
988    }
989}
990
991/* make and return a full-height UPC-A barcode */
992int makeUpcAFull (Bitmap *dest, char *digits, int y)
993{
994    static int baseWidth = 108;
995    static int baseHeight = 60;
996
997    int height = baseHeight + y;
998    int i;
999
1000    bitmapClear (dest);
1001    drawUpcABars (dest, digits, 6, y, height - 10, height - 4);
1002
1003    drawDigitChar (dest, 0, height - 14, digits[0]);
1004
1005    for (i = 0; i < 5; i++)
1006    {
1007        drawDigitChar (dest, 18 + i*7, height - 7, digits[i+1]);
1008        drawDigitChar (dest, 57 + i*7, height - 7, digits[i+6]);
1009    }
1010
1011    drawDigitChar (dest, 103, height - 14, digits[11]);
1012
1013    return baseWidth;
1014}
1015
1016/* make and return a UPC-A barcode */
1017int makeUpcA (Bitmap *dest, char *digits, int y)
1018{
1019    int i;
1020    unsigned int mul = 3;
1021    unsigned int sum = 0;
1022
1023    for (i = 0; i < 11; i++)
1024    {
1025        sum += charToDigit (digits[i]) * mul;
1026        mul ^= 2;
1027    }
1028
1029    if (digits[11] == '?')
1030    {
1031        digits[11] = ((10 - (sum % 10)) % 10) + '0';
1032    }
1033
1034    return makeUpcAFull (dest, digits, y);
1035}
1036
1037/* draw the actual barcode part of a UPC-E barcode */
1038void drawUpcEBars (Bitmap *upcBitmap, char *digits, int x, int y,
1039                   int barY2, int guardY2)
1040{
1041    int i;
1042    int parityPattern = upcELastDigit[charToDigit(digits[7])];
1043
1044    int clockp = (mode == BC_CLOCK12 || mode == BC_CLOCK24);
1045
1046    if (digits[0] == '1')
1047    {
1048        parityPattern = ~parityPattern;
1049    }
1050
1051    /* header */
1052    bitmapVlin (upcBitmap, x,     y, guardY2);
1053    bitmapVlin (upcBitmap, x + 2, y, guardY2);
1054
1055    /* trailer */
1056    bitmapVlin (upcBitmap, x + 46 + (clockp?8:0), y, guardY2);
1057    bitmapVlin (upcBitmap, x + 48 + (clockp?8:0), y, guardY2);
1058    bitmapVlin (upcBitmap, x + 50 + (clockp?8:0), y, guardY2);
1059
1060    /* clock kludge -- this draws an extra set of dividers after
1061       digits 2 and 4.  This makes this *not* be a valid bar code,
1062       but, it looks pretty for the clock display.
1063     */
1064    if (clockp)
1065      {
1066        bitmapVlin (upcBitmap, x + 18,     y, guardY2);
1067        bitmapVlin (upcBitmap, x + 18 + 2, y, guardY2);
1068
1069        bitmapVlin (upcBitmap, x + 36,     y, guardY2);
1070        bitmapVlin (upcBitmap, x + 36 + 2, y, guardY2);
1071      }
1072
1073    for (i = 0; i < 6; i++)
1074    {
1075        UpcSet lset =
1076            (parityPattern & (1 << (5 - i))) ? UPC_LEFT_B : UPC_LEFT_A;
1077        int off = (clockp
1078                   ? (i < 2 ? 0 :
1079                      i < 4 ? 4 :      /* extra spacing for clock bars */
1080                              8)
1081                   : 0);
1082        drawUpcEanDigit (upcBitmap,
1083                         x + 3 + i*7 + off,
1084                         y,
1085                         barY2,
1086                         digits[i + 1],
1087                         lset);
1088    }
1089}
1090
1091/* make and return a full-height UPC-E barcode */
1092int makeUpcEFull (Bitmap *dest, char *digits, int y)
1093{
1094    static int baseWidth = 64;
1095    static int baseHeight = 60;
1096
1097    int height = baseHeight + y;
1098    int i;
1099
1100    bitmapClear (dest);
1101    drawUpcEBars (dest, digits, 6, y, height - 10, height - 4);
1102
1103    drawDigitChar (dest, 0, height - 14, digits[0]);
1104
1105    for (i = 0; i < 6; i++)
1106    {
1107        drawDigitChar (dest, 11 + i*7, height - 7, digits[i+1]);
1108    }
1109
1110    drawDigitChar (dest, 59, height - 14, digits[7]);
1111
1112    return baseWidth;
1113}
1114
1115/* expand 8 UPC-E digits into a UPC-A number, storing into the given result
1116 * array, or just store '\0' into the first element, if the form factor
1117 * is incorrect; this will also calculate the check digit, if it is
1118 * specified as '?' */
1119void expandToUpcADigits (char *compressed, char *expanded)
1120{
1121    int i;
1122
1123    if ((compressed[0] != '0') && (compressed[0] != '1'))
1124    {
1125        return;
1126    }
1127
1128    expanded[0] = compressed[0];
1129    expanded[6] = '0';
1130    expanded[7] = '0';
1131    expanded[11] = compressed[7];
1132
1133    switch (compressed[6])
1134    {
1135        case '0':
1136        case '1':
1137        case '2':
1138        {
1139            expanded[1] = compressed[1];
1140            expanded[2] = compressed[2];
1141            expanded[3] = compressed[6];
1142            expanded[4] = '0';
1143            expanded[5] = '0';
1144            expanded[8] = compressed[3];
1145            expanded[9] = compressed[4];
1146            expanded[10] = compressed[5];
1147            break;
1148        }
1149        case '3':
1150        {
1151            expanded[1] = compressed[1];
1152            expanded[2] = compressed[2];
1153            expanded[3] = compressed[3];
1154            expanded[4] = '0';
1155            expanded[5] = '0';
1156            expanded[8] = '0';
1157            expanded[9] = compressed[4];
1158            expanded[10] = compressed[5];
1159            break;
1160        }
1161        case '4':
1162        {
1163            expanded[1] = compressed[1];
1164            expanded[2] = compressed[2];
1165            expanded[3] = compressed[3];
1166            expanded[4] = compressed[4];
1167            expanded[5] = '0';
1168            expanded[8] = '0';
1169            expanded[9] = '0';
1170            expanded[10] = compressed[5];
1171            break;
1172        }
1173        default:
1174        {
1175            expanded[1] = compressed[1];
1176            expanded[2] = compressed[2];
1177            expanded[3] = compressed[3];
1178            expanded[4] = compressed[4];
1179            expanded[5] = compressed[5];
1180            expanded[8] = '0';
1181            expanded[9] = '0';
1182            expanded[10] = compressed[6];
1183            break;
1184        }
1185    }
1186
1187    if (expanded[11] == '?')
1188    {
1189        unsigned int mul = 3;
1190        unsigned int sum = 0;
1191
1192        for (i = 0; i < 11; i++)
1193        {
1194            sum += charToDigit (expanded[i]) * mul;
1195            mul ^= 2;
1196        }
1197
1198        expanded[11] = ((10 - (sum % 10)) % 10) + '0';
1199    }
1200}
1201
1202/* make and return a UPC-E barcode */
1203int makeUpcE (Bitmap *dest, char *digits, int y)
1204{
1205    char expandedDigits[13];
1206    char compressedDigits[9];
1207
1208    expandedDigits[0] = '\0';
1209    compressedDigits[0] = '0';
1210    strcpy (compressedDigits + 1, digits);
1211
1212    expandToUpcADigits (compressedDigits, expandedDigits);
1213    if (expandedDigits[0] == '\0')
1214    {
1215        return 0;
1216    }
1217   
1218    compressedDigits[7] = expandedDigits[11];
1219
1220    return makeUpcEFull (dest, compressedDigits, y);
1221}
1222
1223/* draw the actual barcode part of a EAN-13 barcode */
1224void drawEan13Bars (Bitmap *upcBitmap, char *digits, int x, int y,
1225                   int barY2, int guardY2)
1226{
1227    int i;
1228    int leftPattern = ean13FirstDigit[charToDigit (digits[0])];
1229
1230    /* header */
1231    bitmapVlin (upcBitmap, x, y, guardY2);
1232    bitmapVlin (upcBitmap, x + 2, y, guardY2);
1233
1234    /* center marker */
1235    bitmapVlin (upcBitmap, x + 46, y, guardY2);
1236    bitmapVlin (upcBitmap, x + 48, y, guardY2);
1237
1238    /* trailer */
1239    bitmapVlin (upcBitmap, x + 92, y, guardY2);
1240    bitmapVlin (upcBitmap, x + 94, y, guardY2);
1241
1242    for (i = 0; i < 6; i++)
1243    {
1244        UpcSet lset = (leftPattern & (1 << (5 - i))) ? UPC_LEFT_B : UPC_LEFT_A;
1245
1246        drawUpcEanDigit (upcBitmap,
1247                         x + 3 + i*7,
1248                         y,
1249                         barY2,
1250                         digits[i+1],
1251                         lset);
1252        drawUpcEanDigit (upcBitmap,
1253                         x + 50 + i*7,
1254                         y,
1255                         barY2,
1256                         digits[i+7],
1257                         UPC_RIGHT);
1258    }
1259}
1260
1261/* make and return a full-height EAN-13 barcode */
1262int makeEan13Full (Bitmap *dest, char *digits, int y)
1263{
1264    static int baseWidth = 102;
1265    static int baseHeight = 60;
1266
1267    int height = baseHeight + y;
1268    int i;
1269
1270    bitmapClear (dest);
1271    drawEan13Bars (dest, digits, 6, y, height - 10, height - 4);
1272
1273    drawDigitChar (dest, 0, height - 7, digits[0]);
1274
1275    for (i = 0; i < 6; i++)
1276    {
1277        drawDigitChar (dest, 11 + i*7, height - 7, digits[i+1]);
1278        drawDigitChar (dest, 57 + i*7, height - 7, digits[i+7]);
1279    }
1280
1281    return baseWidth;
1282}
1283
1284/* make and return an EAN-13 barcode */
1285int makeEan13 (Bitmap *dest, char *digits, int y)
1286{
1287    int i;
1288    unsigned int mul = 1;
1289    unsigned int sum = 0;
1290
1291    for (i = 0; i < 12; i++)
1292    {
1293        sum += charToDigit (digits[i]) * mul;
1294        mul ^= 2;
1295    }
1296
1297    if (digits[12] == '?')
1298    {
1299        digits[12] = ((10 - (sum % 10)) % 10) + '0';
1300    }
1301
1302    return makeEan13Full (dest, digits, y);
1303}
1304
1305/* draw the actual barcode part of an EAN-8 barcode */
1306void drawEan8Bars (Bitmap *upcBitmap, char *digits, int x, int y,
1307                   int barY2, int guardY2)
1308{
1309    int i;
1310
1311    /* header */
1312    bitmapVlin (upcBitmap, x, y, guardY2);
1313    bitmapVlin (upcBitmap, x + 2, y, guardY2);
1314
1315    /* center marker */
1316    bitmapVlin (upcBitmap, x + 32, y, guardY2);
1317    bitmapVlin (upcBitmap, x + 34, y, guardY2);
1318
1319    /* trailer */
1320    bitmapVlin (upcBitmap, x + 64, y, guardY2);
1321    bitmapVlin (upcBitmap, x + 66, y, guardY2);
1322
1323    for (i = 0; i < 4; i++)
1324    {
1325        drawUpcEanDigit (upcBitmap,
1326                         x + 3 + i*7,
1327                         y,
1328                         barY2,
1329                         digits[i],
1330                         UPC_LEFT_A);
1331        drawUpcEanDigit (upcBitmap,
1332                         x + 36 + i*7,
1333                         y,
1334                         barY2,
1335                         digits[i+4],
1336                         UPC_RIGHT);
1337    }
1338}
1339
1340/* make and return a full-height EAN-8 barcode */
1341int makeEan8Full (Bitmap *dest, char *digits, int y)
1342{
1343    static int baseWidth = 68;
1344    static int baseHeight = 60;
1345
1346    int height = baseHeight + y;
1347    int i;
1348
1349    bitmapClear (dest);
1350    drawEan8Bars (dest, digits, 0, y, height - 10, height - 4);
1351
1352    for (i = 0; i < 4; i++)
1353    {
1354        drawDigitChar (dest, 5 + i*7, height - 7, digits[i]);
1355        drawDigitChar (dest, 37 + i*7, height - 7, digits[i+4]);
1356    }
1357
1358    return baseWidth;
1359}
1360
1361/* make and return an EAN-8 barcode */
1362int makeEan8 (Bitmap *dest, char *digits, int y)
1363{
1364    int i;
1365    unsigned int mul = 3;
1366    unsigned int sum = 0;
1367
1368    for (i = 0; i < 7; i++)
1369    {
1370        sum += charToDigit (digits[i]) * mul;
1371        mul ^= 2;
1372    }
1373
1374    if (digits[7] == '?')
1375    {
1376        digits[7] = ((10 - (sum % 10)) % 10) + '0';
1377    }
1378
1379    return makeEan8Full (dest, digits, y);
1380}
1381
1382/* Dispatch to the right form factor UPC/EAN barcode generator */
1383void processUpcEan (char *str, Bitmap *dest)
1384{
1385    char digits[16];
1386    int digitCount = 0;
1387    char supDigits[8];
1388    int supDigitCount = 0;
1389    char *instr = str;
1390    char *banner = NULL;
1391    int supplement = 0;
1392    int vstart = 9;
1393    int width = 0;
1394
1395    while ((digitCount < 15) && (supDigitCount < 7))
1396    {
1397        char c = *instr;
1398        if (((c >= '0') && (c <= '9')) || (c == '?'))
1399        {
1400            if (supplement)
1401            {
1402                supDigits[supDigitCount] = *instr;
1403                supDigitCount++;
1404            }
1405            else
1406            {
1407                digits[digitCount] = *instr;
1408                digitCount++;
1409            }
1410        }
1411        else if (c == ',')
1412        {
1413            supplement = 1;
1414        }
1415        else if (c == ':')
1416        {
1417            banner = instr + 1;
1418            break;
1419        }
1420        else if (c == '\0')
1421        {
1422            break;
1423        }
1424        instr++;
1425    }
1426
1427    digits[digitCount] = '\0';
1428    supDigits[supDigitCount] = '\0';
1429
1430    if (supDigitCount == 0)
1431    {
1432        supplement = 0;
1433    }
1434    else if ((supDigitCount == 2) || (supDigitCount == 5))
1435    {
1436        supplement = upcEanSupplementWidth (supDigits);
1437    }
1438    else
1439    {
1440        fprintf (stderr, "%s: invalid supplement (must be 2 or 5 digits)\n",
1441                 progname);
1442        exit (1);
1443    }
1444
1445    if (banner == NULL)
1446    {
1447        banner = "barcode";
1448    }
1449
1450    switch (digitCount)
1451    {
1452        case 7:
1453        {
1454            width = makeUpcE (dest, digits, vstart);
1455            break;
1456        }
1457        case 8:
1458        {
1459            width = makeEan8 (dest, digits, vstart);
1460            break;
1461        }
1462        case 12:
1463        {
1464            width = makeUpcA (dest, digits, vstart);
1465            break;
1466        }
1467        case 13:
1468        {
1469            width = makeEan13 (dest, digits, vstart);
1470            break;
1471        }
1472        default:
1473        {
1474            fprintf (stderr, "%s: bad barcode (%d digits)\n",
1475                     progname, digitCount);
1476            exit(1);
1477        }
1478    }
1479
1480    if (supplement)
1481    {
1482        drawUpcEanSupplementalBars (dest, supDigits,
1483                                    width,
1484                                    vstart + 1, dest->height - 4, 1);
1485    }
1486
1487    if (banner != NULL)
1488    {
1489        bitmapDrawString5x8 (dest,
1490                             (width + supplement -
1491                              ((int) strlen (banner) * 5)) / 2,
1492                             0,
1493                             banner);
1494    }
1495}
1496
1497
1498
1499/* ----------------------------------------------------------------------------
1500 * the screenhack
1501 */
1502
1503/*
1504 * overall setup stuff
1505 */
1506
1507/* set up the system */
1508static void setup (void)
1509{
1510    XWindowAttributes xgwa;
1511    XGCValues gcv;
1512
1513    XGetWindowAttributes (display, window, &xgwa);
1514
1515    screen = xgwa.screen;
1516    visual = xgwa.visual;
1517    cmap = xgwa.colormap;
1518    windowWidth = xgwa.width;
1519    windowHeight = xgwa.height;
1520
1521    gcv.background = get_pixel_resource ("background", "Background",
1522                                         display, xgwa.colormap);
1523    gcv.foreground = get_pixel_resource ("foreground", "Foreground",
1524                                         display, xgwa.colormap);
1525    fg_pixel = gcv.foreground;
1526    theGC = XCreateGC (display, window, GCForeground|GCBackground, &gcv);
1527
1528    theBitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, BARCODE_HEIGHT * MAX_MAG);
1529    theImage = XCreateImage(display, visual, 1, XYBitmap, 0, theBitmap->buf,
1530                            theBitmap->width, theBitmap->height, 8,
1531                            theBitmap->widthBytes);
1532}
1533
1534
1535
1536/*
1537 * the simulation
1538 */
1539
1540/* set up the model */
1541static void setupModel (void)
1542{
1543    int i;
1544
1545    barcode_max = 20;
1546    barcode_count = 0;
1547    barcodes = malloc (sizeof (Barcode) * barcode_max);
1548
1549    for (i = 0; i < barcode_max; i++)
1550    {
1551        barcodes[i].bitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG,
1552                                        BARCODE_HEIGHT * MAX_MAG);
1553    }
1554}
1555
1556/* make a new barcode string */
1557static void makeBarcodeString (char *str)
1558{
1559    int dig, i;
1560
1561    switch ((int) (RAND_FLOAT_01 * 4))
1562    {
1563        case 0:  dig = 6;  break;
1564        case 1:  dig = 7;  break;
1565        case 2:  dig = 11; break;
1566        default: dig = 12; break;
1567    }
1568
1569    for (i = 0; i < dig; i++)
1570    {
1571        str[i] = RAND_FLOAT_01 * 10 + '0';
1572    }
1573
1574    str[i] = '?';
1575    i++;
1576
1577    switch ((int) (RAND_FLOAT_01 * 3))
1578    {
1579        case 0:  dig = 0; break;
1580        case 1:  dig = 2; break;
1581        default: dig = 5; break;
1582    }
1583
1584    if (dig != 0)
1585    {
1586        str[i] = ',';
1587        i++;
1588        while (dig > 0)
1589        {
1590            str[i] = RAND_FLOAT_01 * 10 + '0';
1591            i++;
1592            dig--;
1593        }
1594    }
1595
1596    str[i] = ':';
1597    i++;
1598
1599    strcpy(&str[i], words[(int) (RAND_FLOAT_01 * WORD_COUNT)]);
1600}
1601
1602/* update the model for one iteration */
1603static void scrollModel (void)
1604{
1605    int i;
1606
1607    for (i = 0; i < barcode_count; i++)
1608    {
1609        Barcode *b = &barcodes[i];
1610        b->x--;
1611        if ((b->x + BARCODE_WIDTH * b->mag) < 0)
1612        {
1613            /* fell off the edge */
1614            if (i != (barcode_count - 1)) {
1615                Bitmap *oldb = b->bitmap;
1616                memmove (b, b + 1, (barcode_count - i - 1) * sizeof (Barcode));
1617                barcodes[barcode_count - 1].bitmap = oldb;
1618
1619                XFreeColors (display, cmap, &b->pixel, 1, 0);
1620            }
1621
1622            i--;
1623            barcode_count--;
1624        }
1625    }
1626
1627    while (barcode_count < barcode_max)
1628    {
1629        Barcode *barcode = &barcodes[barcode_count];
1630        barcode->x = (barcode_count == 0) ?
1631            0 :
1632            (barcodes[barcode_count - 1].x +
1633             barcodes[barcode_count - 1].mag * BARCODE_WIDTH);
1634        barcode->x += RAND_FLOAT_01 * 100;
1635        barcode->mag = RAND_FLOAT_01 * MAX_MAG;
1636        barcode->y =
1637            RAND_FLOAT_01 * (windowHeight - BARCODE_HEIGHT * barcode->mag);
1638        if (barcode->y < 0)
1639        {
1640            barcode->y = 0;
1641        }
1642        makeBarcodeString(barcode->code);
1643        processUpcEan (barcode->code, theBitmap);
1644        bitmapScale (barcode->bitmap, theBitmap, barcode->mag);
1645
1646        {
1647          XColor c;
1648          int i, ok = 0;
1649          for (i = 0; i < 100; i++)
1650            {
1651              hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue);
1652              ok = XAllocColor (display, cmap, &c);
1653              if (ok) break;
1654            }
1655          if (!ok)
1656            {
1657              c.red = c.green = c.blue = 0xFFFF;
1658              if (!XAllocColor (display, cmap, &c))
1659                abort();
1660            }
1661          barcode->pixel = c.pixel;
1662        }
1663
1664        barcode_count++;
1665    }
1666}
1667
1668/* update the model for one iteration */
1669static void updateGrid (void)
1670{
1671    int i, x, y;
1672    static int grid_w = 0;
1673    static int grid_h = 0;
1674
1675    static unsigned long pixel;
1676    static int alloced_p = 0;
1677
1678    static char *strings[200] = { 0, };
1679
1680    if (grid_w == 0 || grid_h == 0 ||
1681        (! (random() % 400)))
1682      {
1683        XClearWindow (display, window);
1684        grid_w = 1 + (random() % 3);
1685        grid_h = 1 + (random() % 4);
1686      }
1687
1688    if (!alloced_p || (! (random() % 100)))
1689      {
1690        XColor c;
1691        hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue);
1692        if (alloced_p)
1693          XFreeColors (display, cmap, &pixel, 1, 0);
1694        XAllocColor (display, cmap, &c);
1695        pixel = c.pixel;
1696        alloced_p = 1;
1697      }
1698
1699    barcode_count = grid_w * grid_h;
1700    if (barcode_count > barcode_max) abort();
1701
1702    for (i = 0; i < barcode_max; i++)
1703      {
1704        Barcode *b = &barcodes[i];
1705        b->x = b->y = 999999;
1706      }
1707
1708    i = 0;
1709    for (y = 0; y < grid_h; y++)
1710      for (x = 0; x < grid_w; x++, i++)
1711        {
1712          Barcode *b = &barcodes[i];
1713          int digits = 12;
1714
1715          int cell_w = (windowWidth  / grid_w);
1716          int cell_h = (windowHeight / grid_h);
1717          int mag_x  = cell_w / BARCODE_WIDTH;
1718          int mag_y  = cell_h / BARCODE_HEIGHT;
1719          int BW = 108 /*BARCODE_WIDTH*/;
1720          int BH = BARCODE_HEIGHT;
1721
1722          b->mag = (mag_x < mag_y ? mag_x : mag_y);
1723
1724          b->x = (x * cell_w) + ((cell_w - b->mag * BW) / 2);
1725          b->y = (y * cell_h) + ((cell_h - b->mag * BH) / 2);
1726          b->pixel = pixel;
1727
1728          if (!strings[i])
1729            {
1730              int j;
1731              char *s = malloc (digits + 10);
1732              strings[i] = s;
1733              for (j = 0; j < digits; j++)
1734                s[j] = (random() % 10) + '0';
1735              s[j++] = '?';
1736              s[j++] = ':';
1737              s[j++] = 0;
1738            }
1739
1740          /* change one digit in this barcode */
1741          strings[i][random() % digits] = (random() % 10) + '0';
1742
1743          strcpy (b->code, strings[i]);
1744          processUpcEan (b->code, b->bitmap);
1745        }
1746}
1747
1748
1749/* update the model for one iteration.
1750   This one draws a clock.  By jwz.  */
1751static void updateClock (void)
1752{
1753  Barcode *b = &barcodes[0];
1754  int BW = 76 /* BARCODE_WIDTH  */;
1755  int BH = BARCODE_HEIGHT;
1756  int mag_x, mag_y;
1757  int i;
1758  time_t now = time ((time_t *) 0);
1759  struct tm *tm = localtime (&now);
1760  XWindowAttributes xgwa;
1761  int ow = windowWidth;
1762  int oh = windowHeight;
1763
1764  XGetWindowAttributes (display, window, &xgwa);
1765  windowWidth = xgwa.width;
1766  windowHeight = xgwa.height;
1767
1768  mag_x  = windowWidth  / BW;
1769  mag_y  = windowHeight / BH;
1770
1771  barcode_count = 1;
1772
1773  b->mag = (mag_x < mag_y ? mag_x : mag_y);
1774
1775  if (b->mag > MAX_MAG) b->mag = MAX_MAG;
1776  if (b->mag < 1) b->mag = 1;
1777
1778  b->x = (windowWidth  - (b->mag * BW      )) / 2;
1779  b->y = (windowHeight - (b->mag * (BH + 9))) / 2;
1780  b->pixel = fg_pixel;
1781
1782  if (!button_down_p)
1783    sprintf (b->code, "0%02d%02d%02d?:",
1784             (mode == BC_CLOCK24
1785              ? tm->tm_hour
1786              : (tm->tm_hour > 12
1787                 ? tm->tm_hour - 12
1788                 : (tm->tm_hour == 0
1789                    ? 12
1790                    : tm->tm_hour))),
1791             tm->tm_min,
1792             tm->tm_sec);
1793  else
1794    sprintf (b->code, "0%02d%02d%02d?:",
1795             tm->tm_year % 100, tm->tm_mon+1, tm->tm_mday);
1796
1797  {
1798    int vstart = 9;
1799    int hh = BH + vstart;
1800    char expandedDigits[13];
1801
1802    expandedDigits[0] = '\0';
1803
1804    expandToUpcADigits (b->code, expandedDigits);
1805    if (expandedDigits[0] != '\0')
1806      b->code[7] = expandedDigits[11];
1807
1808    bitmapClear (theBitmap);
1809    drawUpcEBars (theBitmap, b->code, 6, 9, 59, 65);
1810    for (i = 0; i < 6; i++)
1811      {
1812        int off = (i < 2 ? 0 :
1813                   i < 4 ? 4 :
1814                   8);
1815        drawDigitChar (theBitmap, 11 + i*7 + off, hh - 16, b->code[i+1]);
1816      }
1817
1818    if (!button_down_p)
1819      {
1820#if 0
1821        char *days[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
1822        char *s = days[tm->tm_wday];
1823        bitmapDrawString5x8 (theBitmap, (BW - strlen (s)*5) / 2, 0, s);
1824#endif
1825        drawDigitChar (theBitmap,  0, hh - 23, (tm->tm_hour < 12 ? 'A' : 'P'));
1826        drawDigitChar (theBitmap, 68, hh - 23, 'M');
1827      }
1828    else
1829      {
1830        char s[20];
1831        sprintf (s, "%03d", tm->tm_yday);
1832        bitmapDrawString5x8 (theBitmap, (BW - strlen (s)*5) / 2, 0, s);
1833      }
1834  }
1835
1836  bitmapScale (b->bitmap, theBitmap, b->mag);
1837
1838  if (ow != windowWidth || oh != windowHeight)
1839    XClearWindow (display, window);
1840}
1841
1842
1843
1844/* render and display the current model */
1845static void renderFrame (void)
1846{
1847    int i;
1848
1849    for (i = 0; i < barcode_count; i++)
1850    {
1851        Barcode *barcode = &barcodes[i];
1852
1853        if (barcode->x > windowWidth) {
1854            break;
1855        }
1856
1857        /* bitmapScale (theBitmap, barcode->bitmap, barcode->mag);*/
1858        theImage->data = barcode->bitmap->buf;
1859
1860        XSetForeground (display, theGC, barcode->pixel);
1861        XPutImage (display, window, theGC, theImage,
1862                   0, 0, barcode->x, barcode->y,
1863                   BARCODE_WIDTH * barcode->mag,
1864                   BARCODE_HEIGHT * barcode->mag);
1865    }
1866}
1867
1868/* do one iteration */
1869static void oneIteration (void)
1870{
1871    if (mode == BC_SCROLL)
1872      scrollModel ();
1873    else if (mode == BC_GRID)
1874      updateGrid ();
1875    else if (mode == BC_CLOCK12 || mode == BC_CLOCK24)
1876      updateClock ();
1877    else
1878      abort();
1879
1880    renderFrame ();
1881}
1882
1883
1884static void barcode_handle_events (Display *dpy)
1885{
1886  int clockp = (mode == BC_CLOCK12 || mode == BC_CLOCK24);
1887  while (XPending (dpy))
1888    {
1889      XEvent event;
1890      XNextEvent (dpy, &event);
1891      if (clockp && event.xany.type == ButtonPress)
1892        button_down_p = True;
1893      else if (clockp && event.xany.type == ButtonRelease)
1894        button_down_p = False;
1895      else
1896        screenhack_handle_event (dpy, &event);
1897    }
1898}
1899
1900
1901/* main and options and stuff */
1902
1903char *progclass = "Barcode";
1904
1905char *defaults [] = {
1906    ".background:       black",
1907    ".foreground:       green",
1908    "*delay:            10000",
1909    0
1910};
1911
1912XrmOptionDescRec options [] = {
1913  { "-delay",            ".delay",          XrmoptionSepArg, 0 },
1914  { "-scroll",           ".mode",           XrmoptionNoArg, "scroll"  },
1915  { "-grid",             ".mode",           XrmoptionNoArg, "grid"    },
1916  { "-clock",            ".mode",           XrmoptionNoArg, "clock"   },
1917  { "-clock12",          ".mode",           XrmoptionNoArg, "clock12" },
1918  { "-clock24",          ".mode",           XrmoptionNoArg, "clock24" },
1919  { 0, 0, 0, 0 }
1920};
1921
1922/* initialize the user-specifiable params */
1923static void initParams (void)
1924{
1925    int problems = 0;
1926    char *s;
1927
1928    delay = get_integer_resource ("delay", "Delay");
1929    if (delay < 0)
1930    {
1931        fprintf (stderr, "%s: delay must be at least 0\n", progname);
1932        problems = 1;
1933    }
1934
1935    s = get_string_resource ("mode", "Mode");
1936    if (!s || !*s || !strcasecmp (s, "scroll"))
1937      mode = BC_SCROLL;
1938    else if (!strcasecmp (s, "grid"))
1939      mode = BC_GRID;
1940    else if (!strcasecmp (s, "clock") ||
1941             !strcasecmp (s, "clock12"))
1942      mode = BC_CLOCK12;
1943    else if (!strcasecmp (s, "clock24"))
1944      mode = BC_CLOCK24;
1945    else
1946      {
1947        fprintf (stderr, "%s: unknown mode \"%s\"\n", progname, s);
1948        problems = 1;
1949      }
1950    free (s);
1951
1952    if (mode == BC_CLOCK12 || mode == BC_CLOCK24)
1953      delay = 10000;  /* only update every 1/10th second */
1954
1955    if (problems)
1956    {
1957        exit (1);
1958    }
1959}
1960
1961/* main function */
1962void screenhack (Display *dpy, Window win)
1963{
1964    display = dpy;
1965    window = win;
1966
1967    initParams ();
1968    setup ();
1969    setupModel ();
1970
1971    for (;;)
1972    {
1973        oneIteration ();
1974        XSync (dpy, False);
1975        barcode_handle_events (dpy);
1976        usleep (delay);
1977    }
1978}
Note: See TracBrowser for help on using the repository browser.