xref: /petsc/src/sys/classes/draw/impls/image/drawimage.h (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 #if !defined(_PETSCIMAGE_H)
2 #define _PETSCIMAGE_H
3 
4 #include <petscdraw.h>
5 
6 typedef struct _n_PetscImage *PetscImage;
7 typedef struct _n_PetscImage {
8   unsigned char *buffer;          /* raster buffer  */
9   int            w, h;            /* width, height  */
10   int            clip[4];         /* clip ranges    */
11   unsigned char  palette[256][3]; /* colormap       */
12 } _n_PetscImage;
13 
14 static inline void PetscImageSetClip(PetscImage img, int x, int y, int w, int h) {
15   img->clip[0] = PetscClipInterval(x, 0, img->w - 1); /* xmin   */
16   img->clip[1] = PetscClipInterval(y, 0, img->h - 1); /* ymin   */
17   img->clip[2] = PetscClipInterval(x + w, 0, img->w); /* xmax+1 */
18   img->clip[3] = PetscClipInterval(y + h, 0, img->h); /* ymax+1 */
19 }
20 
21 static inline void PetscImageClear(PetscImage img) {
22   int x, xs = img->clip[0], xe = img->clip[2];
23   int y, ys = img->clip[1], ye = img->clip[3];
24   for (y = ys; y < ye; y++)
25     for (x = xs; x < xe; x++) img->buffer[y * img->w + x] = 0;
26 }
27 
28 static inline void PetscImageDrawPixel(PetscImage img, int x, int y, int c) {
29   if (x < img->clip[0] || x >= img->clip[2]) return;
30   if (y < img->clip[1] || y >= img->clip[3]) return;
31   img->buffer[y * img->w + x] = (unsigned char)c;
32 }
33 
34 static inline void PetscImageDrawLine(PetscImage img, int x_1, int y_1, int x_2, int y_2, int c) {
35   if (y_1 == y_2) {
36     /* Horizontal line */
37     if (x_2 - x_1 < 0) {
38       int tmp = x_1;
39       x_1     = x_2;
40       x_2     = tmp;
41     }
42     while (x_1 <= x_2) PetscImageDrawPixel(img, x_1++, y_1, c);
43   } else if (x_1 == x_2) {
44     /* Vertical line */
45     if (y_2 - y_1 < 0) {
46       int tmp = y_1;
47       y_1     = y_2;
48       y_2     = tmp;
49     }
50     while (y_1 <= y_2) PetscImageDrawPixel(img, x_1, y_1++, c);
51   } else {
52     /* Bresenham's line drawing algorithm */
53     int dx = PetscAbs(x_2 - x_1), sx = (x_2 - x_1) >= 0 ? +1 : -1;
54     int dy = PetscAbs(y_2 - y_1), sy = (y_2 - y_1) >= 0 ? +1 : -1;
55     int error = (dx > dy ? dx : -dy) / 2, err;
56     while (1) {
57       PetscImageDrawPixel(img, x_1, y_1, c);
58       if (x_1 == x_2 && y_1 == y_2) break;
59       err = error;
60       if (err > -dx) {
61         error -= dy;
62         x_1 += sx;
63       }
64       if (err < +dy) {
65         error += dx;
66         y_1 += sy;
67       }
68     }
69   }
70 }
71 
72 static inline void PetscImageDrawRectangle(PetscImage img, int x, int y, int w, int h, int c) {
73   int xs = PetscMax(x, img->clip[0]), xe = PetscMin(x + w, img->clip[2]);
74   int ys = PetscMax(y, img->clip[1]), ye = PetscMin(y + h, img->clip[3]);
75   if (xs >= xe || ys >= ye) return;
76   for (y = ys; y < ye; y++)
77     for (x = xs; x < xe; x++) img->buffer[y * img->w + x] = (unsigned char)c;
78 }
79 
80 static inline void PetscImageDrawEllipse(PetscImage img, int xc, int yc, int w, int h, int c) {
81   /* Bresenham's circle/ellipse drawing algorithm */
82   int x, y, s, a2 = w * w, b2 = h * h;
83   for (x = 0, y = h, s = 2 * b2 + a2 * (1 - 2 * h); b2 * x <= a2 * y; x++) {
84     PetscImageDrawLine(img, xc + x, yc + y, xc - x, yc + y, c);
85     PetscImageDrawLine(img, xc + x, yc - y, xc - x, yc - y, c);
86     if (s >= 0) {
87       s += 4 * a2 * (1 - y);
88       y--;
89     }
90     s += b2 * ((4 * x) + 6);
91   }
92   for (x = w, y = 0, s = 2 * a2 + b2 * (1 - 2 * w); a2 * y <= b2 * x; y++) {
93     PetscImageDrawLine(img, xc + x, yc + y, xc - x, yc + y, c);
94     PetscImageDrawLine(img, xc + x, yc - y, xc - x, yc - y, c);
95     if (s >= 0) {
96       s += 4 * b2 * (1 - x);
97       x--;
98     }
99     s += a2 * ((4 * y) + 6);
100   }
101 }
102 
103 static inline void PetscImageDrawTriangle(PetscImage img, int x_1, int y_1, int t_1, int x_2, int y_2, int t_2, int x_3, int y_3, int t_3) {
104   const int SHIFT_VAL = 6;
105   const int xmin = img->clip[0], xmax = img->clip[2] - 1;
106   const int ymin = img->clip[1], ymax = img->clip[3] - 1;
107   float     rfrac, lfrac, one = 1;
108   float     R_y2_y1, R_y3_y1, R_y3_y2;
109   int       lc, rc = 0, lx, rx = 0, xx, y, c;
110   int       rc_lc, rx_lx, t2_t1, x2_x1, t3_t1, x3_x1, t3_t2, x3_x2;
111 
112   /* Is triangle ever visible in image? */
113   if (x_1 < xmin && x_2 < xmin && x_3 < xmin) return;
114   if (y_1 < ymin && y_2 < ymin && y_3 < ymin) return;
115   if (x_1 > xmax && x_2 > xmax && x_3 > xmax) return;
116   if (y_1 > ymax && y_2 > ymax && y_3 > ymax) return;
117 
118   t_1 = t_1 << SHIFT_VAL;
119   t_2 = t_2 << SHIFT_VAL;
120   t_3 = t_3 << SHIFT_VAL;
121 
122   /* Sort the vertices */
123 #define SWAP(a, b) \
124   do { \
125     int _tmp; \
126     _tmp = a; \
127     a    = b; \
128     b    = _tmp; \
129   } while (0)
130   if (y_1 > y_2) {
131     SWAP(x_1, x_2);
132     SWAP(y_1, y_2);
133     SWAP(t_1, t_2);
134   }
135   if (y_1 > y_3) {
136     SWAP(x_1, x_3);
137     SWAP(y_1, y_3);
138     SWAP(t_1, t_3);
139   }
140   if (y_2 > y_3) {
141     SWAP(x_2, x_3);
142     SWAP(y_2, y_3);
143     SWAP(t_2, t_3);
144   }
145 #undef SWAP
146 
147   /* This code is decidely non-optimal;
148    it is intended to be a start at an implementation */
149 
150   t2_t1   = t_2 - t_1;
151   x2_x1   = x_2 - x_1;
152   R_y2_y1 = (y_2 != y_1) ? one / (y_2 - y_1) : 0;
153   R_y3_y1 = (y_3 != y_1) ? one / (y_3 - y_1) : 0;
154   x3_x1   = x_3 - x_1;
155   t3_t1   = t_3 - t_1;
156 
157   for (y = y_1; y <= y_2; y++) {
158     /* Draw a line with the correct color from t1-t2 to t1-t3 */
159     /* Left color is (y-y1)/(y2-y1) * (t2-t1) + t1 */
160     lfrac = (y - y_1) * R_y2_y1;
161     lc    = (int)(lfrac * (t2_t1) + t_1);
162     lx    = (int)(lfrac * (x2_x1) + x_1);
163     /* Right color is (y-y1)/(y3-y1) * (t3-t1) + t1 */
164     rfrac = (y - y_1) * R_y3_y1;
165     rc    = (int)(rfrac * (t3_t1) + t_1);
166     rx    = (int)(rfrac * (x3_x1) + x_1);
167     /* Draw the line */
168     rc_lc = rc - lc;
169     rx_lx = rx - lx;
170     if (rx > lx) {
171       for (xx = lx; xx <= rx; xx++) {
172         c = (((xx - lx) * (rc_lc)) / (rx_lx) + lc) >> SHIFT_VAL;
173         PetscImageDrawPixel(img, xx, y, c);
174       }
175     } else if (rx < lx) {
176       for (xx = lx; xx >= rx; xx--) {
177         c = (((xx - lx) * (rc_lc)) / (rx_lx) + lc) >> SHIFT_VAL;
178         PetscImageDrawPixel(img, xx, y, c);
179       }
180     } else {
181       c = lc >> SHIFT_VAL;
182       PetscImageDrawPixel(img, lx, y, c);
183     }
184   }
185 
186   /* For simplicity,"move" t1 to the intersection of t1-t3 with the line y=y2.
187      We take advantage of the previous iteration. */
188   if (y_2 >= y_3) return;
189   if (y_1 < y_2) {
190     x_1   = rx;
191     y_1   = y_2;
192     t_1   = rc;
193     x3_x1 = x_3 - x_1;
194     t3_t1 = t_3 - t_1;
195   }
196   R_y3_y1 = (y_3 != y_1) ? one / (y_3 - y_1) : 0;
197   R_y3_y2 = (y_3 != y_2) ? one / (y_3 - y_2) : 0;
198   x3_x2   = x_3 - x_2;
199   t3_t2   = t_3 - t_2;
200 
201   for (y = y_2; y <= y_3; y++) {
202     /* Draw a line with the correct color from t2-t3 to t1-t3 */
203     /* Left color is (y-y1)/(y2-y1) * (t2-t1) + t1 */
204     lfrac = (y - y_2) * R_y3_y2;
205     lc    = (int)(lfrac * (t3_t2) + t_2);
206     lx    = (int)(lfrac * (x3_x2) + x_2);
207     /* Right color is (y-y1)/(y3-y1) * (t3-t1) + t1 */
208     rfrac = (y - y_1) * R_y3_y1;
209     rc    = (int)(rfrac * (t3_t1) + t_1);
210     rx    = (int)(rfrac * (x3_x1) + x_1);
211     /* Draw the line */
212     rc_lc = rc - lc;
213     rx_lx = rx - lx;
214     if (rx > lx) {
215       for (xx = lx; xx <= rx; xx++) {
216         c = (((xx - lx) * (rc_lc)) / (rx_lx) + lc) >> SHIFT_VAL;
217         PetscImageDrawPixel(img, xx, y, c);
218       }
219     } else if (rx < lx) {
220       for (xx = lx; xx >= rx; xx--) {
221         c = (((xx - lx) * (rc_lc)) / (rx_lx) + lc) >> SHIFT_VAL;
222         PetscImageDrawPixel(img, xx, y, c);
223       }
224     } else {
225       c = lc >> SHIFT_VAL;
226       PetscImageDrawPixel(img, lx, y, c);
227     }
228   }
229 }
230 
231 #define PetscImageFontWidth  6
232 #define PetscImageFontHeight 10
233 static const unsigned char PetscImageFontBitmap[128 - 32][10] = {
234   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*   */
235   {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00}, /* ! */
236   {0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
237   {0x00, 0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00}, /* # */
238   {0x00, 0x08, 0x1C, 0x28, 0x1C, 0x0A, 0x1C, 0x08, 0x00, 0x00}, /* $ */
239   {0x00, 0x12, 0x2A, 0x14, 0x08, 0x14, 0x2A, 0x24, 0x00, 0x00}, /* % */
240   {0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00}, /* & */
241   {0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
242   {0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00}, /* ( */
243   {0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00, 0x00}, /*) */
244   {0x00, 0x00, 0x22, 0x14, 0x3E, 0x14, 0x22, 0x00, 0x00, 0x00}, /* * */
245   {0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00}, /* + */
246   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x08, 0x10, 0x00}, /* , */
247   {0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00}, /* - */
248   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x08, 0x00}, /* . */
249   {0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00}, /* / */
250   {0x00, 0x08, 0x14, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00}, /* 0 */
251   {0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /* 1 */
252   {0x00, 0x1C, 0x22, 0x02, 0x0C, 0x10, 0x20, 0x3E, 0x00, 0x00}, /* 2 */
253   {0x00, 0x3E, 0x02, 0x04, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00}, /* 3 */
254   {0x00, 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, 0x00}, /* 4 */
255   {0x00, 0x3E, 0x20, 0x2C, 0x32, 0x02, 0x22, 0x1C, 0x00, 0x00}, /* 5 */
256   {0x00, 0x0C, 0x10, 0x20, 0x2C, 0x32, 0x22, 0x1C, 0x00, 0x00}, /* 6 */
257   {0x00, 0x3E, 0x02, 0x04, 0x04, 0x08, 0x10, 0x10, 0x00, 0x00}, /* 7 */
258   {0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00}, /* 8 */
259   {0x00, 0x1C, 0x22, 0x26, 0x1A, 0x02, 0x04, 0x18, 0x00, 0x00}, /* 9 */
260   {0x00, 0x00, 0x08, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x08, 0x00}, /* : */
261   {0x00, 0x00, 0x08, 0x1C, 0x08, 0x00, 0x0C, 0x08, 0x10, 0x00}, /* } */
262   {0x00, 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00}, /* < */
263   {0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, /* = */
264   {0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00}, /* > */
265   {0x00, 0x1C, 0x22, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00}, /* ? */
266   {0x00, 0x1C, 0x22, 0x26, 0x2A, 0x2C, 0x20, 0x1C, 0x00, 0x00}, /* @ */
267   {0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00}, /* A */
268   {0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00}, /* B */
269   {0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00}, /* C */
270   {0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00}, /* D */
271   {0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00}, /* E */
272   {0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00}, /* F */
273   {0x00, 0x1C, 0x22, 0x20, 0x20, 0x26, 0x22, 0x1C, 0x00, 0x00}, /* G */
274   {0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00}, /* H */
275   {0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00}, /* I */
276   {0x00, 0x0E, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, 0x00, 0x00}, /* J */
277   {0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00}, /* K */
278   {0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00}, /* L */
279   {0x00, 0x22, 0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00}, /* M */
280   {0x00, 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x00, 0x00}, /* N */
281   {0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00}, /* O */
282   {0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00}, /* P */
283   {0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x1C, 0x02, 0x00}, /* Q */
284   {0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00}, /* R */
285   {0x00, 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, 0x00}, /* S */
286   {0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, /* T */
287   {0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00}, /* U */
288   {0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00}, /* V */
289   {0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00}, /* W */
290   {0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00}, /* X */
291   {0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, /* Y */
292   {0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00}, /* Z */
293   {0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00}, /* [ */
294   {0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00}, /* \ */
295   {0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00, 0x00}, /* ] */
296   {0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ^ */
297   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00}, /* _ */
298   {0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
299   {0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00}, /* a */
300   {0x00, 0x20, 0x20, 0x2C, 0x32, 0x22, 0x32, 0x2C, 0x00, 0x00}, /* b */
301   {0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x22, 0x1C, 0x00, 0x00}, /* c */
302   {0x00, 0x02, 0x02, 0x1A, 0x26, 0x22, 0x26, 0x1A, 0x00, 0x00}, /* d */
303   {0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00}, /* e */
304   {0x00, 0x0C, 0x12, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x00, 0x00}, /* f */
305   {0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x22, 0x1C}, /* g */
306   {0x00, 0x20, 0x20, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00}, /* h */
307   {0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00}, /* i */
308   {0x00, 0x02, 0x00, 0x06, 0x02, 0x02, 0x02, 0x12, 0x12, 0x0C}, /* j */
309   {0x00, 0x20, 0x20, 0x22, 0x24, 0x38, 0x24, 0x22, 0x00, 0x00}, /* k */
310   {0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00}, /* l */
311   {0x00, 0x00, 0x00, 0x34, 0x2A, 0x2A, 0x2A, 0x22, 0x00, 0x00}, /* m */
312   {0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00}, /* n */
313   {0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00}, /* o */
314   {0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x32, 0x2C, 0x20, 0x20}, /* p */
315   {0x00, 0x00, 0x00, 0x1A, 0x26, 0x22, 0x26, 0x1A, 0x02, 0x02}, /* q */
316   {0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00}, /* r */
317   {0x00, 0x00, 0x00, 0x1C, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00}, /* s */
318   {0x00, 0x10, 0x10, 0x3C, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00}, /* t */
319   {0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00}, /* u */
320   {0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00}, /* v */
321   {0x00, 0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x14, 0x00, 0x00}, /* w */
322   {0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00}, /* x */
323   {0x00, 0x00, 0x00, 0x22, 0x22, 0x26, 0x1A, 0x02, 0x22, 0x1C}, /* y */
324   {0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00}, /* z */
325   {0x00, 0x06, 0x08, 0x04, 0x18, 0x04, 0x08, 0x06, 0x00, 0x00}, /* { */
326   {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, /* | */
327   {0x00, 0x18, 0x04, 0x08, 0x06, 0x08, 0x04, 0x18, 0x00, 0x00}, /* } */
328   {0x00, 0x12, 0x2A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ~ */
329   {0x00, 0x2A, 0x00, 0x22, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x00}, /* ASCII 127 */
330 };
331 
332 static inline void PetscImageDrawText(PetscImage img, int x, int y, int c, const char text[]) {
333   int i, j, k, tw = PetscImageFontWidth, th = PetscImageFontHeight;
334   for (i = 0; i < th; i++) {
335     for (k = 0; text[k]; k++) {
336       int chr = PetscClipInterval(text[k], 32, 127);
337       for (j = 0; j < tw; j++) {
338         if (PetscImageFontBitmap[chr - 32][i] & (1 << (tw - 1 - j))) PetscImageDrawPixel(img, x + j + k * tw, y + i - th, c);
339       }
340     }
341   }
342 }
343 
344 #endif
345