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 draw 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 Note: 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: `PetscDraw`, `PetscDrawOpenX()`, `PetscDrawOpenImage()`, `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 draw 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 Note: 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: `PetscDraw`, `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 draw 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 the name of the 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 130 The supported image types are .png, .gif, and .ppm (PETSc chooses the default in that order). 131 .vb 132 Support for .png images requires configure --with-libpng. 133 Support for .gif images requires configure --with-giflib. 134 Support for .jpg images requires configure --with-libjpeg. 135 Support for .ppm images is built-in. The PPM format has no compression (640x480 pixels ~ 900 KiB). 136 .ve 137 138 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()` 139 @*/ 140 PetscErrorCode PetscDrawSetSaveFinalImage(PetscDraw draw, const char filename[]) 141 { 142 char buf[PETSC_MAX_PATH_LEN]; 143 144 PetscFunctionBegin; 145 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 146 if (!filename || !filename[0]) { 147 if (!draw->savefilename) { 148 PetscCall(PetscObjectGetName((PetscObject)draw, &filename)); 149 } else { 150 PetscCall(PetscSNPrintf(buf, sizeof(buf), "%s%s", draw->savefilename, draw->saveimageext)); 151 filename = buf; 152 } 153 } 154 PetscCall(PetscFree(draw->savefinalfilename)); 155 PetscCall(PetscStrallocpy(filename, &draw->savefinalfilename)); 156 PetscFunctionReturn(0); 157 } 158 159 /*@ 160 PetscDrawSave - Saves a drawn image 161 162 Collective on draw 163 164 Input Parameters: 165 . draw - the drawing context 166 167 Level: advanced 168 169 Note: 170 this is not normally called by the user. 171 172 .seealso: `PetscDraw`, `PetscDrawSetSave()` 173 @*/ 174 PetscErrorCode PetscDrawSave(PetscDraw draw) 175 { 176 PetscInt saveindex; 177 char basename[PETSC_MAX_PATH_LEN]; 178 unsigned char palette[256][3]; 179 unsigned int w, h; 180 unsigned char *pixels = NULL; 181 PetscMPIInt rank; 182 183 PetscFunctionBegin; 184 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 185 if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(0); 186 if (draw->ops->save) { 187 PetscUseTypeMethod(draw, save); 188 goto finally; 189 } 190 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(0); 191 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank)); 192 193 saveindex = draw->savefilecount++; 194 195 if (rank == 0 && !saveindex) { 196 char path[PETSC_MAX_PATH_LEN]; 197 if (draw->savesinglefile) { 198 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->saveimageext)); 199 (void)remove(path); 200 } else { 201 PetscCall(PetscSNPrintf(path, sizeof(path), "%s", draw->savefilename)); 202 PetscCall(PetscRMTree(path)); 203 PetscCall(PetscMkdir(path)); 204 } 205 if (draw->savemovieext) { 206 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->savemovieext)); 207 (void)remove(path); 208 } 209 } 210 if (draw->savesinglefile) { 211 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s", draw->savefilename)); 212 } else { 213 char *basefilename; 214 215 PetscCall(PetscStrrchr(draw->savefilename, '/', (char **)&basefilename)); 216 if (basefilename != draw->savefilename) { 217 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s_%d", draw->savefilename, (int)saveindex)); 218 } else { 219 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s/%s_%d", draw->savefilename, draw->savefilename, (int)saveindex)); 220 } 221 } 222 223 /* this call is collective, only the first process gets the image data */ 224 PetscUseTypeMethod(draw, getimage, palette, &w, &h, &pixels); 225 /* only the first process handles the saving business */ 226 if (rank == 0) PetscCall(PetscDrawImageSave(basename, draw->saveimageext, palette, w, h, pixels)); 227 PetscCall(PetscFree(pixels)); 228 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw))); 229 230 finally: 231 #if defined(PETSC_HAVE_SAWS) 232 PetscCall(PetscDrawSave_SAWs(draw)); 233 #endif 234 PetscFunctionReturn(0); 235 } 236 237 /*@ 238 PetscDrawSaveMovie - Saves a movie from previously saved images 239 240 Collective on draw 241 242 Input Parameters: 243 . draw - the drawing context 244 245 Level: advanced 246 247 Notes: 248 This is not normally called by the user. 249 250 The ffmpeg utility must be in your path to make the movie. 251 252 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetSaveMovie()` 253 @*/ 254 PetscErrorCode PetscDrawSaveMovie(PetscDraw draw) 255 { 256 PetscMPIInt rank; 257 258 PetscFunctionBegin; 259 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 260 if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(0); 261 if (!draw->savefilename || !draw->savemovieext || draw->savesinglefile) PetscFunctionReturn(0); 262 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank)); 263 { 264 const char *fname = draw->savefilename; 265 const char *imext = draw->saveimageext; 266 const char *mvext = draw->savemovieext; 267 if (rank == 0) PetscCall(PetscDrawMovieSave(fname, draw->savefilecount, imext, draw->savemoviefps, mvext)); 268 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw))); 269 } 270 PetscFunctionReturn(0); 271 } 272 273 #if defined(PETSC_HAVE_SAWS) 274 #include <petscviewersaws.h> 275 /* 276 The PetscImageList object and functions are used to maintain a list of file images 277 that can be displayed by the SAWs webserver. 278 */ 279 typedef struct _P_PetscImageList *PetscImageList; 280 struct _P_PetscImageList { 281 PetscImageList next; 282 char *filename; 283 char *ext; 284 PetscInt count; 285 }; 286 287 static PetscImageList SAWs_images = NULL; 288 289 static PetscErrorCode PetscImageListDestroy(void) 290 { 291 PetscImageList image = SAWs_images; 292 293 PetscFunctionBegin; 294 while (image) { 295 PetscImageList next = image->next; 296 PetscCall(PetscFree(image->filename)); 297 PetscCall(PetscFree(image->ext)); 298 PetscCall(PetscFree(image)); 299 image = next; 300 } 301 PetscFunctionReturn(0); 302 } 303 304 static PetscErrorCode PetscImageListAdd(const char filename[], const char ext[], PetscInt count) 305 { 306 PetscImageList image, oimage = SAWs_images; 307 PetscBool flg; 308 309 PetscFunctionBegin; 310 if (oimage) { 311 PetscCall(PetscStrcmp(filename, oimage->filename, &flg)); 312 if (flg) { 313 oimage->count = count; 314 PetscFunctionReturn(0); 315 } 316 while (oimage->next) { 317 oimage = oimage->next; 318 PetscCall(PetscStrcmp(filename, oimage->filename, &flg)); 319 if (flg) { 320 oimage->count = count; 321 PetscFunctionReturn(0); 322 } 323 } 324 PetscCall(PetscNew(&image)); 325 oimage->next = image; 326 } else { 327 PetscCall(PetscRegisterFinalize(PetscImageListDestroy)); 328 PetscCall(PetscNew(&image)); 329 SAWs_images = image; 330 } 331 PetscCall(PetscStrallocpy(filename, &image->filename)); 332 PetscCall(PetscStrallocpy(ext, &image->ext)); 333 image->count = count; 334 PetscFunctionReturn(0); 335 } 336 337 static PetscErrorCode PetscDrawSave_SAWs(PetscDraw draw) 338 { 339 PetscImageList image; 340 char body[4096]; 341 size_t len = 0; 342 343 PetscFunctionBegin; 344 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(0); 345 PetscCall(PetscImageListAdd(draw->savefilename, draw->saveimageext, draw->savefilecount - 1)); 346 image = SAWs_images; 347 while (image) { 348 const char *name = image->filename; 349 const char *ext = image->ext; 350 if (draw->savesinglefile) { 351 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s%s\" alt=\"None\">", name, ext)); 352 } else { 353 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s/%s_%d%s\" alt=\"None\">", name, name, image->count, ext)); 354 } 355 PetscCall(PetscStrlen(body, &len)); 356 image = image->next; 357 } 358 PetscCall(PetscStrlcat(body, "<br>\n", sizeof(body))); 359 if (draw->savefilecount > 0) PetscCallSAWs(SAWs_Pop_Body, ("index.html", 1)); 360 PetscCallSAWs(SAWs_Push_Body, ("index.html", 1, body)); 361 PetscFunctionReturn(0); 362 } 363 364 #endif 365