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