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