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