xref: /petsc/src/sys/classes/draw/utils/image.c (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
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 */
118067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageSavePPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
128067a7d5SLisandro Dalcin {
138067a7d5SLisandro Dalcin   int            fd;
148067a7d5SLisandro Dalcin   char           header[32];
158067a7d5SLisandro Dalcin   size_t         hdrlen;
168067a7d5SLisandro Dalcin   unsigned char  *rgb;
178067a7d5SLisandro Dalcin 
188067a7d5SLisandro Dalcin   PetscFunctionBegin;
198067a7d5SLisandro Dalcin   PetscValidCharPointer(filename,1);
208067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette,2);
218067a7d5SLisandro Dalcin   PetscValidCharPointer(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;
265f80ce2aSJacob Faibussowitsch     CHKERRQ(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 */
375f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd));
385f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n%c",(int)w,(int)h,'\0'));
395f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlen(header,&hdrlen));
405f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR));
418067a7d5SLisandro Dalcin   /* write image data and close file */
425f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR));
435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBinaryClose(fd));
445f80ce2aSJacob Faibussowitsch   if (palette) CHKERRQ(PetscFree(rgb));
458067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
468067a7d5SLisandro Dalcin }
478067a7d5SLisandro Dalcin 
488067a7d5SLisandro Dalcin static PetscErrorCode PetscDrawImageSave_PPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
498067a7d5SLisandro Dalcin { return PetscDrawImageSavePPM(filename,palette,w,h,pixels); }
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 
648067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
658067a7d5SLisandro Dalcin {
668067a7d5SLisandro Dalcin   FILE           *fp;
678067a7d5SLisandro Dalcin   png_struct     *png_ptr;
688067a7d5SLisandro Dalcin   png_info       *info_ptr;
698067a7d5SLisandro Dalcin   unsigned int   row, stride = palette ? w : 3*w;
708067a7d5SLisandro Dalcin 
718067a7d5SLisandro Dalcin   PetscFunctionBegin;
728067a7d5SLisandro Dalcin   PetscValidCharPointer(filename,1);
738067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette,2);
748067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels,5);
758067a7d5SLisandro Dalcin 
768067a7d5SLisandro Dalcin   /* open file and create libpng structures */
775f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp));
788067a7d5SLisandro Dalcin   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
79*28b400f6SJacob Faibussowitsch   PetscCheck(png_ptr,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
808067a7d5SLisandro Dalcin   info_ptr = png_create_info_struct(png_ptr);
81*28b400f6SJacob Faibussowitsch   PetscCheck(info_ptr,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
828067a7d5SLisandro Dalcin 
838067a7d5SLisandro Dalcin   /* setup libpng error handling */
848067a7d5SLisandro Dalcin #if defined(PNG_SETJMP_SUPPORTED)
858067a7d5SLisandro Dalcin   if (setjmp(png_jmpbuf(png_ptr))) {
868067a7d5SLisandro Dalcin     png_destroy_write_struct(&png_ptr,&info_ptr);
878067a7d5SLisandro Dalcin     (void)PetscFClose(PETSC_COMM_SELF,fp);
8898921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
898067a7d5SLisandro Dalcin   }
908067a7d5SLisandro Dalcin #endif
918067a7d5SLisandro Dalcin 
928067a7d5SLisandro Dalcin   /* setup PNG image metadata */
938067a7d5SLisandro Dalcin   png_init_io(png_ptr, fp);
948067a7d5SLisandro Dalcin   png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
958067a7d5SLisandro Dalcin                palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
968067a7d5SLisandro Dalcin                PNG_INTERLACE_NONE,
978067a7d5SLisandro Dalcin                PNG_COMPRESSION_TYPE_DEFAULT,
988067a7d5SLisandro Dalcin                PNG_FILTER_TYPE_DEFAULT);
998067a7d5SLisandro Dalcin   if (palette)
1008067a7d5SLisandro Dalcin     png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);
1018067a7d5SLisandro Dalcin 
1028067a7d5SLisandro Dalcin   /* write PNG image header and data */
1038067a7d5SLisandro Dalcin   png_write_info(png_ptr, info_ptr);
1048067a7d5SLisandro Dalcin   for (row = 0; row < h; row++)
1058067a7d5SLisandro Dalcin     png_write_row(png_ptr, pixels + row*stride);
1068067a7d5SLisandro Dalcin   png_write_end(png_ptr, NULL);
1078067a7d5SLisandro Dalcin 
1088067a7d5SLisandro Dalcin   /* destroy libpng structures and close file */
1098067a7d5SLisandro Dalcin   png_destroy_write_struct(&png_ptr, &info_ptr);
1105f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFClose(PETSC_COMM_SELF,fp));
1118067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
1128067a7d5SLisandro Dalcin }
1138067a7d5SLisandro Dalcin 
1148067a7d5SLisandro Dalcin static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
1158067a7d5SLisandro Dalcin { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }
1168067a7d5SLisandro Dalcin 
1178067a7d5SLisandro Dalcin #endif/*!PETSC_HAVE_LIBPNG*/
1188067a7d5SLisandro Dalcin 
1198067a7d5SLisandro Dalcin /*
1208067a7d5SLisandro Dalcin    Code to write images in GIF format
1218067a7d5SLisandro Dalcin */
1228067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
1238067a7d5SLisandro Dalcin 
1248067a7d5SLisandro Dalcin #include <gif_lib.h>
1258067a7d5SLisandro Dalcin 
1268067a7d5SLisandro Dalcin #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
1278067a7d5SLisandro Dalcin #define GifMakeMapObject          MakeMapObject
1288067a7d5SLisandro Dalcin #define GifFreeMapObject          FreeMapObject
1298067a7d5SLisandro Dalcin #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
1308067a7d5SLisandro Dalcin #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
1318067a7d5SLisandro Dalcin #define EGifCloseFile(f,err)      EGifCloseFile(f)
13275c73fc3SLisandro Dalcin #define DGifOpenFileName(n,err)   DGifOpenFileName(n)
13375c73fc3SLisandro Dalcin #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
13475c73fc3SLisandro Dalcin #define DGifCloseFile(f,err)      DGifCloseFile(f)
1358067a7d5SLisandro Dalcin #endif
1368067a7d5SLisandro Dalcin 
1378067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
1388067a7d5SLisandro Dalcin {
1398067a7d5SLisandro Dalcin   int            Row, Error;
1408067a7d5SLisandro Dalcin   int            Width  = (int)w;
1418067a7d5SLisandro Dalcin   int            Height = (int)h;
1428067a7d5SLisandro Dalcin   int            ColorRes   = 8;
1438067a7d5SLisandro Dalcin   int            ColorCount = 256;
1448067a7d5SLisandro Dalcin   ColorMapObject *GifCMap = NULL;
1458067a7d5SLisandro Dalcin   GifFileType    *GifFile = NULL;
14698921bdaSJacob Faibussowitsch # define         SETERRGIF(msg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
1478067a7d5SLisandro Dalcin # define         CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while (0)
1488067a7d5SLisandro Dalcin 
1498067a7d5SLisandro Dalcin   PetscFunctionBegin;
1508067a7d5SLisandro Dalcin   PetscValidCharPointer(filename,1);
1518067a7d5SLisandro Dalcin   PetscValidCharPointer(palette,2);
1528067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels,5);
1538067a7d5SLisandro Dalcin 
1548067a7d5SLisandro Dalcin   GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
1558067a7d5SLisandro Dalcin   GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
1568067a7d5SLisandro Dalcin   Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
1578067a7d5SLisandro Dalcin   Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
1588067a7d5SLisandro Dalcin   for (Row = 0; Row < Height; Row++) {
1598067a7d5SLisandro Dalcin     Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
1608067a7d5SLisandro Dalcin   }
1618067a7d5SLisandro Dalcin   Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
1628067a7d5SLisandro Dalcin   GifFreeMapObject(GifCMap); GifCMap = NULL;
1638067a7d5SLisandro Dalcin 
1648067a7d5SLisandro Dalcin # undef SETERRGIF
1658067a7d5SLisandro Dalcin # undef CHKERRGIF
1668067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
1678067a7d5SLisandro Dalcin }
1688067a7d5SLisandro Dalcin 
1698067a7d5SLisandro Dalcin static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
1708067a7d5SLisandro Dalcin { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
1718067a7d5SLisandro Dalcin 
17275c73fc3SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
17375c73fc3SLisandro Dalcin {
17475c73fc3SLisandro Dalcin   int            i,j,Row;
17575c73fc3SLisandro Dalcin   char           image[PETSC_MAX_PATH_LEN];
17675c73fc3SLisandro Dalcin   GifFileType    *GifMovie = NULL;
17775c73fc3SLisandro Dalcin   GifFileType    *GifImage = NULL;
17898921bdaSJacob Faibussowitsch # define         SETERRGIF(msg,fn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)
17975c73fc3SLisandro Dalcin 
18075c73fc3SLisandro Dalcin   PetscFunctionBegin;
18175c73fc3SLisandro Dalcin   PetscValidCharPointer(pattern,1);
18275c73fc3SLisandro Dalcin   PetscValidCharPointer(movie,3);
18375c73fc3SLisandro Dalcin   if (count < 1) PetscFunctionReturn(0);
18475c73fc3SLisandro Dalcin 
18575c73fc3SLisandro Dalcin   for (i = 0; i < count; i++) {
1865f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSNPrintf(image,sizeof(image),pattern,(int)i));
18775c73fc3SLisandro Dalcin     /* open and read image file */
18875c73fc3SLisandro Dalcin     if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
18975c73fc3SLisandro Dalcin     if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
19075c73fc3SLisandro Dalcin     /* open movie file and write header */
19175c73fc3SLisandro Dalcin     if (i == 0) {
19275c73fc3SLisandro Dalcin       if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
19375c73fc3SLisandro Dalcin       if (EGifPutScreenDesc(GifMovie,
19475c73fc3SLisandro Dalcin                             GifImage->SWidth,
19575c73fc3SLisandro Dalcin                             GifImage->SHeight,
19675c73fc3SLisandro Dalcin                             GifImage->SColorResolution,
19775c73fc3SLisandro Dalcin                             GifImage->SBackGroundColor,
19875c73fc3SLisandro Dalcin                             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;
20575c73fc3SLisandro Dalcin       if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
20675c73fc3SLisandro Dalcin           !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
20775c73fc3SLisandro Dalcin                   (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
20875c73fc3SLisandro Dalcin         FrameColorMap = NULL;
20975c73fc3SLisandro Dalcin       /* add frame to movie */
21075c73fc3SLisandro Dalcin       if (EGifPutImageDesc(GifMovie,
21175c73fc3SLisandro Dalcin                            GifFrame->Left,
21275c73fc3SLisandro Dalcin                            GifFrame->Top,
21375c73fc3SLisandro Dalcin                            GifFrame->Width,
21475c73fc3SLisandro Dalcin                            GifFrame->Height,
21575c73fc3SLisandro Dalcin                            GifFrame->Interlace,
21675c73fc3SLisandro Dalcin                            FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
21775c73fc3SLisandro Dalcin       for (Row = 0; Row < GifFrame->Height; Row++) {
21875c73fc3SLisandro Dalcin         if (EGifPutLine(GifMovie,
21975c73fc3SLisandro Dalcin                         sp->RasterBits + Row * GifFrame->Width,
22075c73fc3SLisandro Dalcin                         GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
22175c73fc3SLisandro Dalcin       }
22275c73fc3SLisandro Dalcin     }
22375c73fc3SLisandro Dalcin     if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
22475c73fc3SLisandro Dalcin   }
22575c73fc3SLisandro Dalcin   if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);
22675c73fc3SLisandro Dalcin 
22775c73fc3SLisandro Dalcin # undef SETERRGIF
22875c73fc3SLisandro Dalcin   PetscFunctionReturn(0);
22975c73fc3SLisandro Dalcin }
23075c73fc3SLisandro Dalcin 
2318067a7d5SLisandro Dalcin #endif/*!PETSC_HAVE_GIFLIB*/
2328067a7d5SLisandro Dalcin 
2338067a7d5SLisandro Dalcin /*
2348067a7d5SLisandro Dalcin    Code to write images in JPEG format
2358067a7d5SLisandro Dalcin */
2368067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
2378067a7d5SLisandro Dalcin 
2388067a7d5SLisandro Dalcin #include <jpeglib.h>
2398067a7d5SLisandro Dalcin 
2408067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2418067a7d5SLisandro Dalcin #include <setjmp.h>
2428067a7d5SLisandro Dalcin static jmp_buf petsc_jpeg_jumpbuf;
2438067a7d5SLisandro Dalcin static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
2448067a7d5SLisandro Dalcin #endif
2458067a7d5SLisandro Dalcin 
2468067a7d5SLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
2478067a7d5SLisandro Dalcin {
2488067a7d5SLisandro Dalcin   unsigned char               *rgbpixels;
2498067a7d5SLisandro Dalcin   FILE                        *fp;
2508067a7d5SLisandro Dalcin   struct jpeg_compress_struct cinfo;
2518067a7d5SLisandro Dalcin   struct jpeg_error_mgr       jerr;
2528067a7d5SLisandro Dalcin 
2538067a7d5SLisandro Dalcin   PetscFunctionBegin;
2548067a7d5SLisandro Dalcin   PetscValidCharPointer(filename,1);
2558067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette,2);
2568067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels,5);
2578067a7d5SLisandro Dalcin   /* map pixels to RGB colors */
2588067a7d5SLisandro Dalcin   if (palette) {
2598067a7d5SLisandro Dalcin     int k,p,n = (int)(w*h);
2608067a7d5SLisandro Dalcin     const unsigned char *colordef;
2615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(3*w*h,&rgbpixels));
2628067a7d5SLisandro Dalcin     for (k=p=0; k<n; k++) {
2638067a7d5SLisandro Dalcin       colordef = palette[pixels[k]];
2648067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[0];
2658067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[1];
2668067a7d5SLisandro Dalcin       rgbpixels[p++] = colordef[2];
2678067a7d5SLisandro Dalcin     }
2688067a7d5SLisandro Dalcin   } else { /* assume pixels are RGB colors */
2698067a7d5SLisandro Dalcin     rgbpixels = (unsigned char*)pixels;
2708067a7d5SLisandro Dalcin   }
2715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp));
2728067a7d5SLisandro Dalcin 
2738067a7d5SLisandro Dalcin   cinfo.err = jpeg_std_error(&jerr);
2748067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_SETJMP_H)
2758067a7d5SLisandro Dalcin   jerr.error_exit = petsc_jpeg_error_longjmp;
2768067a7d5SLisandro Dalcin   if (setjmp(petsc_jpeg_jumpbuf)) {
2778067a7d5SLisandro Dalcin     char message[JMSG_LENGTH_MAX];
2788067a7d5SLisandro Dalcin     jerr.format_message((j_common_ptr)&cinfo,message);
2798067a7d5SLisandro Dalcin     jpeg_destroy_compress(&cinfo);
2808067a7d5SLisandro Dalcin     (void)PetscFClose(PETSC_COMM_SELF,fp);
28198921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
2828067a7d5SLisandro Dalcin   }
2838067a7d5SLisandro Dalcin #endif
2848067a7d5SLisandro Dalcin   jpeg_create_compress(&cinfo);
2858067a7d5SLisandro Dalcin   jpeg_stdio_dest(&cinfo,fp);
2868067a7d5SLisandro Dalcin   cinfo.image_width      = w;
2878067a7d5SLisandro Dalcin   cinfo.image_height     = h;
2888067a7d5SLisandro Dalcin   cinfo.input_components = 3;
2898067a7d5SLisandro Dalcin   cinfo.in_color_space   = JCS_RGB;
2908067a7d5SLisandro Dalcin   jpeg_set_defaults(&cinfo);
2918067a7d5SLisandro Dalcin   jpeg_start_compress(&cinfo,TRUE);
2928067a7d5SLisandro Dalcin   while (cinfo.next_scanline < cinfo.image_height) {
2938067a7d5SLisandro Dalcin     unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
2948067a7d5SLisandro Dalcin     (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
2958067a7d5SLisandro Dalcin   }
2968067a7d5SLisandro Dalcin   jpeg_finish_compress(&cinfo);
2978067a7d5SLisandro Dalcin   jpeg_destroy_compress(&cinfo);
2988067a7d5SLisandro Dalcin 
2995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFClose(PETSC_COMM_SELF,fp));
3005f80ce2aSJacob Faibussowitsch   if (palette) CHKERRQ(PetscFree(rgbpixels));
3018067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
3028067a7d5SLisandro Dalcin }
3038067a7d5SLisandro Dalcin 
3048067a7d5SLisandro Dalcin static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
3058067a7d5SLisandro Dalcin { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
3068067a7d5SLisandro Dalcin 
3078067a7d5SLisandro Dalcin #endif/*!PETSC_HAVE_LIBJPEG*/
3088067a7d5SLisandro Dalcin 
3098067a7d5SLisandro Dalcin static struct {
3108067a7d5SLisandro Dalcin   const char      *extension;
3118067a7d5SLisandro Dalcin   PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
3128067a7d5SLisandro Dalcin } PetscDrawImageSaveTable[] = {
3138067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBPNG)
3148067a7d5SLisandro Dalcin   {".png", PetscDrawImageSave_PNG},
3158067a7d5SLisandro Dalcin #endif
3168067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
3178067a7d5SLisandro Dalcin   {".gif", PetscDrawImageSave_GIF},
3188067a7d5SLisandro Dalcin #endif
3198067a7d5SLisandro Dalcin #if defined(PETSC_HAVE_LIBJPEG)
3208067a7d5SLisandro Dalcin   {".jpg", PetscDrawImageSave_JPG},
3218067a7d5SLisandro Dalcin #endif
3228067a7d5SLisandro Dalcin   {".ppm", PetscDrawImageSave_PPM}
3238067a7d5SLisandro Dalcin };
3248067a7d5SLisandro Dalcin 
3258067a7d5SLisandro Dalcin PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
3268067a7d5SLisandro Dalcin {
3278067a7d5SLisandro Dalcin   size_t         k;
3288067a7d5SLisandro Dalcin   PetscBool      match = PETSC_FALSE;
3298067a7d5SLisandro Dalcin 
3308067a7d5SLisandro Dalcin   PetscFunctionBegin;
3318067a7d5SLisandro Dalcin   /* if extension is empty, return default format to caller */
3328067a7d5SLisandro Dalcin   PetscValidPointer(ext,1);
3338067a7d5SLisandro Dalcin   if (!*ext || !**ext) {
3348067a7d5SLisandro Dalcin     *ext = PetscDrawImageSaveTable[0].extension;
3358067a7d5SLisandro Dalcin     PetscFunctionReturn(0);
3368067a7d5SLisandro Dalcin   }
337a9db196aSBarry Smith   /* check the extension matches a supported format */
3388067a7d5SLisandro Dalcin   PetscValidCharPointer(*ext,1);
3398067a7d5SLisandro Dalcin   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
3405f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match));
3418067a7d5SLisandro Dalcin     if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(0);
3428067a7d5SLisandro Dalcin   }
34398921bdaSJacob 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);
3448067a7d5SLisandro Dalcin }
3458067a7d5SLisandro Dalcin 
3468067a7d5SLisandro Dalcin PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
3478067a7d5SLisandro Dalcin {
3488067a7d5SLisandro Dalcin   size_t         k;
3498067a7d5SLisandro Dalcin   PetscBool      match = PETSC_FALSE;
3508067a7d5SLisandro Dalcin   char           filename[PETSC_MAX_PATH_LEN];
3518067a7d5SLisandro Dalcin 
3528067a7d5SLisandro Dalcin   PetscFunctionBegin;
3538067a7d5SLisandro Dalcin   PetscValidCharPointer(basename,1);
3548067a7d5SLisandro Dalcin   if (ext) PetscValidCharPointer(ext,2);
3558067a7d5SLisandro Dalcin   if (palette) PetscValidCharPointer(palette,3);
3568067a7d5SLisandro Dalcin   PetscValidCharPointer(pixels,6);
3578067a7d5SLisandro Dalcin 
3585f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDrawImageCheckFormat(&ext));
3595f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext));
3608067a7d5SLisandro Dalcin   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
3615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match));
3628067a7d5SLisandro Dalcin     if (match && PetscDrawImageSaveTable[k].SaveImage) {
3635f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels));
3648067a7d5SLisandro Dalcin       PetscFunctionReturn(0);
3658067a7d5SLisandro Dalcin     }
3668067a7d5SLisandro Dalcin   }
36798921bdaSJacob Faibussowitsch   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
3688067a7d5SLisandro Dalcin }
3698067a7d5SLisandro Dalcin 
3708067a7d5SLisandro Dalcin PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
3718067a7d5SLisandro Dalcin {
3728067a7d5SLisandro Dalcin   PetscFunctionBegin;
3738067a7d5SLisandro Dalcin   PetscValidPointer(ext,1);
3748067a7d5SLisandro Dalcin   if (!*ext || !**ext) *ext = ".m4v";
3758067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
3768067a7d5SLisandro Dalcin }
3778067a7d5SLisandro Dalcin 
3783d242201SLisandro Dalcin PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
3798067a7d5SLisandro Dalcin {
38075c73fc3SLisandro Dalcin   char           input[PETSC_MAX_PATH_LEN];
38175c73fc3SLisandro Dalcin   char           output[PETSC_MAX_PATH_LEN];
38275c73fc3SLisandro Dalcin   PetscBool      gifinput;
3838067a7d5SLisandro Dalcin 
3848067a7d5SLisandro Dalcin   PetscFunctionBegin;
3858067a7d5SLisandro Dalcin   PetscValidCharPointer(basename,1);
3868067a7d5SLisandro Dalcin   PetscValidCharPointer(imext,3);
387064a246eSJacob Faibussowitsch   if (mvext) PetscValidCharPointer(mvext,5);
3888067a7d5SLisandro Dalcin   if (count < 1) PetscFunctionReturn(0);
3898067a7d5SLisandro Dalcin 
3905f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcasecmp(imext,".gif",&gifinput));
3915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDrawMovieCheckFormat(&mvext));
3925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext));
3935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext));
39475c73fc3SLisandro Dalcin 
39575c73fc3SLisandro Dalcin   /* use GIFLIB to generate an intermediate GIF animation */
39675c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_GIFLIB)
39775c73fc3SLisandro Dalcin   if (gifinput) {
39875c73fc3SLisandro Dalcin     char gifmovie[PETSC_MAX_PATH_LEN];
3995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename));
4005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDrawMovieSaveGIF(input,count,gifmovie));
4015f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcpy(input,gifmovie));
4028067a7d5SLisandro Dalcin   }
40375c73fc3SLisandro Dalcin #endif
40475c73fc3SLisandro Dalcin 
40575c73fc3SLisandro Dalcin   /* use FFmpeg to generate a movie */
40675c73fc3SLisandro Dalcin #if defined(PETSC_HAVE_POPEN)
40775c73fc3SLisandro Dalcin   {
408016831caSBarry Smith     FILE *fd;
40975c73fc3SLisandro Dalcin     char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
41075c73fc3SLisandro Dalcin     char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
4115f80ce2aSJacob Faibussowitsch     if (fps > 0) CHKERRQ(PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps));
41275c73fc3SLisandro Dalcin     if (gifinput) {
4135f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(options," -f gif",sizeof(options)));
4145f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4));
41575c73fc3SLisandro Dalcin     } else {
4165f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(options," -f image2",sizeof(options)));
4175f80ce2aSJacob Faibussowitsch       if (fps > 0) CHKERRQ(PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps));
41875c73fc3SLisandro Dalcin     }
4195f80ce2aSJacob Faibussowitsch     if (extraopts[0]) CHKERRQ(PetscStrlcat(options,extraopts,sizeof(options)));
4205f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output));
4215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd));
4225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPClose(PETSC_COMM_SELF,fd));
4238067a7d5SLisandro Dalcin   }
4248067a7d5SLisandro Dalcin #endif
4258067a7d5SLisandro Dalcin   PetscFunctionReturn(0);
4268067a7d5SLisandro Dalcin }
427