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