xref: /petsc/src/sys/classes/draw/impls/image/drawimage.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1 #include <../src/sys/classes/draw/impls/image/drawimage.h> /*I  "petscdraw.h" I*/
2 #include <petsc/private/drawimpl.h>                        /*I  "petscdraw.h" I*/
3 
4 #if defined(PETSC_USE_DEBUG)
5   #define PetscDrawValidColor(color) PetscCheck((color) >= 0 && (color) < 256, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Color value %" PetscInt_FMT " out of range [0..255]", (PetscInt)(color))
6 #else
7   #define PetscDrawValidColor(color) \
8     do { \
9     } while (0)
10 #endif
11 
12 #define XTRANS(draw, img, x) ((int)(((img)->w - 1) * ((draw)->port_xl + ((((x) - (draw)->coor_xl) * ((draw)->port_xr - (draw)->port_xl)) / ((draw)->coor_xr - (draw)->coor_xl)))))
13 #define YTRANS(draw, img, y) (((img)->h - 1) - (int)(((img)->h - 1) * ((draw)->port_yl + ((((y) - (draw)->coor_yl) * ((draw)->port_yr - (draw)->port_yl)) / ((draw)->coor_yr - (draw)->coor_yl)))))
14 
15 #define ITRANS(draw, img, i) ((draw)->coor_xl + (((PetscReal)(i)) * ((draw)->coor_xr - (draw)->coor_xl) / ((img)->w - 1) - (draw)->port_xl) / ((draw)->port_xr - (draw)->port_xl))
16 #define JTRANS(draw, img, j) ((draw)->coor_yl + (((PetscReal)(j)) / ((img)->h - 1) + (draw)->port_yl - 1) * ((draw)->coor_yr - (draw)->coor_yl) / ((draw)->port_yl - (draw)->port_yr))
17 
18 static PetscErrorCode PetscDrawSetViewport_Image(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr)
19 {
20   PetscImage img = (PetscImage)draw->data;
21   PetscFunctionBegin;
22   {
23     int xmax = img->w - 1, ymax = img->h - 1;
24     int xa = (int)(xl * xmax), ya = ymax - (int)(yr * ymax);
25     int xb = (int)(xr * xmax), yb = ymax - (int)(yl * ymax);
26     PetscImageSetClip(img, xa, ya, xb + 1 - xa, yb + 1 - ya);
27   }
28   PetscFunctionReturn(0);
29 }
30 
31 /*
32 static PetscErrorCode PetscDrawSetCoordinates_Image(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr)
33 {
34   PetscFunctionBegin;
35   PetscFunctionReturn(0);
36 }*/
37 #define PetscDrawSetCoordinates_Image NULL
38 
39 static PetscErrorCode PetscDrawCoordinateToPixel_Image(PetscDraw draw, PetscReal x, PetscReal y, int *i, int *j)
40 {
41   PetscImage img = (PetscImage)draw->data;
42   PetscFunctionBegin;
43   if (i) *i = XTRANS(draw, img, x);
44   if (j) *j = YTRANS(draw, img, y);
45   PetscFunctionReturn(0);
46 }
47 
48 static PetscErrorCode PetscDrawPixelToCoordinate_Image(PetscDraw draw, int i, int j, PetscReal *x, PetscReal *y)
49 {
50   PetscImage img = (PetscImage)draw->data;
51   PetscFunctionBegin;
52   if (x) *x = ITRANS(draw, img, i);
53   if (y) *y = JTRANS(draw, img, j);
54   PetscFunctionReturn(0);
55 }
56 
57 /*
58 static PetscErrorCode PetscDrawPointSetSize_Image(PetscDraw draw,PetscReal width)
59 {
60   PetscFunctionBegin;
61   PetscFunctionReturn(0);
62 }*/
63 #define PetscDrawPointSetSize_Image NULL
64 
65 static PetscErrorCode PetscDrawPoint_Image(PetscDraw draw, PetscReal x, PetscReal y, int c)
66 {
67   PetscImage img = (PetscImage)draw->data;
68   PetscFunctionBegin;
69   PetscDrawValidColor(c);
70   {
71     int j, xx = XTRANS(draw, img, x);
72     int i, yy = YTRANS(draw, img, y);
73     for (i = -1; i <= 1; i++)
74       for (j = -1; j <= 1; j++) PetscImageDrawPixel(img, xx + j, yy + i, c);
75   }
76   PetscFunctionReturn(0);
77 }
78 
79 static PetscErrorCode PetscDrawPointPixel_Image(PetscDraw draw, int x, int y, int c)
80 {
81   PetscImage img = (PetscImage)draw->data;
82   PetscFunctionBegin;
83   PetscDrawValidColor(c);
84   {
85     PetscImageDrawPixel(img, x, y, c);
86   }
87   PetscFunctionReturn(0);
88 }
89 
90 /*
91 static PetscErrorCode PetscDrawLineSetWidth_Image(PetscDraw draw,PetscReal width)
92 {
93   PetscFunctionBegin;
94   PetscFunctionReturn(0);
95 }*/
96 #define PetscDrawLineSetWidth_Image NULL
97 
98 static PetscErrorCode PetscDrawLineGetWidth_Image(PetscDraw draw, PetscReal *width)
99 {
100   PetscImage img = (PetscImage)draw->data;
101   PetscFunctionBegin;
102   {
103     int lw = 1;
104     *width = lw * (draw->coor_xr - draw->coor_xl) / (img->w * (draw->port_xr - draw->port_xl));
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 static PetscErrorCode PetscDrawLine_Image(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c)
110 {
111   PetscImage img = (PetscImage)draw->data;
112   PetscFunctionBegin;
113   {
114     int x_1 = XTRANS(draw, img, xl), x_2 = XTRANS(draw, img, xr);
115     int y_1 = YTRANS(draw, img, yl), y_2 = YTRANS(draw, img, yr);
116     PetscImageDrawLine(img, x_1, y_1, x_2, y_2, c);
117   }
118   PetscFunctionReturn(0);
119 }
120 
121 static PetscErrorCode PetscDrawArrow_Image(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c)
122 {
123   PetscImage img = (PetscImage)draw->data;
124   PetscFunctionBegin;
125   PetscDrawValidColor(c);
126   {
127     int x_1 = XTRANS(draw, img, xl), x_2 = XTRANS(draw, img, xr);
128     int y_1 = YTRANS(draw, img, yl), y_2 = YTRANS(draw, img, yr);
129     if (x_1 == x_2 && y_1 == y_2) PetscFunctionReturn(0);
130     PetscImageDrawLine(img, x_1, y_1, x_2, y_2, c);
131     if (x_1 == x_2 && PetscAbs(y_1 - y_2) > 7) {
132       if (y_2 > y_1) {
133         PetscImageDrawLine(img, x_2, y_2, x_2 - 3, y_2 - 3, c);
134         PetscImageDrawLine(img, x_2, y_2, x_2 + 3, y_2 - 3, c);
135       } else {
136         PetscImageDrawLine(img, x_2, y_2, x_2 - 3, y_2 + 3, c);
137         PetscImageDrawLine(img, x_2, y_2, x_2 + 3, y_2 + 3, c);
138       }
139     }
140     if (y_1 == y_2 && PetscAbs(x_1 - x_2) > 7) {
141       if (x_2 > x_1) {
142         PetscImageDrawLine(img, x_2 - 3, y_2 - 3, x_2, y_2, c);
143         PetscImageDrawLine(img, x_2 - 3, y_2 + 3, x_2, y_2, c);
144       } else {
145         PetscImageDrawLine(img, x_2, y_2, x_2 + 3, y_2 - 3, c);
146         PetscImageDrawLine(img, x_2, y_2, x_2 + 3, y_2 + 3, c);
147       }
148     }
149   }
150   PetscFunctionReturn(0);
151 }
152 
153 static PetscErrorCode PetscDrawRectangle_Image(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4)
154 {
155   PetscImage img = (PetscImage)draw->data;
156   PetscFunctionBegin;
157   PetscDrawValidColor(c1);
158   PetscDrawValidColor(c2);
159   PetscDrawValidColor(c3);
160   PetscDrawValidColor(c4);
161   {
162     int x = XTRANS(draw, img, xl), w = XTRANS(draw, img, xr) + 1 - x;
163     int y = YTRANS(draw, img, yr), h = YTRANS(draw, img, yl) + 1 - y;
164     int c = (c1 + c2 + c3 + c4) / 4;
165     PetscImageDrawRectangle(img, x, y, w, h, c);
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 static PetscErrorCode PetscDrawEllipse_Image(PetscDraw draw, PetscReal x, PetscReal y, PetscReal a, PetscReal b, int c)
171 {
172   PetscImage img = (PetscImage)draw->data;
173   PetscFunctionBegin;
174   PetscDrawValidColor(c);
175   a = PetscAbsReal(a);
176   b = PetscAbsReal(b);
177   {
178     int xc = XTRANS(draw, img, x), w = XTRANS(draw, img, x + a / 2) + 0 - xc;
179     int yc = YTRANS(draw, img, y), h = YTRANS(draw, img, y - b / 2) + 0 - yc;
180     if (PetscAbsReal(a - b) <= 0) w = h = PetscMin(w, h); /* workaround truncation errors */
181     PetscImageDrawEllipse(img, xc, yc, w, h, c);
182   }
183   PetscFunctionReturn(0);
184 }
185 
186 static PetscErrorCode PetscDrawTriangle_Image(PetscDraw draw, PetscReal X_1, PetscReal Y_1, PetscReal X_2, PetscReal Y_2, PetscReal X_3, PetscReal Y_3, int c1, int c2, int c3)
187 {
188   PetscImage img = (PetscImage)draw->data;
189   PetscFunctionBegin;
190   PetscDrawValidColor(c1);
191   PetscDrawValidColor(c2);
192   PetscDrawValidColor(c3);
193   {
194     int x_1 = XTRANS(draw, img, X_1), x_2 = XTRANS(draw, img, X_2), x_3 = XTRANS(draw, img, X_3);
195     int y_1 = YTRANS(draw, img, Y_1), y_2 = YTRANS(draw, img, Y_2), y_3 = YTRANS(draw, img, Y_3);
196     PetscImageDrawTriangle(img, x_1, y_1, c1, x_2, y_2, c2, x_3, y_3, c3);
197   }
198   PetscFunctionReturn(0);
199 }
200 
201 /*
202 static PetscErrorCode PetscDrawStringSetSize_Image(PetscDraw draw,PetscReal w,PetscReal h)
203 {
204   PetscFunctionBegin;
205   PetscFunctionReturn(0);
206 }*/
207 #define PetscDrawStringSetSize_Image NULL
208 
209 static PetscErrorCode PetscDrawStringGetSize_Image(PetscDraw draw, PetscReal *w, PetscReal *h)
210 {
211   PetscImage img = (PetscImage)draw->data;
212   PetscFunctionBegin;
213   {
214     int tw = PetscImageFontWidth;
215     int th = PetscImageFontHeight;
216     if (w) *w = tw * (draw->coor_xr - draw->coor_xl) / (img->w * (draw->port_xr - draw->port_xl));
217     if (h) *h = th * (draw->coor_yr - draw->coor_yl) / (img->h * (draw->port_yr - draw->port_yl));
218   }
219   PetscFunctionReturn(0);
220 }
221 
222 static PetscErrorCode PetscDrawString_Image(PetscDraw draw, PetscReal x, PetscReal y, int c, const char text[])
223 {
224   PetscImage img = (PetscImage)draw->data;
225   PetscToken token;
226   char      *subtext;
227   PetscFunctionBegin;
228   PetscDrawValidColor(c);
229   {
230     int xx = XTRANS(draw, img, x);
231     int yy = YTRANS(draw, img, y);
232     PetscCall(PetscTokenCreate(text, '\n', &token));
233     PetscCall(PetscTokenFind(token, &subtext));
234     while (subtext) {
235       PetscImageDrawText(img, xx, yy, c, subtext);
236       yy += PetscImageFontHeight;
237       PetscCall(PetscTokenFind(token, &subtext));
238     }
239     PetscCall(PetscTokenDestroy(&token));
240   }
241   PetscFunctionReturn(0);
242 }
243 
244 static PetscErrorCode PetscDrawStringVertical_Image(PetscDraw draw, PetscReal x, PetscReal y, int c, const char text[])
245 {
246   PetscImage img = (PetscImage)draw->data;
247   PetscFunctionBegin;
248   PetscDrawValidColor(c);
249   {
250     char chr[2] = {0, 0};
251     int  xx     = XTRANS(draw, img, x);
252     int  yy     = YTRANS(draw, img, y);
253     int  offset = PetscImageFontHeight;
254     while ((chr[0] = *text++)) {
255       PetscImageDrawText(img, xx, yy + offset, c, chr);
256       yy += PetscImageFontHeight;
257     }
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 /*
263 static PetscErrorCode PetscDrawStringBoxed_Image(PetscDraw draw,PetscReal sxl,PetscReal syl,int sc,int bc,const char text[],PetscReal *w,PetscReal *h)
264 {
265   PetscFunctionBegin;
266   if (w) *w = 0;
267   if (h) *h = 0;
268   PetscFunctionReturn(0);
269 */
270 #define PetscDrawStringBoxed_Image NULL
271 
272 /*
273 static PetscErrorCode PetscDrawFlush_Image(PetscDraw draw)
274 {
275   PetscFunctionBegin;
276   PetscFunctionReturn(0);
277 }*/
278 #define PetscDrawFlush_Image NULL
279 
280 static PetscErrorCode PetscDrawClear_Image(PetscDraw draw)
281 {
282   PetscImage img = (PetscImage)draw->data;
283   PetscFunctionBegin;
284   {
285     PetscImageClear(img);
286   }
287   PetscFunctionReturn(0);
288 }
289 
290 /*
291 static PetscErrorCode PetscDrawSetDoubleBuffer_Image(PetscDraw draw)
292 {
293   PetscFunctionBegin;
294   PetscFunctionReturn(0);
295 }*/
296 #define PetscDrawSetDoubleBuffer_Image NULL
297 
298 static PetscErrorCode PetscDrawGetPopup_Image(PetscDraw draw, PetscDraw *popup)
299 {
300   PetscBool flg = PETSC_FALSE;
301 
302   PetscFunctionBegin;
303   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_popup", &flg, NULL));
304   if (!flg) {
305     *popup = NULL;
306     PetscFunctionReturn(0);
307   }
308   PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw), NULL, NULL, 0, 0, 220, 220, popup));
309   PetscCall(PetscDrawSetType(*popup, PETSC_DRAW_IMAGE));
310   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*popup, "popup_"));
311   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*popup, ((PetscObject)draw)->prefix));
312   draw->popup = *popup;
313   PetscFunctionReturn(0);
314 }
315 
316 /*
317 static PetscErrorCode PetscDrawSetTitle_Image(PetscDraw draw,const char title[])
318 {
319   PetscFunctionBegin;
320   PetscFunctionReturn(0);
321 }*/
322 #define PetscDrawSetTitle_Image NULL
323 
324 /*
325 static PetscErrorCode PetscDrawCheckResizedWindow_Image(PetscDraw draw)
326 {
327   PetscFunctionBegin;
328   PetscFunctionReturn(0);
329 }*/
330 #define PetscDrawCheckResizedWindow_Image NULL
331 
332 static PetscErrorCode PetscDrawResizeWindow_Image(PetscDraw draw, int w, int h)
333 {
334   PetscImage img = (PetscImage)draw->data;
335 
336   PetscFunctionBegin;
337   if (w == img->w && h == img->h) PetscFunctionReturn(0);
338   PetscCall(PetscFree(img->buffer));
339 
340   img->w = w;
341   img->h = h;
342   PetscCall(PetscCalloc1((size_t)(img->w * img->h), &img->buffer));
343   PetscCall(PetscDrawSetViewport_Image(draw, draw->port_xl, draw->port_yl, draw->port_xr, draw->port_yr));
344   PetscFunctionReturn(0);
345 }
346 
347 static PetscErrorCode PetscDrawDestroy_Image(PetscDraw draw)
348 {
349   PetscImage img = (PetscImage)draw->data;
350 
351   PetscFunctionBegin;
352   PetscCall(PetscDrawDestroy(&draw->popup));
353   PetscCall(PetscFree(img->buffer));
354   PetscCall(PetscFree(draw->data));
355   PetscFunctionReturn(0);
356 }
357 
358 /*
359 static PetscErrorCode PetscDrawView_Image(PetscDraw draw,PetscViewer viewer)
360 {
361   PetscFunctionBegin;
362   PetscFunctionReturn(0);
363 }*/
364 #define PetscDrawView_Image NULL
365 
366 /*
367 static PetscErrorCode PetscDrawGetMouseButton_Image(PetscDraw draw,PetscDrawButton *button,PetscReal *x_user,PetscReal *y_user,PetscReal *x_phys,PetscReal *y_phys)
368 {
369   PetscFunctionBegin;
370   *button = PETSC_BUTTON_NONE;
371   if (x_user) *x_user = 0;
372   if (y_user) *y_user = 0;
373   if (x_phys) *x_phys = 0;
374   if (y_phys) *y_phys = 0;
375   PetscFunctionReturn(0);
376 }*/
377 #define PetscDrawGetMouseButton_Image NULL
378 
379 /*
380 static PetscErrorCode PetscDrawPause_Image(PetscDraw draw)
381 {
382   PetscFunctionBegin;
383   PetscFunctionReturn(0);
384 }*/
385 #define PetscDrawPause_Image NULL
386 
387 /*
388 static PetscErrorCode PetscDrawBeginPage_Image(PetscDraw draw)
389 {
390   PetscFunctionBegin;
391   PetscFunctionReturn(0);
392 }*/
393 #define PetscDrawBeginPage_Image NULL
394 
395 /*
396 static PetscErrorCode PetscDrawEndPage_Image(PetscDraw draw)
397 {
398   PetscFunctionBegin;
399   PetscFunctionReturn(0);
400 }*/
401 #define PetscDrawEndPage_Image NULL
402 
403 static PetscErrorCode PetscDrawGetSingleton_Image(PetscDraw draw, PetscDraw *sdraw)
404 {
405   PetscImage pimg = (PetscImage)draw->data;
406   PetscImage simg;
407 
408   PetscFunctionBegin;
409   PetscCall(PetscDrawCreate(PETSC_COMM_SELF, NULL, NULL, 0, 0, draw->w, draw->h, sdraw));
410   PetscCall(PetscDrawSetType(*sdraw, PETSC_DRAW_IMAGE));
411   (*sdraw)->ops->resizewindow = NULL;
412   simg                        = (PetscImage)(*sdraw)->data;
413   PetscCall(PetscArraycpy(simg->buffer, pimg->buffer, pimg->w * pimg->h));
414   PetscFunctionReturn(0);
415 }
416 
417 static PetscErrorCode PetscDrawRestoreSingleton_Image(PetscDraw draw, PetscDraw *sdraw)
418 {
419   PetscImage pimg = (PetscImage)draw->data;
420   PetscImage simg = (PetscImage)(*sdraw)->data;
421 
422   PetscFunctionBegin;
423   PetscCall(PetscArraycpy(pimg->buffer, simg->buffer, pimg->w * pimg->h));
424   PetscCall(PetscDrawDestroy(sdraw));
425   PetscFunctionReturn(0);
426 }
427 
428 /*
429 static PetscErrorCode PetscDrawSave_Image(PetscDraw draw)
430 {
431   PetscFunctionBegin;
432   PetscFunctionReturn(0);
433 }*/
434 #define PetscDrawSave_Image NULL
435 
436 static PetscErrorCode PetscDrawGetImage_Image(PetscDraw draw, unsigned char palette[256][3], unsigned int *w, unsigned int *h, unsigned char *pixels[])
437 {
438   PetscImage     img    = (PetscImage)draw->data;
439   unsigned char *buffer = NULL;
440   PetscMPIInt    rank, size;
441 
442   PetscFunctionBegin;
443   if (w) *w = (unsigned int)img->w;
444   if (h) *h = (unsigned int)img->h;
445   if (pixels) *pixels = NULL;
446   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
447   if (rank == 0) {
448     PetscCall(PetscMemcpy(palette, img->palette, sizeof(img->palette)));
449     PetscCall(PetscMalloc1((size_t)(img->w * img->h), &buffer));
450     if (pixels) *pixels = buffer;
451   }
452   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)draw), &size));
453   if (size == 1) {
454     PetscCall(PetscArraycpy(buffer, img->buffer, img->w * img->h));
455   } else {
456     PetscCallMPI(MPI_Reduce(img->buffer, buffer, img->w * img->h, MPI_UNSIGNED_CHAR, MPI_MAX, 0, PetscObjectComm((PetscObject)draw)));
457   }
458   PetscFunctionReturn(0);
459 }
460 
461 static struct _PetscDrawOps DvOps = {PetscDrawSetDoubleBuffer_Image, PetscDrawFlush_Image, PetscDrawLine_Image, PetscDrawLineSetWidth_Image, PetscDrawLineGetWidth_Image, PetscDrawPoint_Image, PetscDrawPointSetSize_Image, PetscDrawString_Image, PetscDrawStringVertical_Image, PetscDrawStringSetSize_Image, PetscDrawStringGetSize_Image, PetscDrawSetViewport_Image, PetscDrawClear_Image, PetscDrawRectangle_Image, PetscDrawTriangle_Image, PetscDrawEllipse_Image, PetscDrawGetMouseButton_Image, PetscDrawPause_Image, PetscDrawBeginPage_Image, PetscDrawEndPage_Image, PetscDrawGetPopup_Image, PetscDrawSetTitle_Image, PetscDrawCheckResizedWindow_Image, PetscDrawResizeWindow_Image, PetscDrawDestroy_Image, PetscDrawView_Image, PetscDrawGetSingleton_Image, PetscDrawRestoreSingleton_Image, PetscDrawSave_Image, PetscDrawGetImage_Image, PetscDrawSetCoordinates_Image, PetscDrawArrow_Image, PetscDrawCoordinateToPixel_Image, PetscDrawPixelToCoordinate_Image, PetscDrawPointPixel_Image, PetscDrawStringBoxed_Image};
462 
463 static const unsigned char BasicColors[PETSC_DRAW_BASIC_COLORS][3] = {
464   {255, 255, 255}, /* white */
465   {0,   0,   0  }, /* black */
466   {255, 0,   0  }, /* red */
467   {0,   255, 0  }, /* green */
468   {0,   255, 255}, /* cyan */
469   {0,   0,   255}, /* blue */
470   {255, 0,   255}, /* magenta */
471   {127, 255, 212}, /* aquamarine */
472   {34,  139, 34 }, /* forestgreen */
473   {255, 165, 0  }, /* orange */
474   {238, 130, 238}, /* violet */
475   {165, 42,  42 }, /* brown */
476   {255, 192, 203}, /* pink */
477   {255, 127, 80 }, /* coral */
478   {190, 190, 190}, /* gray */
479   {255, 255, 0  }, /* yellow */
480   {255, 215, 0  }, /* gold */
481   {255, 182, 193}, /* lightpink */
482   {72,  209, 204}, /* mediumturquoise */
483   {240, 230, 140}, /* khaki */
484   {105, 105, 105}, /* dimgray */
485   {54,  205, 50 }, /* yellowgreen */
486   {135, 206, 235}, /* skyblue */
487   {0,   100, 0  }, /* darkgreen */
488   {0,   0,   128}, /* navyblue */
489   {244, 164, 96 }, /* sandybrown */
490   {95,  158, 160}, /* cadetblue */
491   {176, 224, 230}, /* powderblue */
492   {255, 20,  147}, /* deeppink */
493   {216, 191, 216}, /* thistle */
494   {50,  205, 50 }, /* limegreen */
495   {255, 240, 245}, /* lavenderblush */
496   {221, 160, 221}, /* plum */
497 };
498 
499 /*MC
500    PETSC_DRAW_IMAGE - PETSc graphics device that uses a raster buffer
501 
502    Options Database Keys:
503 .  -draw_size w,h - size of image in pixels
504 
505    Level: beginner
506 
507 .seealso: `PetscDrawOpenImage()`, `PetscDrawSetFromOptions()`
508 M*/
509 PETSC_EXTERN PetscErrorCode PetscDrawCreate_Image(PetscDraw);
510 
511 PETSC_EXTERN PetscErrorCode PetscDrawCreate_Image(PetscDraw draw)
512 {
513   PetscImage img;
514   int        w = draw->w, h = draw->h;
515   PetscInt   size[2], nsize = 2;
516   PetscBool  set;
517 
518   PetscFunctionBegin;
519   draw->pause   = 0;
520   draw->coor_xl = 0;
521   draw->coor_xr = 1;
522   draw->coor_yl = 0;
523   draw->coor_yr = 1;
524   draw->port_xl = 0;
525   draw->port_xr = 1;
526   draw->port_yl = 0;
527   draw->port_yr = 1;
528 
529   size[0] = w;
530   if (size[0] < 1) size[0] = 300;
531   size[1] = h;
532   if (size[1] < 1) size[1] = size[0];
533   PetscCall(PetscOptionsGetIntArray(((PetscObject)draw)->options, ((PetscObject)draw)->prefix, "-draw_size", size, &nsize, &set));
534   if (set && nsize == 1) size[1] = size[0];
535   if (size[0] < 1) size[0] = 300;
536   if (size[1] < 1) size[1] = size[0];
537   draw->w = w = size[0];
538   draw->x     = 0;
539   draw->h = h = size[1];
540   draw->x     = 0;
541 
542   PetscCall(PetscNew(&img));
543   PetscCall(PetscMemcpy(draw->ops, &DvOps, sizeof(DvOps)));
544   draw->data = (void *)img;
545 
546   img->w = w;
547   img->h = h;
548   PetscCall(PetscCalloc1((size_t)(img->w * img->h), &img->buffer));
549   PetscImageSetClip(img, 0, 0, img->w, img->h);
550   {
551     int           i, k, ncolors = 256 - PETSC_DRAW_BASIC_COLORS;
552     unsigned char R[256 - PETSC_DRAW_BASIC_COLORS];
553     unsigned char G[256 - PETSC_DRAW_BASIC_COLORS];
554     unsigned char B[256 - PETSC_DRAW_BASIC_COLORS];
555     PetscCall(PetscDrawUtilitySetCmap(NULL, ncolors, R, G, B));
556     for (k = 0; k < PETSC_DRAW_BASIC_COLORS; k++) {
557       img->palette[k][0] = BasicColors[k][0];
558       img->palette[k][1] = BasicColors[k][1];
559       img->palette[k][2] = BasicColors[k][2];
560     }
561     for (i = 0; i < ncolors; i++, k++) {
562       img->palette[k][0] = R[i];
563       img->palette[k][1] = G[i];
564       img->palette[k][2] = B[i];
565     }
566   }
567 
568   if (!draw->savefilename) PetscCall(PetscDrawSetSave(draw, draw->title));
569   PetscFunctionReturn(0);
570 }
571 
572 /*@C
573    PetscDrawOpenImage - Opens an image for use with the `PetscDraw` routines.
574 
575    Collective
576 
577    Input Parameters:
578 +  comm - the communicator that will share image
579 -  filename - optional name of the file where the image will be stored
580 -  w, h - the image width and height in pixels
581 
582    Output Parameters:
583 .  draw - the drawing context.
584 
585    Level: beginner
586 
587 .seealso: `PetscDraw`, `PETSC_DRAW_IMAGE`, `PETSC_DRAW_X`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
588 @*/
589 PetscErrorCode PetscDrawOpenImage(MPI_Comm comm, const char filename[], int w, int h, PetscDraw *draw)
590 {
591   PetscFunctionBegin;
592   PetscCall(PetscDrawCreate(comm, NULL, NULL, 0, 0, w, h, draw));
593   PetscCall(PetscDrawSetType(*draw, PETSC_DRAW_IMAGE));
594   PetscCall(PetscDrawSetSave(*draw, filename));
595   PetscFunctionReturn(0);
596 }
597