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 */
PetscDrawImageSavePPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])11d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscDrawImageSavePPM(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
12d71ae5a4SJacob Faibussowitsch {
138067a7d5SLisandro Dalcin int fd;
148067a7d5SLisandro Dalcin char header[32];
158067a7d5SLisandro Dalcin size_t hdrlen;
168067a7d5SLisandro Dalcin unsigned char *rgb;
178067a7d5SLisandro Dalcin
188067a7d5SLisandro Dalcin PetscFunctionBegin;
194f572ea9SToby Isaac PetscAssertPointer(filename, 1);
204f572ea9SToby Isaac if (palette) PetscAssertPointer(palette, 2);
214f572ea9SToby Isaac PetscAssertPointer(pixels, 5);
228067a7d5SLisandro Dalcin /* map pixels to RGB colors */
238067a7d5SLisandro Dalcin if (palette) {
248067a7d5SLisandro Dalcin int k, p, n = (int)(w * h);
258067a7d5SLisandro Dalcin const unsigned char *colordef;
269566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3 * w * h, &rgb));
278067a7d5SLisandro Dalcin for (k = p = 0; k < n; k++) {
288067a7d5SLisandro Dalcin colordef = palette[pixels[k]];
298067a7d5SLisandro Dalcin rgb[p++] = colordef[0];
308067a7d5SLisandro Dalcin rgb[p++] = colordef[1];
318067a7d5SLisandro Dalcin rgb[p++] = colordef[2];
328067a7d5SLisandro Dalcin }
338067a7d5SLisandro Dalcin } else { /* assume pixels are RGB colors */
348067a7d5SLisandro Dalcin rgb = (unsigned char *)pixels;
358067a7d5SLisandro Dalcin }
368067a7d5SLisandro Dalcin /* open file and write PPM header */
379566063dSJacob Faibussowitsch PetscCall(PetscBinaryOpen(filename, FILE_MODE_WRITE, &fd));
389566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(header, sizeof(header), "P6\n%d %d\n255\n%c", (int)w, (int)h, '\0'));
399566063dSJacob Faibussowitsch PetscCall(PetscStrlen(header, &hdrlen));
409566063dSJacob Faibussowitsch PetscCall(PetscBinaryWrite(fd, header, hdrlen, PETSC_CHAR));
418067a7d5SLisandro Dalcin /* write image data and close file */
429566063dSJacob Faibussowitsch PetscCall(PetscBinaryWrite(fd, rgb, 3 * w * h, PETSC_CHAR));
439566063dSJacob Faibussowitsch PetscCall(PetscBinaryClose(fd));
449566063dSJacob Faibussowitsch if (palette) PetscCall(PetscFree(rgb));
453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
468067a7d5SLisandro Dalcin }
478067a7d5SLisandro Dalcin
PetscDrawImageSave_PPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])48d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDrawImageSave_PPM(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
49d71ae5a4SJacob Faibussowitsch {
509371c9d4SSatish Balay return PetscDrawImageSavePPM(filename, palette, w, h, pixels);
519371c9d4SSatish Balay }
528067a7d5SLisandro Dalcin
538067a7d5SLisandro Dalcin /*
548067a7d5SLisandro Dalcin Code to write images in PNG format
558067a7d5SLisandro Dalcin */
568067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBPNG)
578067a7d5SLisandro Dalcin
588067a7d5SLisandro Dalcin #include <png.h>
598067a7d5SLisandro Dalcin
608067a7d5SLisandro Dalcin #if defined(PNG_SETJMP_SUPPORTED)
61*beceaeb6SBarry Smith #if !defined(png_jmpbuf)
628067a7d5SLisandro Dalcin #define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
638067a7d5SLisandro Dalcin #endif
648067a7d5SLisandro Dalcin #endif
658067a7d5SLisandro Dalcin
PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])66d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
67d71ae5a4SJacob Faibussowitsch {
688067a7d5SLisandro Dalcin FILE *fp;
698067a7d5SLisandro Dalcin png_struct *png_ptr;
708067a7d5SLisandro Dalcin png_info *info_ptr;
718067a7d5SLisandro Dalcin unsigned int row, stride = palette ? w : 3 * w;
728067a7d5SLisandro Dalcin
738067a7d5SLisandro Dalcin PetscFunctionBegin;
744f572ea9SToby Isaac PetscAssertPointer(filename, 1);
754f572ea9SToby Isaac if (palette) PetscAssertPointer(palette, 2);
764f572ea9SToby Isaac PetscAssertPointer(pixels, 5);
778067a7d5SLisandro Dalcin
788067a7d5SLisandro Dalcin /* open file and create libpng structures */
799566063dSJacob Faibussowitsch PetscCall(PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp));
808067a7d5SLisandro Dalcin png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
8128b400f6SJacob Faibussowitsch PetscCheck(png_ptr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot create PNG context");
828067a7d5SLisandro Dalcin info_ptr = png_create_info_struct(png_ptr);
8328b400f6SJacob Faibussowitsch PetscCheck(info_ptr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot create PNG context");
848067a7d5SLisandro Dalcin
858067a7d5SLisandro Dalcin /* setup libpng error handling */
868067a7d5SLisandro Dalcin #if defined(PNG_SETJMP_SUPPORTED)
878067a7d5SLisandro Dalcin if (setjmp(png_jmpbuf(png_ptr))) {
888067a7d5SLisandro Dalcin png_destroy_write_struct(&png_ptr, &info_ptr);
898067a7d5SLisandro Dalcin (void)PetscFClose(PETSC_COMM_SELF, fp);
9098921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing PNG file %s", filename);
918067a7d5SLisandro Dalcin }
928067a7d5SLisandro Dalcin #endif
938067a7d5SLisandro Dalcin
948067a7d5SLisandro Dalcin /* setup PNG image metadata */
958067a7d5SLisandro Dalcin png_init_io(png_ptr, fp);
969371c9d4SSatish 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);
979371c9d4SSatish Balay if (palette) png_set_PLTE(png_ptr, info_ptr, (png_color *)palette, 256);
988067a7d5SLisandro Dalcin
998067a7d5SLisandro Dalcin /* write PNG image header and data */
1008067a7d5SLisandro Dalcin png_write_info(png_ptr, info_ptr);
1019371c9d4SSatish Balay for (row = 0; row < h; row++) png_write_row(png_ptr, pixels + row * stride);
1028067a7d5SLisandro Dalcin png_write_end(png_ptr, NULL);
1038067a7d5SLisandro Dalcin
1048067a7d5SLisandro Dalcin /* destroy libpng structures and close file */
1058067a7d5SLisandro Dalcin png_destroy_write_struct(&png_ptr, &info_ptr);
1069566063dSJacob Faibussowitsch PetscCall(PetscFClose(PETSC_COMM_SELF, fp));
1073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1088067a7d5SLisandro Dalcin }
1098067a7d5SLisandro Dalcin
PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])110d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDrawImageSave_PNG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
111d71ae5a4SJacob Faibussowitsch {
1129371c9d4SSatish Balay return PetscDrawImageSavePNG(filename, palette, w, h, pixels);
1139371c9d4SSatish Balay }
1148067a7d5SLisandro Dalcin
1158067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_LIBPNG*/
1168067a7d5SLisandro Dalcin
1178067a7d5SLisandro Dalcin /*
1188067a7d5SLisandro Dalcin Code to write images in GIF format
1198067a7d5SLisandro Dalcin */
1208067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
1218067a7d5SLisandro Dalcin
1228067a7d5SLisandro Dalcin #include <gif_lib.h>
1238067a7d5SLisandro Dalcin
1248067a7d5SLisandro Dalcin #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
1258067a7d5SLisandro Dalcin #define GifMakeMapObject MakeMapObject
1268067a7d5SLisandro Dalcin #define GifFreeMapObject FreeMapObject
1278067a7d5SLisandro Dalcin #define EGifOpenFileName(n, b, err) EGifOpenFileName(n, b)
1288067a7d5SLisandro Dalcin #define EGifOpenFileHandle(h, err) EGifOpenFileName(h)
1298067a7d5SLisandro Dalcin #define EGifCloseFile(f, err) EGifCloseFile(f)
13075c73fc3SLisandro Dalcin #define DGifOpenFileName(n, err) DGifOpenFileName(n)
13175c73fc3SLisandro Dalcin #define DGifOpenFileHandle(h, err) DGifOpenFileName(h)
13275c73fc3SLisandro Dalcin #define DGifCloseFile(f, err) DGifCloseFile(f)
1338067a7d5SLisandro Dalcin #endif
1348067a7d5SLisandro Dalcin
PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])135d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
136d71ae5a4SJacob Faibussowitsch {
1379566063dSJacob Faibussowitsch int Row;
1388067a7d5SLisandro Dalcin int Width = (int)w;
1398067a7d5SLisandro Dalcin int Height = (int)h;
1408067a7d5SLisandro Dalcin int ColorRes = 8;
1418067a7d5SLisandro Dalcin int ColorCount = 256;
1428067a7d5SLisandro Dalcin ColorMapObject *GifCMap = NULL;
1438067a7d5SLisandro Dalcin GifFileType *GifFile = NULL;
14498921bdaSJacob Faibussowitsch #define SETERRGIF(msg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg ", GIF file: %s", filename)
1459371c9d4SSatish Balay #define PetscCallGIF(msg, ...) \
1469371c9d4SSatish Balay do { \
1479566063dSJacob Faibussowitsch int Error = __VA_ARGS__; \
1489566063dSJacob Faibussowitsch if (PetscUnlikely(Error != GIF_OK)) SETERRGIF(msg); \
1499566063dSJacob Faibussowitsch } while (0)
1508067a7d5SLisandro Dalcin
1518067a7d5SLisandro Dalcin PetscFunctionBegin;
1524f572ea9SToby Isaac PetscAssertPointer(filename, 1);
1534f572ea9SToby Isaac PetscAssertPointer(palette, 2);
1544f572ea9SToby Isaac PetscAssertPointer(pixels, 5);
1558067a7d5SLisandro Dalcin
1569371c9d4SSatish Balay GifCMap = GifMakeMapObject(ColorCount, (GifColorType *)palette);
1579371c9d4SSatish Balay if (!GifCMap) SETERRGIF("Allocating colormap");
1589371c9d4SSatish Balay GifFile = EGifOpenFileName(filename, 0, NULL);
1599371c9d4SSatish Balay if (!GifFile) SETERRGIF("Opening");
1609566063dSJacob Faibussowitsch PetscCallGIF("Writing screen descriptor", EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap));
1619566063dSJacob Faibussowitsch PetscCallGIF("Writing image descriptor", EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL));
16248a46eb9SPierre Jolivet for (Row = 0; Row < Height; Row++) PetscCallGIF("Writing image pixels", EGifPutLine(GifFile, (GifPixelType *)pixels + Row * Width, Width));
1639566063dSJacob Faibussowitsch PetscCallGIF("Closing", EGifCloseFile(GifFile, NULL));
1649371c9d4SSatish Balay GifFreeMapObject(GifCMap);
1659371c9d4SSatish Balay GifCMap = NULL;
1668067a7d5SLisandro Dalcin
1678067a7d5SLisandro Dalcin #undef SETERRGIF
1688067a7d5SLisandro Dalcin #undef CHKERRGIF
1693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1708067a7d5SLisandro Dalcin }
1718067a7d5SLisandro Dalcin
PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])172d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDrawImageSave_GIF(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
173d71ae5a4SJacob Faibussowitsch {
1749371c9d4SSatish Balay return PetscDrawImageSaveGIF(filename, palette, w, h, pixels);
1759371c9d4SSatish Balay }
1768067a7d5SLisandro Dalcin
PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])177d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[], PetscInt count, const char movie[])
178d71ae5a4SJacob Faibussowitsch {
17975c73fc3SLisandro Dalcin int i, j, Row;
18075c73fc3SLisandro Dalcin char image[PETSC_MAX_PATH_LEN];
18175c73fc3SLisandro Dalcin GifFileType *GifMovie = NULL;
18275c73fc3SLisandro Dalcin GifFileType *GifImage = NULL;
18398921bdaSJacob Faibussowitsch #define SETERRGIF(msg, fn) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg " GIF file %s", fn)
18475c73fc3SLisandro Dalcin
18575c73fc3SLisandro Dalcin PetscFunctionBegin;
1864f572ea9SToby Isaac PetscAssertPointer(pattern, 1);
1874f572ea9SToby Isaac PetscAssertPointer(movie, 3);
1883ba16761SJacob Faibussowitsch if (count < 1) PetscFunctionReturn(PETSC_SUCCESS);
18975c73fc3SLisandro Dalcin
19075c73fc3SLisandro Dalcin for (i = 0; i < count; i++) {
1919566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(image, sizeof(image), pattern, (int)i));
19275c73fc3SLisandro Dalcin /* open and read image file */
19375c73fc3SLisandro Dalcin if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input", image);
19475c73fc3SLisandro Dalcin if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input", image);
19575c73fc3SLisandro Dalcin /* open movie file and write header */
19675c73fc3SLisandro Dalcin if (i == 0) {
19775c73fc3SLisandro Dalcin if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output", movie);
1989371c9d4SSatish Balay if (EGifPutScreenDesc(GifMovie, GifImage->SWidth, GifImage->SHeight, GifImage->SColorResolution, GifImage->SBackGroundColor, GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,", movie);
19975c73fc3SLisandro Dalcin }
20075c73fc3SLisandro Dalcin /* loop over all frames in image */
20175c73fc3SLisandro Dalcin for (j = 0; j < GifImage->ImageCount; j++) {
20275c73fc3SLisandro Dalcin SavedImage *sp = &GifImage->SavedImages[j];
20375c73fc3SLisandro Dalcin GifImageDesc *GifFrame = &sp->ImageDesc;
20475c73fc3SLisandro Dalcin ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
2059371c9d4SSatish Balay if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount && !memcmp(GifMovie->SColorMap->Colors, FrameColorMap->Colors, (size_t)FrameColorMap->ColorCount * sizeof(GifColorType))) FrameColorMap = NULL;
20675c73fc3SLisandro Dalcin /* add frame to movie */
2079371c9d4SSatish Balay if (EGifPutImageDesc(GifMovie, GifFrame->Left, GifFrame->Top, GifFrame->Width, GifFrame->Height, GifFrame->Interlace, FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,", movie);
20875c73fc3SLisandro Dalcin for (Row = 0; Row < GifFrame->Height; Row++) {
2099371c9d4SSatish Balay if (EGifPutLine(GifMovie, sp->RasterBits + Row * GifFrame->Width, GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,", movie);
21075c73fc3SLisandro Dalcin }
21175c73fc3SLisandro Dalcin }
21275c73fc3SLisandro Dalcin if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input", image);
21375c73fc3SLisandro Dalcin }
21475c73fc3SLisandro Dalcin if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output", movie);
21575c73fc3SLisandro Dalcin
21675c73fc3SLisandro Dalcin #undef SETERRGIF
2173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
21875c73fc3SLisandro Dalcin }
21975c73fc3SLisandro Dalcin
2208067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_GIFLIB*/
2218067a7d5SLisandro Dalcin
2228067a7d5SLisandro Dalcin /*
2238067a7d5SLisandro Dalcin Code to write images in JPEG format
2248067a7d5SLisandro Dalcin */
2258067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
2268067a7d5SLisandro Dalcin
2278067a7d5SLisandro Dalcin #include <jpeglib.h>
2288067a7d5SLisandro Dalcin
2298067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2308067a7d5SLisandro Dalcin #include <setjmp.h>
2318067a7d5SLisandro Dalcin static jmp_buf petsc_jpeg_jumpbuf;
petsc_jpeg_error_longjmp(j_common_ptr cinfo)232d71ae5a4SJacob Faibussowitsch static void petsc_jpeg_error_longjmp(j_common_ptr cinfo)
233d71ae5a4SJacob Faibussowitsch {
2349371c9d4SSatish Balay (void)cinfo;
2359371c9d4SSatish Balay longjmp(petsc_jpeg_jumpbuf, 1);
2369371c9d4SSatish Balay }
2378067a7d5SLisandro Dalcin #endif
2388067a7d5SLisandro Dalcin
PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])239d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
240d71ae5a4SJacob Faibussowitsch {
2418067a7d5SLisandro Dalcin unsigned char *rgbpixels;
2428067a7d5SLisandro Dalcin FILE *fp;
2438067a7d5SLisandro Dalcin struct jpeg_compress_struct cinfo;
2448067a7d5SLisandro Dalcin struct jpeg_error_mgr jerr;
2458067a7d5SLisandro Dalcin
2468067a7d5SLisandro Dalcin PetscFunctionBegin;
2474f572ea9SToby Isaac PetscAssertPointer(filename, 1);
2484f572ea9SToby Isaac if (palette) PetscAssertPointer(palette, 2);
2494f572ea9SToby Isaac PetscAssertPointer(pixels, 5);
2508067a7d5SLisandro Dalcin /* map pixels to RGB colors */
2518067a7d5SLisandro Dalcin if (palette) {
2528067a7d5SLisandro Dalcin int k, p, n = (int)(w * h);
2538067a7d5SLisandro Dalcin const unsigned char *colordef;
2549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3 * w * h, &rgbpixels));
2558067a7d5SLisandro Dalcin for (k = p = 0; k < n; k++) {
2568067a7d5SLisandro Dalcin colordef = palette[pixels[k]];
2578067a7d5SLisandro Dalcin rgbpixels[p++] = colordef[0];
2588067a7d5SLisandro Dalcin rgbpixels[p++] = colordef[1];
2598067a7d5SLisandro Dalcin rgbpixels[p++] = colordef[2];
2608067a7d5SLisandro Dalcin }
2618067a7d5SLisandro Dalcin } else { /* assume pixels are RGB colors */
2628067a7d5SLisandro Dalcin rgbpixels = (unsigned char *)pixels;
2638067a7d5SLisandro Dalcin }
2649566063dSJacob Faibussowitsch PetscCall(PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp));
2658067a7d5SLisandro Dalcin
2668067a7d5SLisandro Dalcin cinfo.err = jpeg_std_error(&jerr);
2678067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2688067a7d5SLisandro Dalcin jerr.error_exit = petsc_jpeg_error_longjmp;
2698067a7d5SLisandro Dalcin if (setjmp(petsc_jpeg_jumpbuf)) {
2708067a7d5SLisandro Dalcin char message[JMSG_LENGTH_MAX];
2718067a7d5SLisandro Dalcin jerr.format_message((j_common_ptr)&cinfo, message);
2728067a7d5SLisandro Dalcin jpeg_destroy_compress(&cinfo);
2738067a7d5SLisandro Dalcin (void)PetscFClose(PETSC_COMM_SELF, fp);
27498921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing JPEG file %s\n%s", filename, message);
2758067a7d5SLisandro Dalcin }
2768067a7d5SLisandro Dalcin #endif
2778067a7d5SLisandro Dalcin jpeg_create_compress(&cinfo);
2788067a7d5SLisandro Dalcin jpeg_stdio_dest(&cinfo, fp);
2798067a7d5SLisandro Dalcin cinfo.image_width = w;
2808067a7d5SLisandro Dalcin cinfo.image_height = h;
2818067a7d5SLisandro Dalcin cinfo.input_components = 3;
2828067a7d5SLisandro Dalcin cinfo.in_color_space = JCS_RGB;
2838067a7d5SLisandro Dalcin jpeg_set_defaults(&cinfo);
2848067a7d5SLisandro Dalcin jpeg_start_compress(&cinfo, TRUE);
2858067a7d5SLisandro Dalcin while (cinfo.next_scanline < cinfo.image_height) {
2868067a7d5SLisandro Dalcin unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3 * w;
2878067a7d5SLisandro Dalcin (void)jpeg_write_scanlines(&cinfo, &rowptr, 1);
2888067a7d5SLisandro Dalcin }
2898067a7d5SLisandro Dalcin jpeg_finish_compress(&cinfo);
2908067a7d5SLisandro Dalcin jpeg_destroy_compress(&cinfo);
2918067a7d5SLisandro Dalcin
2929566063dSJacob Faibussowitsch PetscCall(PetscFClose(PETSC_COMM_SELF, fp));
2939566063dSJacob Faibussowitsch if (palette) PetscCall(PetscFree(rgbpixels));
2943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2958067a7d5SLisandro Dalcin }
2968067a7d5SLisandro Dalcin
PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])297d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDrawImageSave_JPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
298d71ae5a4SJacob Faibussowitsch {
2999371c9d4SSatish Balay return PetscDrawImageSaveJPG(filename, palette, w, h, pixels);
3009371c9d4SSatish Balay }
3018067a7d5SLisandro Dalcin
3028067a7d5SLisandro Dalcin #endif /*!PETSC_HAVE_LIBJPEG*/
3038067a7d5SLisandro Dalcin
3048067a7d5SLisandro Dalcin static struct {
3058067a7d5SLisandro Dalcin const char *extension;
3068067a7d5SLisandro Dalcin PetscErrorCode (*SaveImage)(const char[], unsigned char[][3], unsigned int, unsigned int, const unsigned char[]);
3078067a7d5SLisandro Dalcin } PetscDrawImageSaveTable[] = {
3088067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBPNG)
3098067a7d5SLisandro Dalcin {".png", PetscDrawImageSave_PNG},
3108067a7d5SLisandro Dalcin #endif
3118067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
3128067a7d5SLisandro Dalcin {".gif", PetscDrawImageSave_GIF},
3138067a7d5SLisandro Dalcin #endif
3148067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
3158067a7d5SLisandro Dalcin {".jpg", PetscDrawImageSave_JPG},
3168067a7d5SLisandro Dalcin #endif
3178067a7d5SLisandro Dalcin {".ppm", PetscDrawImageSave_PPM}
3188067a7d5SLisandro Dalcin };
3198067a7d5SLisandro Dalcin
PetscDrawImageCheckFormat(const char * ext[])320d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
321d71ae5a4SJacob Faibussowitsch {
3228067a7d5SLisandro Dalcin size_t k;
3238067a7d5SLisandro Dalcin PetscBool match = PETSC_FALSE;
3248067a7d5SLisandro Dalcin
3258067a7d5SLisandro Dalcin PetscFunctionBegin;
3268067a7d5SLisandro Dalcin /* if extension is empty, return default format to caller */
3274f572ea9SToby Isaac PetscAssertPointer(ext, 1);
3288067a7d5SLisandro Dalcin if (!*ext || !**ext) {
3298067a7d5SLisandro Dalcin *ext = PetscDrawImageSaveTable[0].extension;
3303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3318067a7d5SLisandro Dalcin }
332a9db196aSBarry Smith /* check the extension matches a supported format */
3334f572ea9SToby Isaac PetscAssertPointer(*ext, 1);
334dd39110bSPierre Jolivet for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
3359566063dSJacob Faibussowitsch PetscCall(PetscStrcasecmp(*ext, PetscDrawImageSaveTable[k].extension, &match));
3363ba16761SJacob Faibussowitsch if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(PETSC_SUCCESS);
3378067a7d5SLisandro Dalcin }
33898921bdaSJacob 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);
3398067a7d5SLisandro Dalcin }
3408067a7d5SLisandro Dalcin
PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])341d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDrawImageSave(const char basename[], const char ext[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
342d71ae5a4SJacob Faibussowitsch {
3438067a7d5SLisandro Dalcin size_t k;
3448067a7d5SLisandro Dalcin PetscBool match = PETSC_FALSE;
3458067a7d5SLisandro Dalcin char filename[PETSC_MAX_PATH_LEN];
3468067a7d5SLisandro Dalcin
3478067a7d5SLisandro Dalcin PetscFunctionBegin;
3484f572ea9SToby Isaac PetscAssertPointer(basename, 1);
3494f572ea9SToby Isaac if (ext) PetscAssertPointer(ext, 2);
3504f572ea9SToby Isaac if (palette) PetscAssertPointer(palette, 3);
3514f572ea9SToby Isaac PetscAssertPointer(pixels, 6);
3528067a7d5SLisandro Dalcin
3539566063dSJacob Faibussowitsch PetscCall(PetscDrawImageCheckFormat(&ext));
3549566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(filename, sizeof(filename), "%s%s", basename, ext));
355dd39110bSPierre Jolivet for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
3569566063dSJacob Faibussowitsch PetscCall(PetscStrcasecmp(ext, PetscDrawImageSaveTable[k].extension, &match));
3578067a7d5SLisandro Dalcin if (match && PetscDrawImageSaveTable[k].SaveImage) {
3589566063dSJacob Faibussowitsch PetscCall(PetscDrawImageSaveTable[k].SaveImage(filename, palette, w, h, pixels));
3593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3608067a7d5SLisandro Dalcin }
3618067a7d5SLisandro Dalcin }
36298921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Image extension %s not supported, use .ppm", ext);
3638067a7d5SLisandro Dalcin }
3648067a7d5SLisandro Dalcin
PetscDrawMovieCheckFormat(const char * ext[])365d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
366d71ae5a4SJacob Faibussowitsch {
3678067a7d5SLisandro Dalcin PetscFunctionBegin;
3684f572ea9SToby Isaac PetscAssertPointer(ext, 1);
3698067a7d5SLisandro Dalcin if (!*ext || !**ext) *ext = ".m4v";
3703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3718067a7d5SLisandro Dalcin }
3728067a7d5SLisandro Dalcin
PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])373d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDrawMovieSave(const char basename[], PetscInt count, const char imext[], PetscInt fps, const char mvext[])
374d71ae5a4SJacob Faibussowitsch {
37575c73fc3SLisandro Dalcin char input[PETSC_MAX_PATH_LEN];
37675c73fc3SLisandro Dalcin char output[PETSC_MAX_PATH_LEN];
37775c73fc3SLisandro Dalcin PetscBool gifinput;
3788067a7d5SLisandro Dalcin
3798067a7d5SLisandro Dalcin PetscFunctionBegin;
3804f572ea9SToby Isaac PetscAssertPointer(basename, 1);
3814f572ea9SToby Isaac PetscAssertPointer(imext, 3);
3824f572ea9SToby Isaac if (mvext) PetscAssertPointer(mvext, 5);
3833ba16761SJacob Faibussowitsch if (count < 1) PetscFunctionReturn(PETSC_SUCCESS);
3848067a7d5SLisandro Dalcin
3859566063dSJacob Faibussowitsch PetscCall(PetscStrcasecmp(imext, ".gif", &gifinput));
3869566063dSJacob Faibussowitsch PetscCall(PetscDrawMovieCheckFormat(&mvext));
3879566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(input, sizeof(input), "%s/%s_%%d%s", basename, basename, imext));
3889566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(output, sizeof(output), "%s%s", basename, mvext));
38975c73fc3SLisandro Dalcin
39075c73fc3SLisandro Dalcin /* use GIFLIB to generate an intermediate GIF animation */
39175c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
39275c73fc3SLisandro Dalcin if (gifinput) {
39375c73fc3SLisandro Dalcin char gifmovie[PETSC_MAX_PATH_LEN];
3949566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(gifmovie, sizeof(gifmovie), "%s/%s_movie.gif", basename, basename));
3959566063dSJacob Faibussowitsch PetscCall(PetscDrawMovieSaveGIF(input, count, gifmovie));
396c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(input, gifmovie, sizeof(input)));
3978067a7d5SLisandro Dalcin }
39875c73fc3SLisandro Dalcin #endif
39975c73fc3SLisandro Dalcin
40075c73fc3SLisandro Dalcin /* use FFmpeg to generate a movie */
40175c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_POPEN)
40275c73fc3SLisandro Dalcin {
403016831caSBarry Smith FILE *fd;
40475c73fc3SLisandro Dalcin char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
40575c73fc3SLisandro Dalcin char command[sizeof(options) + sizeof(extraopts) + sizeof(framerate) + PETSC_MAX_PATH_LEN * 2];
406835f2295SStefano Zampini if (fps > 0) PetscCall(PetscSNPrintf(framerate, sizeof(framerate), "-r %" PetscInt_FMT, fps));
40775c73fc3SLisandro Dalcin if (gifinput) {
4089566063dSJacob Faibussowitsch PetscCall(PetscStrlcat(options, " -f gif", sizeof(options)));
409835f2295SStefano Zampini PetscCall(PetscSNPrintf(extraopts, sizeof(extraopts), " -default_delay %" PetscInt_FMT, (fps > 0) ? 100 / fps : 4));
41075c73fc3SLisandro Dalcin } else {
4119566063dSJacob Faibussowitsch PetscCall(PetscStrlcat(options, " -f image2", sizeof(options)));
412835f2295SStefano Zampini if (fps > 0) PetscCall(PetscSNPrintf(extraopts, sizeof(extraopts), " -framerate %" PetscInt_FMT, fps));
41375c73fc3SLisandro Dalcin }
4149566063dSJacob Faibussowitsch if (extraopts[0]) PetscCall(PetscStrlcat(options, extraopts, sizeof(options)));
4159566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(command, sizeof(command), "ffmpeg %s -i \"%s\" %s \"%s\"", options, input, framerate, output));
4169566063dSJacob Faibussowitsch PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", &fd));
4179566063dSJacob Faibussowitsch PetscCall(PetscPClose(PETSC_COMM_SELF, fd));
4188067a7d5SLisandro Dalcin }
4198067a7d5SLisandro Dalcin #endif
4203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4218067a7d5SLisandro Dalcin }
422