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