Actual source code: dsave.c
1: #include <petsc/private/drawimpl.h>
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 *[]);
8: #if PetscDefined(HAVE_SAWS)
9: static PetscErrorCode PetscDrawSave_SAWs(PetscDraw);
10: #endif
12: /*@
13: PetscDrawSetSave - Saves images produced in a `PetscDraw` into a file
15: Collective
17: Input Parameters:
18: + draw - the graphics context
19: - filename - name of the file, if `filename` is only an extension `.ext` then uses the name of draw object plus `.ext`. Uses the extension to determine the image type
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 [filename] - saves the final image displayed in a window
24: - -draw_save_single_file (true|false) - saves each new image in the same file, normally each new image is saved in a new file with filename/filename_%d.ext
26: Level: intermediate
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).
36: .seealso: `PetscDraw`, `PetscDrawOpenX()`, `PetscDrawOpenImage()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`, `PetscDrawSetSaveFinalImage()`
37: @*/
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];
44: PetscFunctionBegin;
46: if (filename) PetscAssertPointer(filename, 2);
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: }
62: if (!savename) PetscCall(PetscObjectGetName((PetscObject)draw, &savename));
63: PetscCall(PetscDrawImageCheckFormat(&imageext));
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));
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: }
79: /*@
80: PetscDrawSetSaveMovie - Saves a movie produced from a `PetscDraw` into a file
82: Collective
84: Input Parameters:
85: + draw - the graphics context
86: - movieext - optional extension defining the movie format
88: Options Database Key:
89: . -draw_save_movie [.ext] - saves a movie with extension `.ext`
91: Level: intermediate
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.
97: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
98: @*/
99: PetscErrorCode PetscDrawSetSaveMovie(PetscDraw draw, const char movieext[])
100: {
101: PetscFunctionBegin;
103: if (movieext) PetscAssertPointer(movieext, 2);
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 */
110: PetscCall(PetscInfo(NULL, "Will save movie to file %s%s\n", draw->savefilename, draw->savemovieext));
111: PetscFunctionReturn(PETSC_SUCCESS);
112: }
114: /*@
115: PetscDrawSetSaveFinalImage - Saves the final image produced in a `PetscDraw` into a file
117: Collective
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
123: Options Database Key:
124: . -draw_save_final_image [filename] - filename could be `name.ext` or `.ext` (`.ext` determines the type of graphics file to save, for example `.png`)
126: Level: intermediate
128: Notes:
129: You should call this BEFORE creating your image and calling `PetscDrawSave()`.
131: See `PetscDrawSetSave()` for details on supported formats
133: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
134: @*/
135: PetscErrorCode PetscDrawSetSaveFinalImage(PetscDraw draw, const char filename[])
136: {
137: char buf[PETSC_MAX_PATH_LEN];
139: PetscFunctionBegin;
141: if (!filename || !filename[0]) {
142: if (!draw->savefilename) {
143: PetscCall(PetscObjectGetName((PetscObject)draw, &filename));
144: } else {
145: PetscCall(PetscSNPrintf(buf, sizeof(buf), "%s%s", draw->savefilename, draw->saveimageext));
146: filename = buf;
147: }
148: }
149: PetscCall(PetscFree(draw->savefinalfilename));
150: PetscCall(PetscStrallocpy(filename, &draw->savefinalfilename));
151: PetscFunctionReturn(PETSC_SUCCESS);
152: }
154: /*@
155: PetscDrawSave - Saves a drawn image
157: Collective
159: Input Parameter:
160: . draw - the drawing context
162: Options Database Keys:
163: + -draw_save [filename] - `filename` could be `name.ext` or `.ext` (where `.ext` determines the type of graphics file to save, for example `.png`)
164: . -draw_save_final_image [filename] - saves the final image displayed in a window
165: - -draw_save_single_file (true|false) - saves each new image in the same file, normally each new image is saved in a new file with filename/filename_%d.ext
167: Level: advanced
169: Notes:
170: This is not normally called by the user.
172: See `PetscDrawSetSave()` for details on the possible image formats
174: .seealso: `PetscDraw`, `PetscDrawSetSave()`
175: @*/
176: PetscErrorCode PetscDrawSave(PetscDraw draw)
177: {
178: PetscInt saveindex;
179: char basename[PETSC_MAX_PATH_LEN];
180: unsigned char palette[256][3];
181: unsigned int w, h;
182: unsigned char *pixels = NULL;
183: PetscMPIInt rank;
185: PetscFunctionBegin;
187: if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(PETSC_SUCCESS);
188: if (draw->ops->save) {
189: PetscUseTypeMethod(draw, save);
190: goto finally;
191: }
192: if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(PETSC_SUCCESS);
193: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
195: saveindex = draw->savefilecount++;
197: if (rank == 0 && !saveindex) {
198: char path[PETSC_MAX_PATH_LEN];
199: if (draw->savesinglefile) {
200: PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->saveimageext));
201: (void)remove(path);
202: } else {
203: PetscCall(PetscSNPrintf(path, sizeof(path), "%s", draw->savefilename));
204: PetscCall(PetscRMTree(path));
205: PetscCall(PetscMkdir(path));
206: }
207: if (draw->savemovieext) {
208: PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->savemovieext));
209: (void)remove(path);
210: }
211: }
212: if (draw->savesinglefile) {
213: PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s", draw->savefilename));
214: } else {
215: char *basefilename = NULL;
217: PetscCall(PetscStrrchr(draw->savefilename, '/', &basefilename));
218: if (basefilename != draw->savefilename) {
219: PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s_%" PetscInt_FMT, draw->savefilename, saveindex));
220: } else {
221: PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s/%s_%" PetscInt_FMT, draw->savefilename, draw->savefilename, saveindex));
222: }
223: }
225: /* this call is collective, only the first process gets the image data */
226: PetscUseTypeMethod(draw, getimage, palette, &w, &h, &pixels);
227: /* only the first process handles the saving business */
228: if (rank == 0) PetscCall(PetscDrawImageSave(basename, draw->saveimageext, palette, w, h, pixels));
229: PetscCall(PetscFree(pixels));
230: PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
232: finally:
233: #if PetscDefined(HAVE_SAWS)
234: PetscCall(PetscDrawSave_SAWs(draw));
235: #endif
236: PetscFunctionReturn(PETSC_SUCCESS);
237: }
239: /*@
240: PetscDrawSaveMovie - Saves a movie from previously saved images
242: Collective
244: Input Parameter:
245: . draw - the drawing context
247: Level: advanced
249: Notes:
250: This is not normally called by the user.
252: The ffmpeg utility must be in your path to make the movie.
254: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetSaveMovie()`
255: @*/
256: PetscErrorCode PetscDrawSaveMovie(PetscDraw draw)
257: {
258: PetscMPIInt rank;
260: PetscFunctionBegin;
262: if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(PETSC_SUCCESS);
263: if (!draw->savefilename || !draw->savemovieext || draw->savesinglefile) PetscFunctionReturn(PETSC_SUCCESS);
264: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
265: {
266: const char *fname = draw->savefilename;
267: const char *imext = draw->saveimageext;
268: const char *mvext = draw->savemovieext;
269: if (rank == 0) PetscCall(PetscDrawMovieSave(fname, draw->savefilecount, imext, draw->savemoviefps, mvext));
270: PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
271: }
272: PetscFunctionReturn(PETSC_SUCCESS);
273: }
275: #if PetscDefined(HAVE_SAWS)
276: #include <petscviewersaws.h>
277: /*
278: The PetscImageList object and functions are used to maintain a list of file images
279: that can be displayed by the SAWs webserver.
280: */
281: typedef struct _P_PetscImageList *PetscImageList;
282: struct _P_PetscImageList {
283: PetscImageList next;
284: char *filename;
285: char *ext;
286: PetscInt count;
287: };
289: static PetscImageList SAWs_images = NULL;
291: static PetscErrorCode PetscImageListDestroy(void)
292: {
293: PetscImageList image = SAWs_images;
295: PetscFunctionBegin;
296: while (image) {
297: PetscImageList next = image->next;
298: PetscCall(PetscFree(image->filename));
299: PetscCall(PetscFree(image->ext));
300: PetscCall(PetscFree(image));
301: image = next;
302: }
303: PetscFunctionReturn(PETSC_SUCCESS);
304: }
306: static PetscErrorCode PetscImageListAdd(const char filename[], const char ext[], PetscInt count)
307: {
308: PetscImageList image, oimage = SAWs_images;
309: PetscBool flg;
311: PetscFunctionBegin;
312: if (oimage) {
313: PetscCall(PetscStrcmp(filename, oimage->filename, &flg));
314: if (flg) {
315: oimage->count = count;
316: PetscFunctionReturn(PETSC_SUCCESS);
317: }
318: while (oimage->next) {
319: oimage = oimage->next;
320: PetscCall(PetscStrcmp(filename, oimage->filename, &flg));
321: if (flg) {
322: oimage->count = count;
323: PetscFunctionReturn(PETSC_SUCCESS);
324: }
325: }
326: PetscCall(PetscNew(&image));
327: oimage->next = image;
328: } else {
329: PetscCall(PetscRegisterFinalize(PetscImageListDestroy));
330: PetscCall(PetscNew(&image));
331: SAWs_images = image;
332: }
333: PetscCall(PetscStrallocpy(filename, &image->filename));
334: PetscCall(PetscStrallocpy(ext, &image->ext));
335: image->count = count;
336: PetscFunctionReturn(PETSC_SUCCESS);
337: }
339: static PetscErrorCode PetscDrawSave_SAWs(PetscDraw draw)
340: {
341: PetscImageList image;
342: char body[4096];
343: size_t len = 0;
345: PetscFunctionBegin;
346: if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(PETSC_SUCCESS);
347: PetscCall(PetscImageListAdd(draw->savefilename, draw->saveimageext, draw->savefilecount - 1));
348: image = SAWs_images;
349: while (image) {
350: const char *name = image->filename;
351: const char *ext = image->ext;
352: if (draw->savesinglefile) {
353: PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s%s\" alt=\"None\">", name, ext));
354: } else {
355: PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s/%s_%d%s\" alt=\"None\">", name, name, image->count, ext));
356: }
357: PetscCall(PetscStrlen(body, &len));
358: image = image->next;
359: }
360: PetscCall(PetscStrlcat(body, "<br>\n", sizeof(body)));
361: if (draw->savefilecount > 0) PetscCallSAWs(SAWs_Pop_Body, ("index.html", 1));
362: PetscCallSAWs(SAWs_Push_Body, ("index.html", 1, body));
363: PetscFunctionReturn(PETSC_SUCCESS);
364: }
366: #endif