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