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 PetscCall(PetscStrchr(filename,'.',(char **)&imageext)); 51 if (!imageext) savename = filename; 52 else if (imageext != filename) { 53 size_t l1 = 0,l2 = 0; 54 PetscCall(PetscStrlen(filename,&l1)); 55 PetscCall(PetscStrlen(imageext,&l2)); 56 PetscCall(PetscStrncpy(buf,filename,l1-l2+1)); 57 savename = buf; 58 } 59 } 60 61 if (!savename) PetscCall(PetscObjectGetName((PetscObject)draw,&savename)); 62 PetscCall(PetscDrawImageCheckFormat(&imageext)); 63 64 draw->savefilecount = 0; 65 PetscCall(PetscFree(draw->savefilename)); 66 PetscCall(PetscFree(draw->saveimageext)); 67 PetscCall(PetscStrallocpy(savename,&draw->savefilename)); 68 PetscCall(PetscStrallocpy(imageext,&draw->saveimageext)); 69 70 if (draw->savesinglefile) { 71 PetscCall(PetscInfo(NULL,"Will save image to file %s%s\n",draw->savefilename,draw->saveimageext)); 72 } else { 73 PetscCall(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) PetscCall(PetscDrawSetSave(draw,"")); 105 PetscCall(PetscDrawMovieCheckFormat(&movieext)); 106 PetscCall(PetscStrallocpy(movieext,&draw->savemovieext)); 107 draw->savesinglefile = PETSC_FALSE; /* otherwise we cannot generage movies */ 108 109 PetscCall(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 PetscCall(PetscObjectGetName((PetscObject)draw,&filename)); 146 } else { 147 PetscCall(PetscSNPrintf(buf,sizeof(buf),"%s%s",draw->savefilename,draw->saveimageext)); 148 filename = buf; 149 } 150 } 151 PetscCall(PetscFree(draw->savefinalfilename)); 152 PetscCall(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) {PetscCall((*draw->ops->save)(draw)); goto finally;} 185 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(0); 186 PetscCallMPI(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 PetscCall(PetscSNPrintf(path,sizeof(path),"%s%s",draw->savefilename,draw->saveimageext)); 194 (void)remove(path); 195 } else { 196 PetscCall(PetscSNPrintf(path,sizeof(path),"%s",draw->savefilename)); 197 PetscCall(PetscRMTree(path)); 198 PetscCall(PetscMkdir(path)); 199 } 200 if (draw->savemovieext) { 201 PetscCall(PetscSNPrintf(path,sizeof(path),"%s%s",draw->savefilename,draw->savemovieext)); 202 (void)remove(path); 203 } 204 } 205 if (draw->savesinglefile) { 206 PetscCall(PetscSNPrintf(basename,sizeof(basename),"%s",draw->savefilename)); 207 } else { 208 char *basefilename; 209 210 PetscCall(PetscStrrchr(draw->savefilename, '/', (char **) &basefilename)); 211 if (basefilename != draw->savefilename) { 212 PetscCall(PetscSNPrintf(basename,sizeof(basename),"%s_%d",draw->savefilename,(int)saveindex)); 213 } else { 214 PetscCall(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 PetscCall((*draw->ops->getimage)(draw,palette,&w,&h,&pixels)); 220 /* only the first process handles the saving business */ 221 if (rank == 0) PetscCall(PetscDrawImageSave(basename,draw->saveimageext,palette,w,h,pixels)); 222 PetscCall(PetscFree(pixels)); 223 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw))); 224 225 finally: 226 #if defined(PETSC_HAVE_SAWS) 227 PetscCall(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 PetscCallMPI(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) PetscCall(PetscDrawMovieSave(fname,draw->savefilecount,imext,draw->savemoviefps,mvext)); 263 PetscCallMPI(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 PetscCall(PetscFree(image->filename)); 292 PetscCall(PetscFree(image->ext)); 293 PetscCall(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 PetscCall(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 PetscCall(PetscStrcmp(filename,oimage->filename,&flg)); 314 if (flg) { 315 oimage->count = count; 316 PetscFunctionReturn(0); 317 } 318 } 319 PetscCall(PetscNew(&image)); 320 oimage->next = image; 321 } else { 322 PetscCall(PetscRegisterFinalize(PetscImageListDestroy)); 323 PetscCall(PetscNew(&image)); 324 SAWs_images = image; 325 } 326 PetscCall(PetscStrallocpy(filename,&image->filename)); 327 PetscCall(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 PetscCall(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 PetscCall(PetscSNPrintf(body+len,4086-len,"<img src=\"%s%s\" alt=\"None\">",name,ext)); 347 } else { 348 PetscCall(PetscSNPrintf(body+len,4086-len,"<img src=\"%s/%s_%d%s\" alt=\"None\">",name,name,image->count,ext)); 349 } 350 PetscCall(PetscStrlen(body,&len)); 351 image = image->next; 352 } 353 PetscCall(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