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