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 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 draw 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 Note: 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: `PetscDraw`, `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 draw 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 the name of the 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 128 The supported image types are .png, .gif, and .ppm (PETSc chooses the default in that order). 129 .vb 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 .ve 135 136 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()` 137 @*/ 138 PetscErrorCode PetscDrawSetSaveFinalImage(PetscDraw draw, const char filename[]) { 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 draw 160 161 Input Parameters: 162 . draw - the drawing context 163 164 Level: advanced 165 166 Note: 167 this is not normally called by the user. 168 169 .seealso: `PetscDraw`, `PetscDrawSetSave()` 170 @*/ 171 PetscErrorCode PetscDrawSave(PetscDraw draw) { 172 PetscInt saveindex; 173 char basename[PETSC_MAX_PATH_LEN]; 174 unsigned char palette[256][3]; 175 unsigned int w, h; 176 unsigned char *pixels = NULL; 177 PetscMPIInt rank; 178 179 PetscFunctionBegin; 180 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 181 if (!draw->ops->save && !draw->ops->getimage) PetscFunctionReturn(0); 182 if (draw->ops->save) { 183 PetscUseTypeMethod(draw, save); 184 goto finally; 185 } 186 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(0); 187 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank)); 188 189 saveindex = draw->savefilecount++; 190 191 if (rank == 0 && !saveindex) { 192 char path[PETSC_MAX_PATH_LEN]; 193 if (draw->savesinglefile) { 194 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->saveimageext)); 195 (void)remove(path); 196 } else { 197 PetscCall(PetscSNPrintf(path, sizeof(path), "%s", draw->savefilename)); 198 PetscCall(PetscRMTree(path)); 199 PetscCall(PetscMkdir(path)); 200 } 201 if (draw->savemovieext) { 202 PetscCall(PetscSNPrintf(path, sizeof(path), "%s%s", draw->savefilename, draw->savemovieext)); 203 (void)remove(path); 204 } 205 } 206 if (draw->savesinglefile) { 207 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s", draw->savefilename)); 208 } else { 209 char *basefilename; 210 211 PetscCall(PetscStrrchr(draw->savefilename, '/', (char **)&basefilename)); 212 if (basefilename != draw->savefilename) { 213 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s_%d", draw->savefilename, (int)saveindex)); 214 } else { 215 PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s/%s_%d", draw->savefilename, draw->savefilename, (int)saveindex)); 216 } 217 } 218 219 /* this call is collective, only the first process gets the image data */ 220 PetscUseTypeMethod(draw, getimage, palette, &w, &h, &pixels); 221 /* only the first process handles the saving business */ 222 if (rank == 0) PetscCall(PetscDrawImageSave(basename, draw->saveimageext, palette, w, h, pixels)); 223 PetscCall(PetscFree(pixels)); 224 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw))); 225 226 finally: 227 #if defined(PETSC_HAVE_SAWS) 228 PetscCall(PetscDrawSave_SAWs(draw)); 229 #endif 230 PetscFunctionReturn(0); 231 } 232 233 /*@ 234 PetscDrawSaveMovie - Saves a movie from previously saved images 235 236 Collective on draw 237 238 Input Parameters: 239 . draw - the drawing context 240 241 Level: advanced 242 243 Notes: 244 This is not normally called by the user. 245 246 The ffmpeg utility must be in your path to make the movie. 247 248 .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetSaveMovie()` 249 @*/ 250 PetscErrorCode PetscDrawSaveMovie(PetscDraw draw) { 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 PetscImageList image = SAWs_images; 286 287 PetscFunctionBegin; 288 while (image) { 289 PetscImageList next = image->next; 290 PetscCall(PetscFree(image->filename)); 291 PetscCall(PetscFree(image->ext)); 292 PetscCall(PetscFree(image)); 293 image = next; 294 } 295 PetscFunctionReturn(0); 296 } 297 298 static PetscErrorCode PetscImageListAdd(const char filename[], const char ext[], PetscInt count) { 299 PetscImageList image, oimage = SAWs_images; 300 PetscBool flg; 301 302 PetscFunctionBegin; 303 if (oimage) { 304 PetscCall(PetscStrcmp(filename, oimage->filename, &flg)); 305 if (flg) { 306 oimage->count = count; 307 PetscFunctionReturn(0); 308 } 309 while (oimage->next) { 310 oimage = oimage->next; 311 PetscCall(PetscStrcmp(filename, oimage->filename, &flg)); 312 if (flg) { 313 oimage->count = count; 314 PetscFunctionReturn(0); 315 } 316 } 317 PetscCall(PetscNew(&image)); 318 oimage->next = image; 319 } else { 320 PetscCall(PetscRegisterFinalize(PetscImageListDestroy)); 321 PetscCall(PetscNew(&image)); 322 SAWs_images = image; 323 } 324 PetscCall(PetscStrallocpy(filename, &image->filename)); 325 PetscCall(PetscStrallocpy(ext, &image->ext)); 326 image->count = count; 327 PetscFunctionReturn(0); 328 } 329 330 static PetscErrorCode PetscDrawSave_SAWs(PetscDraw draw) { 331 PetscImageList image; 332 char body[4096]; 333 size_t len = 0; 334 335 PetscFunctionBegin; 336 if (!draw->savefilename || !draw->saveimageext) PetscFunctionReturn(0); 337 PetscCall(PetscImageListAdd(draw->savefilename, draw->saveimageext, draw->savefilecount - 1)); 338 image = SAWs_images; 339 while (image) { 340 const char *name = image->filename; 341 const char *ext = image->ext; 342 if (draw->savesinglefile) { 343 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s%s\" alt=\"None\">", name, ext)); 344 } else { 345 PetscCall(PetscSNPrintf(body + len, 4086 - len, "<img src=\"%s/%s_%d%s\" alt=\"None\">", name, name, image->count, ext)); 346 } 347 PetscCall(PetscStrlen(body, &len)); 348 image = image->next; 349 } 350 PetscCall(PetscStrlcat(body, "<br>\n", sizeof(body))); 351 if (draw->savefilecount > 0) PetscCallSAWs(SAWs_Pop_Body, ("index.html", 1)); 352 PetscCallSAWs(SAWs_Push_Body, ("index.html", 1, body)); 353 PetscFunctionReturn(0); 354 } 355 356 #endif 357