Actual source code: image.c
petsc-3.9.4 2018-09-11
1: #include <petsc/private/petscimpl.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: /*
9: Code to write images in PPM format
10: */
11: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
12: {
13: int fd;
14: char header[32];
15: size_t hdrlen;
16: unsigned char *rgb;
23: /* map pixels to RGB colors */
24: if (palette) {
25: int k,p,n = (int)(w*h);
26: const unsigned char *colordef;
27: PetscMalloc1(3*w*h,&rgb);
28: for (k=p=0; k<n; k++) {
29: colordef = palette[pixels[k]];
30: rgb[p++] = colordef[0];
31: rgb[p++] = colordef[1];
32: rgb[p++] = colordef[2];
33: }
34: } else { /* assume pixels are RGB colors */
35: rgb = (unsigned char*)pixels;
36: }
37: /* open file and write PPM header */
38: PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);
39: PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n\0",(int)w,(int)h);
40: PetscStrlen(header,&hdrlen);
41: PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR,PETSC_FALSE);
42: /* write image data and close file */
43: PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR,PETSC_FALSE);
44: PetscBinaryClose(fd);
45: if (palette) {PetscFree(rgb);}
46: return(0);
47: }
49: static PetscErrorCode PetscDrawImageSave_PPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
50: { return PetscDrawImageSavePPM(filename,palette,w,h,pixels); }
53: /*
54: Code to write images in PNG format
55: */
56: #if defined(PETSC_HAVE_LIBPNG)
58: #include <png.h>
60: #if defined(PNG_SETJMP_SUPPORTED)
61: # ifndef png_jmpbuf
62: # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
63: # endif
64: #endif
66: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
67: {
68: FILE *fp;
69: png_struct *png_ptr;
70: png_info *info_ptr;
71: unsigned int row, stride = palette ? w : 3*w;
79: /* open file and create libpng structures */
80: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
81: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
82: if (!png_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
83: info_ptr = png_create_info_struct(png_ptr);
84: if (!info_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
86: /* setup libpng error handling */
87: #if defined(PNG_SETJMP_SUPPORTED)
88: if (setjmp(png_jmpbuf(png_ptr))) {
89: png_destroy_write_struct(&png_ptr,&info_ptr);
90: (void)PetscFClose(PETSC_COMM_SELF,fp);
91: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
92: }
93: #endif
95: /* setup PNG image metadata */
96: png_init_io(png_ptr, fp);
97: png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
98: palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
99: PNG_INTERLACE_NONE,
100: PNG_COMPRESSION_TYPE_DEFAULT,
101: PNG_FILTER_TYPE_DEFAULT);
102: if (palette)
103: png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);
105: /* write PNG image header and data */
106: png_write_info(png_ptr, info_ptr);
107: for (row = 0; row < h; row++)
108: png_write_row(png_ptr, pixels + row*stride);
109: png_write_end(png_ptr, NULL);
111: /* destroy libpng structures and close file */
112: png_destroy_write_struct(&png_ptr, &info_ptr);
113: PetscFClose(PETSC_COMM_SELF,fp);
114: return(0);
115: }
117: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
118: { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }
120: #endif/*!PETSC_HAVE_LIBPNG*/
123: /*
124: Code to write images in GIF format
125: */
126: #if defined(PETSC_HAVE_GIFLIB)
128: #include <gif_lib.h>
130: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
131: #define GifMakeMapObject MakeMapObject
132: #define GifFreeMapObject FreeMapObject
133: #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
134: #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
135: #define EGifCloseFile(f,err) EGifCloseFile(f)
136: #define DGifOpenFileName(n,err) DGifOpenFileName(n)
137: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
138: #define DGifCloseFile(f,err) DGifCloseFile(f)
139: #endif
141: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
142: {
143: int Row, Error;
144: int Width = (int)w;
145: int Height = (int)h;
146: int ColorRes = 8;
147: int ColorCount = 256;
148: ColorMapObject *GifCMap = NULL;
149: GifFileType *GifFile = NULL;
150: # define SETERRGIF(msg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
151: # define CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while(0)
158: GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
159: GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
160: Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
161: Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
162: for (Row = 0; Row < Height; Row++) {
163: Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
164: }
165: Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
166: GifFreeMapObject(GifCMap); GifCMap = NULL;
168: # undef SETERRGIF
169: # undef CHKERRGIF
170: return(0);
171: }
173: static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
174: { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
176: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
177: {
178: int i,j,Row;
179: char image[PETSC_MAX_PATH_LEN];
180: GifFileType *GifMovie = NULL;
181: GifFileType *GifImage = NULL;
183: # define SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)
188: if (count < 1) return(0);
190: for (i = 0; i < count; i++) {
191: PetscSNPrintf(image,sizeof(image),pattern,(int)i);
192: /* open and read image file */
193: if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
194: if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
195: /* open movie file and write header */
196: if (i == 0) {
197: if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
198: if (EGifPutScreenDesc(GifMovie,
199: GifImage->SWidth,
200: GifImage->SHeight,
201: GifImage->SColorResolution,
202: GifImage->SBackGroundColor,
203: GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,",movie);
204: }
205: /* loop over all frames in image */
206: for (j = 0; j < GifImage->ImageCount; j++) {
207: SavedImage *sp = &GifImage->SavedImages[j];
208: GifImageDesc *GifFrame = &sp->ImageDesc;
209: ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
210: if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
211: !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
212: (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
213: FrameColorMap = NULL;
214: /* add frame to movie */
215: if (EGifPutImageDesc(GifMovie,
216: GifFrame->Left,
217: GifFrame->Top,
218: GifFrame->Width,
219: GifFrame->Height,
220: GifFrame->Interlace,
221: FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
222: for (Row = 0; Row < GifFrame->Height; Row++) {
223: if (EGifPutLine(GifMovie,
224: sp->RasterBits + Row * GifFrame->Width,
225: GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
226: }
227: }
228: if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
229: }
230: if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);
232: # undef SETERRGIF
233: return(0);
234: }
236: #endif/*!PETSC_HAVE_GIFLIB*/
238: /*
239: Code to write images in JPEG format
240: */
241: #if defined(PETSC_HAVE_LIBJPEG)
243: #include <jpeglib.h>
245: #if defined(PETSC_HAVE_SETJMP_H)
246: #include <setjmp.h>
247: static jmp_buf petsc_jpeg_jumpbuf;
248: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
249: #endif
251: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
252: {
253: unsigned char *rgbpixels;
254: FILE *fp;
255: struct jpeg_compress_struct cinfo;
256: struct jpeg_error_mgr jerr;
257: PetscErrorCode ierr;
263: /* map pixels to RGB colors */
264: if (palette) {
265: int k,p,n = (int)(w*h);
266: const unsigned char *colordef;
267: PetscMalloc1(3*w*h,&rgbpixels);
268: for (k=p=0; k<n; k++) {
269: colordef = palette[pixels[k]];
270: rgbpixels[p++] = colordef[0];
271: rgbpixels[p++] = colordef[1];
272: rgbpixels[p++] = colordef[2];
273: }
274: } else { /* assume pixels are RGB colors */
275: rgbpixels = (unsigned char*)pixels;
276: }
277: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
279: cinfo.err = jpeg_std_error(&jerr);
280: #if defined(PETSC_HAVE_SETJMP_H)
281: jerr.error_exit = petsc_jpeg_error_longjmp;
282: if (setjmp(petsc_jpeg_jumpbuf)) {
283: char message[JMSG_LENGTH_MAX];
284: jerr.format_message((j_common_ptr)&cinfo,message);
285: jpeg_destroy_compress(&cinfo);
286: (void)PetscFClose(PETSC_COMM_SELF,fp);
287: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
288: }
289: #endif
290: jpeg_create_compress(&cinfo);
291: jpeg_stdio_dest(&cinfo,fp);
292: cinfo.image_width = w;
293: cinfo.image_height = h;
294: cinfo.input_components = 3;
295: cinfo.in_color_space = JCS_RGB;
296: jpeg_set_defaults(&cinfo);
297: jpeg_start_compress(&cinfo,TRUE);
298: while (cinfo.next_scanline < cinfo.image_height) {
299: unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
300: (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
301: }
302: jpeg_finish_compress(&cinfo);
303: jpeg_destroy_compress(&cinfo);
305: PetscFClose(PETSC_COMM_SELF,fp);
306: if (palette) {PetscFree(rgbpixels);}
307: return(0);
308: }
310: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
311: { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
313: #endif/*!PETSC_HAVE_LIBJPEG*/
315: static struct {
316: const char *extension;
317: PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
318: } PetscDrawImageSaveTable[] = {
319: #if defined(PETSC_HAVE_LIBPNG)
320: {".png", PetscDrawImageSave_PNG},
321: #endif
322: #if defined(PETSC_HAVE_GIFLIB)
323: {".gif", PetscDrawImageSave_GIF},
324: #endif
325: #if defined(PETSC_HAVE_LIBJPEG)
326: {".jpg", PetscDrawImageSave_JPG},
327: #endif
328: {".ppm", PetscDrawImageSave_PPM}
329: };
331: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
332: {
333: size_t k;
334: PetscBool match = PETSC_FALSE;
338: /* if extension is empty, return default format to caller */
340: if (!*ext || !**ext) {
341: *ext = PetscDrawImageSaveTable[0].extension;
342: return(0);
343: }
344: /* check the extension mathes a supported format otherwise */
346: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
347: PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
348: if (match && PetscDrawImageSaveTable[k].SaveImage) return(0);
349: }
350: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext);
351: return(0);
352: }
354: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
355: {
356: size_t k;
357: PetscBool match = PETSC_FALSE;
358: char filename[PETSC_MAX_PATH_LEN];
367: PetscDrawImageCheckFormat(&ext);
368: PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
369: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
370: PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
371: if (match && PetscDrawImageSaveTable[k].SaveImage) {
372: PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
373: return(0);
374: }
375: }
376: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
377: return(0);
378: }
380: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
381: {
384: if (!*ext || !**ext) *ext = ".m4v";
385: return(0);
386: }
388: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
389: {
390: char input[PETSC_MAX_PATH_LEN];
391: char output[PETSC_MAX_PATH_LEN];
392: PetscBool gifinput;
399: if (count < 1) return(0);
401: PetscStrcasecmp(imext,".gif",&gifinput);
402: PetscDrawMovieCheckFormat(&mvext);
403: PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
404: PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);
406: /* use GIFLIB to generate an intermediate GIF animation */
407: #if defined(PETSC_HAVE_GIFLIB)
408: if (gifinput) {
409: char gifmovie[PETSC_MAX_PATH_LEN];
410: PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
411: PetscDrawMovieSaveGIF(input,count,gifmovie);
412: PetscStrcpy(input,gifmovie);
413: }
414: #endif
416: /* use FFmpeg to generate a movie */
417: #if defined(PETSC_HAVE_POPEN)
418: {
419: FILE *fd;
420: char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
421: char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
422: if (fps > 0) {PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);}
423: if (gifinput) {
424: PetscStrlcat(options," -f gif",sizeof(options));
425: PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
426: } else {
427: PetscStrlcat(options," -f image2",sizeof(options));
428: if (fps > 0) {PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);}
429: }
430: if (extraopts[0]) {PetscStrlcat(options,extraopts,sizeof(options));}
431: PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
432: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
433: PetscPClose(PETSC_COMM_SELF,fd);
434: }
435: #endif
436: return(0);
437: }