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