xref: /petsc/src/sys/classes/draw/utils/image.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
18067a7d5SLisandro Dalcin #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/
28067a7d5SLisandro Dalcin 
38067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageSave(const char[], const char[], unsigned char[][3], unsigned int, unsigned int, const unsigned char[]);
43d242201SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawMovieSave(const char[], PetscInt, const char[], PetscInt, const char[]);
58067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageCheckFormat(const char *[]);
68067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawMovieCheckFormat(const char *[]);
78067a7d5SLisandro Dalcin 
88067a7d5SLisandro Dalcin /*
98067a7d5SLisandro Dalcin    Code to write images in PPM format
108067a7d5SLisandro Dalcin */
119371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscDrawImageSavePPM(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
128067a7d5SLisandro Dalcin   int            fd;
138067a7d5SLisandro Dalcin   char           header[32];
148067a7d5SLisandro Dalcin   size_t         hdrlen;
158067a7d5SLisandro Dalcin   unsigned char *rgb;
168067a7d5SLisandro Dalcin 
178067a7d5SLisandro Dalcin   PetscFunctionBegin;
188067a7d5SLisandro Dalcin   PetscValidCharPointer(filename, 1);
198067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette, 2);
208067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels, 5);
218067a7d5SLisandro Dalcin   /* map pixels to RGB colors */
228067a7d5SLisandro Dalcin   if (palette) {
238067a7d5SLisandro Dalcin     int                  k, p, n = (int)(w * h);
248067a7d5SLisandro Dalcin     const unsigned char *colordef;
259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(3 * w * h, &rgb));
268067a7d5SLisandro Dalcin     for (k = p = 0; k < n; k++) {
278067a7d5SLisandro Dalcin       colordef = palette[pixels[k]];
288067a7d5SLisandro Dalcin       rgb[p++] = colordef[0];
298067a7d5SLisandro Dalcin       rgb[p++] = colordef[1];
308067a7d5SLisandro Dalcin       rgb[p++] = colordef[2];
318067a7d5SLisandro Dalcin     }
328067a7d5SLisandro Dalcin   } else { /* assume pixels are RGB colors */
338067a7d5SLisandro Dalcin     rgb = (unsigned char *)pixels;
348067a7d5SLisandro Dalcin   }
358067a7d5SLisandro Dalcin   /* open file and write PPM header */
369566063dSJacob Faibussowitsch   PetscCall(PetscBinaryOpen(filename, FILE_MODE_WRITE, &fd));
379566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(header, sizeof(header), "P6\n%d %d\n255\n%c", (int)w, (int)h, '\0'));
389566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header, &hdrlen));
399566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(fd, header, hdrlen, PETSC_CHAR));
408067a7d5SLisandro Dalcin   /* write image data and close file */
419566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(fd, rgb, 3 * w * h, PETSC_CHAR));
429566063dSJacob Faibussowitsch   PetscCall(PetscBinaryClose(fd));
439566063dSJacob Faibussowitsch   if (palette) PetscCall(PetscFree(rgb));
448067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
458067a7d5SLisandro Dalcin }
468067a7d5SLisandro Dalcin 
479371c9d4SSatish Balay static PetscErrorCode PetscDrawImageSave_PPM(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
489371c9d4SSatish Balay   return PetscDrawImageSavePPM(filename, palette, w, h, pixels);
499371c9d4SSatish Balay }
508067a7d5SLisandro Dalcin 
518067a7d5SLisandro Dalcin /*
528067a7d5SLisandro Dalcin    Code to write images in PNG format
538067a7d5SLisandro Dalcin */
548067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBPNG)
558067a7d5SLisandro Dalcin 
568067a7d5SLisandro Dalcin #include <png.h>
578067a7d5SLisandro Dalcin 
588067a7d5SLisandro Dalcin #if defined(PNG_SETJMP_SUPPORTED)
598067a7d5SLisandro Dalcin #ifndef png_jmpbuf
608067a7d5SLisandro Dalcin #define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
618067a7d5SLisandro Dalcin #endif
628067a7d5SLisandro Dalcin #endif
638067a7d5SLisandro Dalcin 
649371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
658067a7d5SLisandro Dalcin   FILE        *fp;
668067a7d5SLisandro Dalcin   png_struct  *png_ptr;
678067a7d5SLisandro Dalcin   png_info    *info_ptr;
688067a7d5SLisandro Dalcin   unsigned int row, stride = palette ? w : 3 * w;
698067a7d5SLisandro Dalcin 
708067a7d5SLisandro Dalcin   PetscFunctionBegin;
718067a7d5SLisandro Dalcin   PetscValidCharPointer(filename, 1);
728067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette, 2);
738067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels, 5);
748067a7d5SLisandro Dalcin 
758067a7d5SLisandro Dalcin   /* open file and create libpng structures */
769566063dSJacob Faibussowitsch   PetscCall(PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp));
778067a7d5SLisandro Dalcin   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
7828b400f6SJacob Faibussowitsch   PetscCheck(png_ptr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot create PNG context");
798067a7d5SLisandro Dalcin   info_ptr = png_create_info_struct(png_ptr);
8028b400f6SJacob Faibussowitsch   PetscCheck(info_ptr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot create PNG context");
818067a7d5SLisandro Dalcin 
828067a7d5SLisandro Dalcin   /* setup libpng error handling */
838067a7d5SLisandro Dalcin #if defined(PNG_SETJMP_SUPPORTED)
848067a7d5SLisandro Dalcin   if (setjmp(png_jmpbuf(png_ptr))) {
858067a7d5SLisandro Dalcin     png_destroy_write_struct(&png_ptr, &info_ptr);
868067a7d5SLisandro Dalcin     (void)PetscFClose(PETSC_COMM_SELF, fp);
8798921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing PNG file %s", filename);
888067a7d5SLisandro Dalcin   }
898067a7d5SLisandro Dalcin #endif
908067a7d5SLisandro Dalcin 
918067a7d5SLisandro Dalcin   /* setup PNG image metadata */
928067a7d5SLisandro Dalcin   png_init_io(png_ptr, fp);
939371c9d4SSatish Balay   png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/ 8, palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
949371c9d4SSatish Balay   if (palette) png_set_PLTE(png_ptr, info_ptr, (png_color *)palette, 256);
958067a7d5SLisandro Dalcin 
968067a7d5SLisandro Dalcin   /* write PNG image header and data */
978067a7d5SLisandro Dalcin   png_write_info(png_ptr, info_ptr);
989371c9d4SSatish Balay   for (row = 0; row < h; row++) png_write_row(png_ptr, pixels + row * stride);
998067a7d5SLisandro Dalcin   png_write_end(png_ptr, NULL);
1008067a7d5SLisandro Dalcin 
1018067a7d5SLisandro Dalcin   /* destroy libpng structures and close file */
1028067a7d5SLisandro Dalcin   png_destroy_write_struct(&png_ptr, &info_ptr);
1039566063dSJacob Faibussowitsch   PetscCall(PetscFClose(PETSC_COMM_SELF, fp));
1048067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
1058067a7d5SLisandro Dalcin }
1068067a7d5SLisandro Dalcin 
1079371c9d4SSatish Balay static PetscErrorCode PetscDrawImageSave_PNG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
1089371c9d4SSatish Balay   return PetscDrawImageSavePNG(filename, palette, w, h, pixels);
1099371c9d4SSatish Balay }
1108067a7d5SLisandro Dalcin 
1118067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_LIBPNG*/
1128067a7d5SLisandro Dalcin 
1138067a7d5SLisandro Dalcin /*
1148067a7d5SLisandro Dalcin    Code to write images in GIF format
1158067a7d5SLisandro Dalcin */
1168067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
1178067a7d5SLisandro Dalcin 
1188067a7d5SLisandro Dalcin #include <gif_lib.h>
1198067a7d5SLisandro Dalcin 
1208067a7d5SLisandro Dalcin #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
1218067a7d5SLisandro Dalcin #define GifMakeMapObject            MakeMapObject
1228067a7d5SLisandro Dalcin #define GifFreeMapObject            FreeMapObject
1238067a7d5SLisandro Dalcin #define EGifOpenFileName(n, b, err) EGifOpenFileName(n, b)
1248067a7d5SLisandro Dalcin #define EGifOpenFileHandle(h, err)  EGifOpenFileName(h)
1258067a7d5SLisandro Dalcin #define EGifCloseFile(f, err)       EGifCloseFile(f)
12675c73fc3SLisandro Dalcin #define DGifOpenFileName(n, err)    DGifOpenFileName(n)
12775c73fc3SLisandro Dalcin #define DGifOpenFileHandle(h, err)  DGifOpenFileName(h)
12875c73fc3SLisandro Dalcin #define DGifCloseFile(f, err)       DGifCloseFile(f)
1298067a7d5SLisandro Dalcin #endif
1308067a7d5SLisandro Dalcin 
1319371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
1329566063dSJacob Faibussowitsch   int             Row;
1338067a7d5SLisandro Dalcin   int             Width      = (int)w;
1348067a7d5SLisandro Dalcin   int             Height     = (int)h;
1358067a7d5SLisandro Dalcin   int             ColorRes   = 8;
1368067a7d5SLisandro Dalcin   int             ColorCount = 256;
1378067a7d5SLisandro Dalcin   ColorMapObject *GifCMap    = NULL;
1388067a7d5SLisandro Dalcin   GifFileType    *GifFile    = NULL;
13998921bdaSJacob Faibussowitsch #define SETERRGIF(msg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg ", GIF file: %s", filename)
1409371c9d4SSatish Balay #define PetscCallGIF(msg, ...) \
1419371c9d4SSatish Balay   do { \
1429566063dSJacob Faibussowitsch     int Error = __VA_ARGS__; \
1439566063dSJacob Faibussowitsch     if (PetscUnlikely(Error != GIF_OK)) SETERRGIF(msg); \
1449566063dSJacob Faibussowitsch   } while (0)
1458067a7d5SLisandro Dalcin 
1468067a7d5SLisandro Dalcin   PetscFunctionBegin;
1478067a7d5SLisandro Dalcin   PetscValidCharPointer(filename, 1);
1488067a7d5SLisandro Dalcin   PetscValidCharPointer(palette, 2);
1498067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels, 5);
1508067a7d5SLisandro Dalcin 
1519371c9d4SSatish Balay   GifCMap = GifMakeMapObject(ColorCount, (GifColorType *)palette);
1529371c9d4SSatish Balay   if (!GifCMap) SETERRGIF("Allocating colormap");
1539371c9d4SSatish Balay   GifFile = EGifOpenFileName(filename, 0, NULL);
1549371c9d4SSatish Balay   if (!GifFile) SETERRGIF("Opening");
1559566063dSJacob Faibussowitsch   PetscCallGIF("Writing screen descriptor", EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap));
1569566063dSJacob Faibussowitsch   PetscCallGIF("Writing image descriptor", EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL));
157*48a46eb9SPierre Jolivet   for (Row = 0; Row < Height; Row++) PetscCallGIF("Writing image pixels", EGifPutLine(GifFile, (GifPixelType *)pixels + Row * Width, Width));
1589566063dSJacob Faibussowitsch   PetscCallGIF("Closing", EGifCloseFile(GifFile, NULL));
1599371c9d4SSatish Balay   GifFreeMapObject(GifCMap);
1609371c9d4SSatish Balay   GifCMap = NULL;
1618067a7d5SLisandro Dalcin 
1628067a7d5SLisandro Dalcin #undef SETERRGIF
1638067a7d5SLisandro Dalcin #undef CHKERRGIF
1648067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
1658067a7d5SLisandro Dalcin }
1668067a7d5SLisandro Dalcin 
1679371c9d4SSatish Balay static PetscErrorCode PetscDrawImageSave_GIF(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
1689371c9d4SSatish Balay   return PetscDrawImageSaveGIF(filename, palette, w, h, pixels);
1699371c9d4SSatish Balay }
1708067a7d5SLisandro Dalcin 
1719371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[], PetscInt count, const char movie[]) {
17275c73fc3SLisandro Dalcin   int          i, j, Row;
17375c73fc3SLisandro Dalcin   char         image[PETSC_MAX_PATH_LEN];
17475c73fc3SLisandro Dalcin   GifFileType *GifMovie = NULL;
17575c73fc3SLisandro Dalcin   GifFileType *GifImage = NULL;
17698921bdaSJacob Faibussowitsch #define SETERRGIF(msg, fn) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg " GIF file %s", fn)
17775c73fc3SLisandro Dalcin 
17875c73fc3SLisandro Dalcin   PetscFunctionBegin;
17975c73fc3SLisandro Dalcin   PetscValidCharPointer(pattern, 1);
18075c73fc3SLisandro Dalcin   PetscValidCharPointer(movie, 3);
18175c73fc3SLisandro Dalcin   if (count < 1) PetscFunctionReturn(0);
18275c73fc3SLisandro Dalcin 
18375c73fc3SLisandro Dalcin   for (i = 0; i < count; i++) {
1849566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(image, sizeof(image), pattern, (int)i));
18575c73fc3SLisandro Dalcin     /* open and read image file */
18675c73fc3SLisandro Dalcin     if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input", image);
18775c73fc3SLisandro Dalcin     if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input", image);
18875c73fc3SLisandro Dalcin     /* open movie file and write header */
18975c73fc3SLisandro Dalcin     if (i == 0) {
19075c73fc3SLisandro Dalcin       if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output", movie);
1919371c9d4SSatish Balay       if (EGifPutScreenDesc(GifMovie, GifImage->SWidth, GifImage->SHeight, GifImage->SColorResolution, GifImage->SBackGroundColor, GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,", movie);
19275c73fc3SLisandro Dalcin     }
19375c73fc3SLisandro Dalcin     /* loop over all frames in image */
19475c73fc3SLisandro Dalcin     for (j = 0; j < GifImage->ImageCount; j++) {
19575c73fc3SLisandro Dalcin       SavedImage     *sp            = &GifImage->SavedImages[j];
19675c73fc3SLisandro Dalcin       GifImageDesc   *GifFrame      = &sp->ImageDesc;
19775c73fc3SLisandro Dalcin       ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
1989371c9d4SSatish Balay       if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount && !memcmp(GifMovie->SColorMap->Colors, FrameColorMap->Colors, (size_t)FrameColorMap->ColorCount * sizeof(GifColorType))) FrameColorMap = NULL;
19975c73fc3SLisandro Dalcin       /* add frame to movie */
2009371c9d4SSatish Balay       if (EGifPutImageDesc(GifMovie, GifFrame->Left, GifFrame->Top, GifFrame->Width, GifFrame->Height, GifFrame->Interlace, FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,", movie);
20175c73fc3SLisandro Dalcin       for (Row = 0; Row < GifFrame->Height; Row++) {
2029371c9d4SSatish Balay         if (EGifPutLine(GifMovie, sp->RasterBits + Row * GifFrame->Width, GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,", movie);
20375c73fc3SLisandro Dalcin       }
20475c73fc3SLisandro Dalcin     }
20575c73fc3SLisandro Dalcin     if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input", image);
20675c73fc3SLisandro Dalcin   }
20775c73fc3SLisandro Dalcin   if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output", movie);
20875c73fc3SLisandro Dalcin 
20975c73fc3SLisandro Dalcin #undef SETERRGIF
21075c73fc3SLisandro Dalcin   PetscFunctionReturn(0);
21175c73fc3SLisandro Dalcin }
21275c73fc3SLisandro Dalcin 
2138067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_GIFLIB*/
2148067a7d5SLisandro Dalcin 
2158067a7d5SLisandro Dalcin /*
2168067a7d5SLisandro Dalcin    Code to write images in JPEG format
2178067a7d5SLisandro Dalcin */
2188067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
2198067a7d5SLisandro Dalcin 
2208067a7d5SLisandro Dalcin #include <jpeglib.h>
2218067a7d5SLisandro Dalcin 
2228067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2238067a7d5SLisandro Dalcin #include <setjmp.h>
2248067a7d5SLisandro Dalcin static jmp_buf petsc_jpeg_jumpbuf;
2259371c9d4SSatish Balay static void    petsc_jpeg_error_longjmp(j_common_ptr cinfo) {
2269371c9d4SSatish Balay      (void)cinfo;
2279371c9d4SSatish Balay      longjmp(petsc_jpeg_jumpbuf, 1);
2289371c9d4SSatish Balay }
2298067a7d5SLisandro Dalcin #endif
2308067a7d5SLisandro Dalcin 
2319371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
2328067a7d5SLisandro Dalcin   unsigned char              *rgbpixels;
2338067a7d5SLisandro Dalcin   FILE                       *fp;
2348067a7d5SLisandro Dalcin   struct jpeg_compress_struct cinfo;
2358067a7d5SLisandro Dalcin   struct jpeg_error_mgr       jerr;
2368067a7d5SLisandro Dalcin 
2378067a7d5SLisandro Dalcin   PetscFunctionBegin;
2388067a7d5SLisandro Dalcin   PetscValidCharPointer(filename, 1);
2398067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette, 2);
2408067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels, 5);
2418067a7d5SLisandro Dalcin   /* map pixels to RGB colors */
2428067a7d5SLisandro Dalcin   if (palette) {
2438067a7d5SLisandro Dalcin     int                  k, p, n = (int)(w * h);
2448067a7d5SLisandro Dalcin     const unsigned char *colordef;
2459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(3 * w * h, &rgbpixels));
2468067a7d5SLisandro Dalcin     for (k = p = 0; k < n; k++) {
2478067a7d5SLisandro Dalcin       colordef       = palette[pixels[k]];
2488067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[0];
2498067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[1];
2508067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[2];
2518067a7d5SLisandro Dalcin     }
2528067a7d5SLisandro Dalcin   } else { /* assume pixels are RGB colors */
2538067a7d5SLisandro Dalcin     rgbpixels = (unsigned char *)pixels;
2548067a7d5SLisandro Dalcin   }
2559566063dSJacob Faibussowitsch   PetscCall(PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp));
2568067a7d5SLisandro Dalcin 
2578067a7d5SLisandro Dalcin   cinfo.err = jpeg_std_error(&jerr);
2588067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2598067a7d5SLisandro Dalcin   jerr.error_exit = petsc_jpeg_error_longjmp;
2608067a7d5SLisandro Dalcin   if (setjmp(petsc_jpeg_jumpbuf)) {
2618067a7d5SLisandro Dalcin     char message[JMSG_LENGTH_MAX];
2628067a7d5SLisandro Dalcin     jerr.format_message((j_common_ptr)&cinfo, message);
2638067a7d5SLisandro Dalcin     jpeg_destroy_compress(&cinfo);
2648067a7d5SLisandro Dalcin     (void)PetscFClose(PETSC_COMM_SELF, fp);
26598921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing JPEG file %s\n%s", filename, message);
2668067a7d5SLisandro Dalcin   }
2678067a7d5SLisandro Dalcin #endif
2688067a7d5SLisandro Dalcin   jpeg_create_compress(&cinfo);
2698067a7d5SLisandro Dalcin   jpeg_stdio_dest(&cinfo, fp);
2708067a7d5SLisandro Dalcin   cinfo.image_width      = w;
2718067a7d5SLisandro Dalcin   cinfo.image_height     = h;
2728067a7d5SLisandro Dalcin   cinfo.input_components = 3;
2738067a7d5SLisandro Dalcin   cinfo.in_color_space   = JCS_RGB;
2748067a7d5SLisandro Dalcin   jpeg_set_defaults(&cinfo);
2758067a7d5SLisandro Dalcin   jpeg_start_compress(&cinfo, TRUE);
2768067a7d5SLisandro Dalcin   while (cinfo.next_scanline < cinfo.image_height) {
2778067a7d5SLisandro Dalcin     unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3 * w;
2788067a7d5SLisandro Dalcin     (void)jpeg_write_scanlines(&cinfo, &rowptr, 1);
2798067a7d5SLisandro Dalcin   }
2808067a7d5SLisandro Dalcin   jpeg_finish_compress(&cinfo);
2818067a7d5SLisandro Dalcin   jpeg_destroy_compress(&cinfo);
2828067a7d5SLisandro Dalcin 
2839566063dSJacob Faibussowitsch   PetscCall(PetscFClose(PETSC_COMM_SELF, fp));
2849566063dSJacob Faibussowitsch   if (palette) PetscCall(PetscFree(rgbpixels));
2858067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
2868067a7d5SLisandro Dalcin }
2878067a7d5SLisandro Dalcin 
2889371c9d4SSatish Balay static PetscErrorCode PetscDrawImageSave_JPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
2899371c9d4SSatish Balay   return PetscDrawImageSaveJPG(filename, palette, w, h, pixels);
2909371c9d4SSatish Balay }
2918067a7d5SLisandro Dalcin 
2928067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_LIBJPEG*/
2938067a7d5SLisandro Dalcin 
2948067a7d5SLisandro Dalcin static struct {
2958067a7d5SLisandro Dalcin   const char *extension;
2968067a7d5SLisandro Dalcin   PetscErrorCode (*SaveImage)(const char[], unsigned char[][3], unsigned int, unsigned int, const unsigned char[]);
2978067a7d5SLisandro Dalcin } PetscDrawImageSaveTable[] = {
2988067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBPNG)
2998067a7d5SLisandro Dalcin   {".png", PetscDrawImageSave_PNG},
3008067a7d5SLisandro Dalcin #endif
3018067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
3028067a7d5SLisandro Dalcin   {".gif", PetscDrawImageSave_GIF},
3038067a7d5SLisandro Dalcin #endif
3048067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
3058067a7d5SLisandro Dalcin   {".jpg", PetscDrawImageSave_JPG},
3068067a7d5SLisandro Dalcin #endif
3078067a7d5SLisandro Dalcin   {".ppm", PetscDrawImageSave_PPM}
3088067a7d5SLisandro Dalcin };
3098067a7d5SLisandro Dalcin 
3109371c9d4SSatish Balay PetscErrorCode PetscDrawImageCheckFormat(const char *ext[]) {
3118067a7d5SLisandro Dalcin   size_t    k;
3128067a7d5SLisandro Dalcin   PetscBool match = PETSC_FALSE;
3138067a7d5SLisandro Dalcin 
3148067a7d5SLisandro Dalcin   PetscFunctionBegin;
3158067a7d5SLisandro Dalcin   /* if extension is empty, return default format to caller */
3168067a7d5SLisandro Dalcin   PetscValidPointer(ext, 1);
3178067a7d5SLisandro Dalcin   if (!*ext || !**ext) {
3188067a7d5SLisandro Dalcin     *ext = PetscDrawImageSaveTable[0].extension;
3198067a7d5SLisandro Dalcin     PetscFunctionReturn(0);
3208067a7d5SLisandro Dalcin   }
321a9db196aSBarry Smith   /* check the extension matches a supported format */
3228067a7d5SLisandro Dalcin   PetscValidCharPointer(*ext, 1);
323dd39110bSPierre Jolivet   for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
3249566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(*ext, PetscDrawImageSaveTable[k].extension, &match));
3258067a7d5SLisandro Dalcin     if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(0);
3268067a7d5SLisandro Dalcin   }
32798921bdaSJacob Faibussowitsch   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Image extension %s not supported, use .ppm or see PetscDrawSetSave() for what ./configure option you may need", *ext);
3288067a7d5SLisandro Dalcin }
3298067a7d5SLisandro Dalcin 
3309371c9d4SSatish Balay PetscErrorCode PetscDrawImageSave(const char basename[], const char ext[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[]) {
3318067a7d5SLisandro Dalcin   size_t    k;
3328067a7d5SLisandro Dalcin   PetscBool match = PETSC_FALSE;
3338067a7d5SLisandro Dalcin   char      filename[PETSC_MAX_PATH_LEN];
3348067a7d5SLisandro Dalcin 
3358067a7d5SLisandro Dalcin   PetscFunctionBegin;
3368067a7d5SLisandro Dalcin   PetscValidCharPointer(basename, 1);
3378067a7d5SLisandro Dalcin   if (ext) PetscValidCharPointer(ext, 2);
338dadcf809SJacob Faibussowitsch   if (palette) PetscValidPointer(palette, 3);
3398067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels, 6);
3408067a7d5SLisandro Dalcin 
3419566063dSJacob Faibussowitsch   PetscCall(PetscDrawImageCheckFormat(&ext));
3429566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(filename, sizeof(filename), "%s%s", basename, ext));
343dd39110bSPierre Jolivet   for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
3449566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(ext, PetscDrawImageSaveTable[k].extension, &match));
3458067a7d5SLisandro Dalcin     if (match && PetscDrawImageSaveTable[k].SaveImage) {
3469566063dSJacob Faibussowitsch       PetscCall(PetscDrawImageSaveTable[k].SaveImage(filename, palette, w, h, pixels));
3478067a7d5SLisandro Dalcin       PetscFunctionReturn(0);
3488067a7d5SLisandro Dalcin     }
3498067a7d5SLisandro Dalcin   }
35098921bdaSJacob Faibussowitsch   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Image extension %s not supported, use .ppm", ext);
3518067a7d5SLisandro Dalcin }
3528067a7d5SLisandro Dalcin 
3539371c9d4SSatish Balay PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[]) {
3548067a7d5SLisandro Dalcin   PetscFunctionBegin;
3558067a7d5SLisandro Dalcin   PetscValidPointer(ext, 1);
3568067a7d5SLisandro Dalcin   if (!*ext || !**ext) *ext = ".m4v";
3578067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
3588067a7d5SLisandro Dalcin }
3598067a7d5SLisandro Dalcin 
3609371c9d4SSatish Balay PetscErrorCode PetscDrawMovieSave(const char basename[], PetscInt count, const char imext[], PetscInt fps, const char mvext[]) {
36175c73fc3SLisandro Dalcin   char      input[PETSC_MAX_PATH_LEN];
36275c73fc3SLisandro Dalcin   char      output[PETSC_MAX_PATH_LEN];
36375c73fc3SLisandro Dalcin   PetscBool gifinput;
3648067a7d5SLisandro Dalcin 
3658067a7d5SLisandro Dalcin   PetscFunctionBegin;
3668067a7d5SLisandro Dalcin   PetscValidCharPointer(basename, 1);
3678067a7d5SLisandro Dalcin   PetscValidCharPointer(imext, 3);
368064a246eSJacob Faibussowitsch   if (mvext) PetscValidCharPointer(mvext, 5);
3698067a7d5SLisandro Dalcin   if (count < 1) PetscFunctionReturn(0);
3708067a7d5SLisandro Dalcin 
3719566063dSJacob Faibussowitsch   PetscCall(PetscStrcasecmp(imext, ".gif", &gifinput));
3729566063dSJacob Faibussowitsch   PetscCall(PetscDrawMovieCheckFormat(&mvext));
3739566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(input, sizeof(input), "%s/%s_%%d%s", basename, basename, imext));
3749566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(output, sizeof(output), "%s%s", basename, mvext));
37575c73fc3SLisandro Dalcin 
37675c73fc3SLisandro Dalcin   /* use GIFLIB to generate an intermediate GIF animation */
37775c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
37875c73fc3SLisandro Dalcin   if (gifinput) {
37975c73fc3SLisandro Dalcin     char gifmovie[PETSC_MAX_PATH_LEN];
3809566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(gifmovie, sizeof(gifmovie), "%s/%s_movie.gif", basename, basename));
3819566063dSJacob Faibussowitsch     PetscCall(PetscDrawMovieSaveGIF(input, count, gifmovie));
3829566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(input, gifmovie));
3838067a7d5SLisandro Dalcin   }
38475c73fc3SLisandro Dalcin #endif
38575c73fc3SLisandro Dalcin 
38675c73fc3SLisandro Dalcin   /* use FFmpeg to generate a movie */
38775c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_POPEN)
38875c73fc3SLisandro Dalcin   {
389016831caSBarry Smith     FILE *fd;
39075c73fc3SLisandro Dalcin     char  options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
39175c73fc3SLisandro Dalcin     char  command[sizeof(options) + sizeof(extraopts) + sizeof(framerate) + PETSC_MAX_PATH_LEN * 2];
3929566063dSJacob Faibussowitsch     if (fps > 0) PetscCall(PetscSNPrintf(framerate, sizeof(framerate), "-r %d", (int)fps));
39375c73fc3SLisandro Dalcin     if (gifinput) {
3949566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(options, " -f gif", sizeof(options)));
3959566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(extraopts, sizeof(extraopts), " -default_delay %d", (fps > 0) ? 100 / (int)fps : 4));
39675c73fc3SLisandro Dalcin     } else {
3979566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(options, " -f image2", sizeof(options)));
3989566063dSJacob Faibussowitsch       if (fps > 0) PetscCall(PetscSNPrintf(extraopts, sizeof(extraopts), " -framerate %d", (int)fps));
39975c73fc3SLisandro Dalcin     }
4009566063dSJacob Faibussowitsch     if (extraopts[0]) PetscCall(PetscStrlcat(options, extraopts, sizeof(options)));
4019566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(command, sizeof(command), "ffmpeg %s -i \"%s\" %s \"%s\"", options, input, framerate, output));
4029566063dSJacob Faibussowitsch     PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", &fd));
4039566063dSJacob Faibussowitsch     PetscCall(PetscPClose(PETSC_COMM_SELF, fd));
4048067a7d5SLisandro Dalcin   }
4058067a7d5SLisandro Dalcin #endif
4068067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
4078067a7d5SLisandro Dalcin }
408