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