1 #include <petsc/private/drawimpl.h> /*I "petscdraw.h" I*/
2
3 PETSC_EXTERN PetscErrorCode PetscDrawImageSave(const char[], const char[], unsigned char[][3], unsigned int, unsigned int, const unsigned char[]);
4 PETSC_EXTERN PetscErrorCode PetscDrawMovieSave(const char[], PetscInt, const char[], PetscInt, const char[]);
5 PETSC_EXTERN PetscErrorCode PetscDrawImageCheckFormat(const char *[]);
6 PETSC_EXTERN PetscErrorCode PetscDrawMovieCheckFormat(const char *[]);
7
8 #if defined(PETSC_HAVE_SAWS)
9 static PetscErrorCode PetscDrawSave_SAWs(PetscDraw);
10 #endif
11
12 /*@
13 PetscDrawSetSave - Saves images produced in a `PetscDraw` into a file
14
15 Collective
16
17 Input Parameters:
18 + draw - the graphics context
19 - filename - name of the file, if .ext then uses name of draw object plus .ext using .ext to determine the image type
20
21 Options Database Keys:
22 + -draw_save <filename> - filename could be name.ext or .ext (where .ext determines the type of graphics file to save, for example .png)
23 . -draw_save_final_image [optional filename] - saves the final image displayed in a window
24 - -draw_save_single_file - saves each new image in the same file, normally each new image is saved in a new file with filename/filename_%d.ext
25
26 Level: intermediate
27
28 Note:
29 You should call this BEFORE creating your image and calling `PetscDrawSave()`.
30 The supported image types are .png, .gif, .jpg, and .ppm (PETSc chooses the default in that order).
31 Support for .png images requires configure --with-libpng.
32 Support for .gif images requires configure --with-giflib.
33 Support for .jpg images requires configure --with-libjpeg.
34 Support for .ppm images is built-in. The PPM format has no compression (640x480 pixels ~ 900 KiB).
35
36 .seealso: `PetscDraw`, `PetscDrawOpenX()`, `PetscDrawOpenImage()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`, `PetscDrawSetSaveFinalImage()`
37 @*/
PetscDrawSetSave(PetscDraw draw,const char filename[])38 PetscErrorCode PetscDrawSetSave(PetscDraw draw, const char filename[])
39 {
40 const char *savename = NULL;
41 const char *imageext = NULL;
42 char buf[PETSC_MAX_PATH_LEN];
43
44 PetscFunctionBegin;
45 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
46 if (filename) PetscAssertPointer(filename, 2);
47
48 /* determine save filename and image extension */
49 if (filename && filename[0]) {
50 PetscCall(PetscStrchr(filename, '.', (char **)&imageext));
51 if (!imageext) savename = filename;
52 else if (imageext != filename) {
53 size_t l1 = 0, l2 = 0;
54 PetscCall(PetscStrlen(filename, &l1));
55 PetscCall(PetscStrlen(imageext, &l2));
56 PetscCall(PetscStrncpy(buf, filename, sizeof(buf)));
57 buf[l1 - l2 + 1] = '\0';
58 savename = buf;
59 }
60 }
61
62 if (!savename) PetscCall(PetscObjectGetName((PetscObject)draw, &savename));
63 PetscCall(PetscDrawImageCheckFormat(&imageext));
64
65 draw->savefilecount = 0;
66 PetscCall(PetscFree(draw->savefilename));
67 PetscCall(PetscFree(draw->saveimageext));
68 PetscCall(PetscStrallocpy(savename, &draw->savefilename));
69 PetscCall(PetscStrallocpy(imageext, &draw->saveimageext));
70
71 if (draw->savesinglefile) {
72 PetscCall(PetscInfo(NULL, "Will save image to file %s%s\n", draw->savefilename, draw->saveimageext));
73 } else {
74 PetscCall(PetscInfo(NULL, "Will save images to file %s/%s_%%d%s\n", draw->savefilename, draw->savefilename, draw->saveimageext));
75 }
76 PetscFunctionReturn(PETSC_SUCCESS);
77 }
78
79 /*@
80 PetscDrawSetSaveMovie - Saves a movie produced from a `PetscDraw` into a file
81
82 Collective
83
84 Input Parameters:
85 + draw - the graphics context
86 - movieext - optional extension defining the movie format
87
88 Options Database Key:
89 . -draw_save_movie <.ext> - saves a movie with extension .ext
90
91 Level: intermediate
92
93 Note:
94 You should call this AFTER calling `PetscDrawSetSave()` and BEFORE creating your image with `PetscDrawSave()`.
95 The ffmpeg utility must be in your path to make the movie.
96
97 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
98 @*/
PetscDrawSetSaveMovie(PetscDraw draw,const char movieext[])99 PetscErrorCode PetscDrawSetSaveMovie(PetscDraw draw, const char movieext[])
100 {
101 PetscFunctionBegin;
102 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
103 if (movieext) PetscAssertPointer(movieext, 2);
104
105 if (!draw->savefilename) PetscCall(PetscDrawSetSave(draw, ""));
106 PetscCall(PetscDrawMovieCheckFormat(&movieext));
107 PetscCall(PetscStrallocpy(movieext, &draw->savemovieext));
108 draw->savesinglefile = PETSC_FALSE; /* otherwise we cannot generate movies */
109
110 PetscCall(PetscInfo(NULL, "Will save movie to file %s%s\n", draw->savefilename, draw->savemovieext));
111 PetscFunctionReturn(PETSC_SUCCESS);
112 }
113
114 /*@
115 PetscDrawSetSaveFinalImage - Saves the final image produced in a `PetscDraw` into a file
116
117 Collective
118
119 Input Parameters:
120 + draw - the graphics context
121 - filename - name of the file, if NULL or empty uses name set with `PetscDrawSetSave()` or the name of the draw object
122
123 Options Database Key:
124 . -draw_save_final_image <filename> - filename could be name.ext or .ext (where .ext determines the type of graphics file to save, for example .png)
125
126 Level: intermediate
127
128 Notes:
129 You should call this BEFORE creating your image and calling `PetscDrawSave()`.
130
131 The supported image types are .png, .gif, and .ppm (PETSc chooses the default in that order).
132 .vb
133 Support for .png images requires configure --with-libpng.
134 Support for .gif images requires configure --with-giflib.
135 Support for .jpg images requires configure --with-libjpeg.
136 Support for .ppm images is built-in. The PPM format has no compression (640x480 pixels ~ 900 KiB).
137 .ve
138
139 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
140 @*/
PetscDrawSetSaveFinalImage(PetscDraw draw,const char filename[])141 PetscErrorCode PetscDrawSetSaveFinalImage(PetscDraw draw, const char filename[])
142 {
143 char buf[PETSC_MAX_PATH_LEN];
144
145 PetscFunctionBegin;
146 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
147 if (!filename || !filename[0]) {
148 if (!draw->savefilename) {
149 PetscCall(PetscObjectGetName((PetscObject)draw, &filename));
150 } else {
151 PetscCall(PetscSNPrintf(buf, sizeof(buf), "%s%s", draw->savefilename, draw->saveimageext));
152 filename = buf;
153 }
154 }
155 PetscCall(PetscFree(draw->savefinalfilename));
156 PetscCall(PetscStrallocpy(filename, &draw->savefinalfilename));
157 PetscFunctionReturn(PETSC_SUCCESS);
158 }
159
160 /*@
161 PetscDrawSave - Saves a drawn image
162
163 Collective
164
165 Input Parameter:
166 . draw - the drawing context
167
168 Level: advanced
169
170 Note:
171 this is not normally called by the user.
172
173 .seealso: `PetscDraw`, `PetscDrawSetSave()`
174 @*/
PetscDrawSave(PetscDraw draw)175 PetscErrorCode PetscDrawSave(PetscDraw draw)
176 {
177 PetscInt saveindex;
178 char basename[PETSC_MAX_PATH_LEN];
179 unsigned char palette[256][3];
180 unsigned int w, h;
181 unsigned char *pixels = NULL;
182 PetscMPIInt rank;
183
184 PetscFunctionBegin;
185 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
186 if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(PETSC_SUCCESS);
187 if (draw->ops->save) {
188 PetscUseTypeMethod(draw, save);
189 goto finally;
190 }
191 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(PETSC_SUCCESS);
192 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
193
194 saveindex = draw->savefilecount++;
195
196 if (rank == 0 && !saveindex) {
197 char path[PETSC_MAX_PATH_LEN];
198 if (draw->savesinglefile) {
199 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->saveimageext));
200 (void)remove(path);
201 } else {
202 PetscCall(PetscSNPrintf(path, sizeof(path), "%s", draw->savefilename));
203 PetscCall(PetscRMTree(path));
204 PetscCall(PetscMkdir(path));
205 }
206 if (draw->savemovieext) {
207 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->savemovieext));
208 (void)remove(path);
209 }
210 }
211 if (draw->savesinglefile) {
212 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s", draw->savefilename));
213 } else {
214 char *basefilename = NULL;
215
216 PetscCall(PetscStrrchr(draw->savefilename, '/', &basefilename));
217 if (basefilename != draw->savefilename) {
218 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s_%" PetscInt_FMT, draw->savefilename, saveindex));
219 } else {
220 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s/%s_%" PetscInt_FMT, draw->savefilename, draw->savefilename, saveindex));
221 }
222 }
223
224 /* this call is collective, only the first process gets the image data */
225 PetscUseTypeMethod(draw, getimage, palette, &w, &h, &pixels);
226 /* only the first process handles the saving business */
227 if (rank == 0) PetscCall(PetscDrawImageSave(basename, draw->saveimageext, palette, w, h, pixels));
228 PetscCall(PetscFree(pixels));
229 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
230
231 finally:
232 #if defined(PETSC_HAVE_SAWS)
233 PetscCall(PetscDrawSave_SAWs(draw));
234 #endif
235 PetscFunctionReturn(PETSC_SUCCESS);
236 }
237
238 /*@
239 PetscDrawSaveMovie - Saves a movie from previously saved images
240
241 Collective
242
243 Input Parameter:
244 . draw - the drawing context
245
246 Level: advanced
247
248 Notes:
249 This is not normally called by the user.
250
251 The ffmpeg utility must be in your path to make the movie.
252
253 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetSaveMovie()`
254 @*/
PetscDrawSaveMovie(PetscDraw draw)255 PetscErrorCode PetscDrawSaveMovie(PetscDraw draw)
256 {
257 PetscMPIInt rank;
258
259 PetscFunctionBegin;
260 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
261 if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(PETSC_SUCCESS);
262 if (!draw->savefilename || !draw->savemovieext || draw->savesinglefile) PetscFunctionReturn(PETSC_SUCCESS);
263 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
264 {
265 const char *fname = draw->savefilename;
266 const char *imext = draw->saveimageext;
267 const char *mvext = draw->savemovieext;
268 if (rank == 0) PetscCall(PetscDrawMovieSave(fname, draw->savefilecount, imext, draw->savemoviefps, mvext));
269 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
270 }
271 PetscFunctionReturn(PETSC_SUCCESS);
272 }
273
274 #if defined(PETSC_HAVE_SAWS)
275 #include <petscviewersaws.h>
276 /*
277 The PetscImageList object and functions are used to maintain a list of file images
278 that can be displayed by the SAWs webserver.
279 */
280 typedef struct _P_PetscImageList *PetscImageList;
281 struct _P_PetscImageList {
282 PetscImageList next;
283 char *filename;
284 char *ext;
285 PetscInt count;
286 };
287
288 static PetscImageList SAWs_images = NULL;
289
PetscImageListDestroy(void)290 static PetscErrorCode PetscImageListDestroy(void)
291 {
292 PetscImageList image = SAWs_images;
293
294 PetscFunctionBegin;
295 while (image) {
296 PetscImageList next = image->next;
297 PetscCall(PetscFree(image->filename));
298 PetscCall(PetscFree(image->ext));
299 PetscCall(PetscFree(image));
300 image = next;
301 }
302 PetscFunctionReturn(PETSC_SUCCESS);
303 }
304
PetscImageListAdd(const char filename[],const char ext[],PetscInt count)305 static PetscErrorCode PetscImageListAdd(const char filename[], const char ext[], PetscInt count)
306 {
307 PetscImageList image, oimage = SAWs_images;
308 PetscBool flg;
309
310 PetscFunctionBegin;
311 if (oimage) {
312 PetscCall(PetscStrcmp(filename, oimage->filename, &flg));
313 if (flg) {
314 oimage->count = count;
315 PetscFunctionReturn(PETSC_SUCCESS);
316 }
317 while (oimage->next) {
318 oimage = oimage->next;
319 PetscCall(PetscStrcmp(filename, oimage->filename, &flg));
320 if (flg) {
321 oimage->count = count;
322 PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 }
325 PetscCall(PetscNew(&image));
326 oimage->next = image;
327 } else {
328 PetscCall(PetscRegisterFinalize(PetscImageListDestroy));
329 PetscCall(PetscNew(&image));
330 SAWs_images = image;
331 }
332 PetscCall(PetscStrallocpy(filename, &image->filename));
333 PetscCall(PetscStrallocpy(ext, &image->ext));
334 image->count = count;
335 PetscFunctionReturn(PETSC_SUCCESS);
336 }
337
PetscDrawSave_SAWs(PetscDraw draw)338 static PetscErrorCode PetscDrawSave_SAWs(PetscDraw draw)
339 {
340 PetscImageList image;
341 char body[4096];
342 size_t len = 0;
343
344 PetscFunctionBegin;
345 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(PETSC_SUCCESS);
346 PetscCall(PetscImageListAdd(draw->savefilename, draw->saveimageext, draw->savefilecount - 1));
347 image = SAWs_images;
348 while (image) {
349 const char *name = image->filename;
350 const char *ext = image->ext;
351 if (draw->savesinglefile) {
352 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s%s\" alt=\"None\">", name, ext));
353 } else {
354 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s/%s_%d%s\" alt=\"None\">", name, name, image->count, ext));
355 }
356 PetscCall(PetscStrlen(body, &len));
357 image = image->next;
358 }
359 PetscCall(PetscStrlcat(body, "<br>\n", sizeof(body)));
360 if (draw->savefilecount > 0) PetscCallSAWs(SAWs_Pop_Body, ("index.html", 1));
361 PetscCallSAWs(SAWs_Push_Body, ("index.html", 1, body));
362 PetscFunctionReturn(PETSC_SUCCESS);
363 }
364
365 #endif
366