Date: 2026-05-01T06:12:04+00:00

Actual source code: dsave.c

      1: #include <petsc/private/drawimpl.h>

      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 *[]);

      8: #if defined(PETSC_HAVE_SAWS)
      9: static PetscErrorCode PetscDrawSave_SAWs(PetscDraw);
     10: #endif

     12: /*@
     13:   PetscDrawSetSave - Saves images produced in a `PetscDraw` into a file

     15:   Collective

     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

     21:   Options Database Keys:
     22: + -draw_save filename 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 [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

     26:   Level: intermediate

     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).

     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];

     44:   PetscFunctionBegin;
     46:   if (filename) PetscAssertPointer(filename, 2);

     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:   }

     62:   if (!savename) PetscCall(PetscObjectGetName((PetscObject)draw, &savename));
     63:   PetscCall(PetscDrawImageCheckFormat(&imageext));

     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));

     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: }

     79: /*@
     80:   PetscDrawSetSaveMovie - Saves a movie produced from a `PetscDraw` into a file

     82:   Collective

     84:   Input Parameters:
     85: + draw     - the graphics context
     86: - movieext - optional extension defining the movie format

     88:   Options Database Key:
     89: . -draw_save_movie .ext - saves a movie with extension .ext

     91:   Level: intermediate

     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.

     97: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
     98: @*/
     99: PetscErrorCode PetscDrawSetSaveMovie(PetscDraw draw, const char movieext[])
    100: {
    101:   PetscFunctionBegin;
    103:   if (movieext) PetscAssertPointer(movieext, 2);

    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 generate movies */

    110:   PetscCall(PetscInfo(NULL, "Will save movie to file %s%s\n", draw->savefilename, draw->savemovieext));
    111:   PetscFunctionReturn(PETSC_SUCCESS);
    112: }

    114: /*@
    115:   PetscDrawSetSaveFinalImage - Saves the final image produced in a `PetscDraw` into a file

    117:   Collective

    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

    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)

    126:   Level: intermediate

    128:   Notes:
    129:   You should call this BEFORE creating your image and calling `PetscDrawSave()`.

    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

    139: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetFromOptions()`, `PetscDrawCreate()`, `PetscDrawDestroy()`
    140: @*/
    141: PetscErrorCode PetscDrawSetSaveFinalImage(PetscDraw draw, const char filename[])
    142: {
    143:   char buf[PETSC_MAX_PATH_LEN];

    145:   PetscFunctionBegin;
    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: }

    160: /*@
    161:   PetscDrawSave - Saves a drawn image

    163:   Collective

    165:   Input Parameter:
    166: . draw - the drawing context

    168:   Level: advanced

    170:   Note:
    171:   this is not normally called by the user.

    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;

    184:   PetscFunctionBegin;
    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));

    194:   saveindex = draw->savefilecount++;

    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;

    216:     PetscCall(PetscStrrchr(draw->savefilename, '/', &basefilename));
    217:     if (basefilename != draw->savefilename) {
    218:       PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s_%" PetscInt_FMT, draw->savefilename, saveindex));
    219:     } else {
    220:       PetscCall(PetscSNPrintf(basename, sizeof(basename), "%s/%s_%" PetscInt_FMT, draw->savefilename, draw->savefilename, saveindex));
    221:     }
    222:   }

    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)));

    231: finally:
    232: #if defined(PETSC_HAVE_SAWS)
    233:   PetscCall(PetscDrawSave_SAWs(draw));
    234: #endif
    235:   PetscFunctionReturn(PETSC_SUCCESS);
    236: }

    238: /*@
    239:   PetscDrawSaveMovie - Saves a movie from previously saved images

    241:   Collective

    243:   Input Parameter:
    244: . draw - the drawing context

    246:   Level: advanced

    248:   Notes:
    249:   This is not normally called by the user.

    251:   The ffmpeg utility must be in your path to make the movie.

    253: .seealso: `PetscDraw`, `PetscDrawSetSave()`, `PetscDrawSetSaveMovie()`
    254: @*/
    255: PetscErrorCode PetscDrawSaveMovie(PetscDraw draw)
    256: {
    257:   PetscMPIInt rank;

    259:   PetscFunctionBegin;
    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: }

    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: };

    288: static PetscImageList SAWs_images = NULL;

    290: static PetscErrorCode PetscImageListDestroy(void)
    291: {
    292:   PetscImageList image = SAWs_images;

    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: }

    305: static PetscErrorCode PetscImageListAdd(const char filename[], const char ext[], PetscInt count)
    306: {
    307:   PetscImageList image, oimage = SAWs_images;
    308:   PetscBool      flg;

    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: }

    338: static PetscErrorCode PetscDrawSave_SAWs(PetscDraw draw)
    339: {
    340:   PetscImageList image;
    341:   char           body[4096];
    342:   size_t         len = 0;

    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: }

    365: #endif