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