Actual source code: image.c
petsc-3.7.3 2016-08-01
1: #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/
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: */
13: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
14: {
15: int fd;
16: char header[32];
17: size_t hdrlen;
18: unsigned char *rgb;
25: /* map pixels to RGB colors */
26: if (palette) {
27: int k,p,n = (int)(w*h);
28: const unsigned char *colordef;
29: PetscMalloc1(3*w*h,&rgb);
30: for (k=p=0; k<n; k++) {
31: colordef = palette[pixels[k]];
32: rgb[p++] = colordef[0];
33: rgb[p++] = colordef[1];
34: rgb[p++] = colordef[2];
35: }
36: } else { /* assume pixels are RGB colors */
37: rgb = (unsigned char*)pixels;
38: }
39: /* open file and write PPM header */
40: PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);
41: PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n\0",(int)w,(int)h);
42: PetscStrlen(header,&hdrlen);
43: PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR,PETSC_FALSE);
44: /* write image data and close file */
45: PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR,PETSC_FALSE);
46: PetscBinaryClose(fd);
47: if (palette) {PetscFree(rgb);}
48: return(0);
49: }
51: static PetscErrorCode PetscDrawImageSave_PPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
52: { return PetscDrawImageSavePPM(filename,palette,w,h,pixels); }
55: /*
56: Code to write images in PNG format
57: */
58: #if defined(PETSC_HAVE_LIBPNG)
60: #include <png.h>
62: #if defined(PNG_SETJMP_SUPPORTED)
63: # ifndef png_jmpbuf
64: # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
65: # endif
66: #endif
70: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
71: {
72: FILE *fp;
73: png_struct *png_ptr;
74: png_info *info_ptr;
75: unsigned int row, stride = palette ? w : 3*w;
83: /* open file and create libpng structures */
84: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
85: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
86: if (!png_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
87: info_ptr = png_create_info_struct(png_ptr);
88: if (!info_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
90: /* setup libpng error handling */
91: #if defined(PNG_SETJMP_SUPPORTED)
92: if (setjmp(png_jmpbuf(png_ptr))) {
93: png_destroy_write_struct(&png_ptr,&info_ptr);
94: (void)PetscFClose(PETSC_COMM_SELF,fp);
95: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
96: }
97: #endif
99: /* setup PNG image metadata */
100: png_init_io(png_ptr, fp);
101: png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
102: palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
103: PNG_INTERLACE_NONE,
104: PNG_COMPRESSION_TYPE_DEFAULT,
105: PNG_FILTER_TYPE_DEFAULT);
106: if (palette)
107: png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);
109: /* write PNG image header and data */
110: png_write_info(png_ptr, info_ptr);
111: for (row = 0; row < h; row++)
112: png_write_row(png_ptr, pixels + row*stride);
113: png_write_end(png_ptr, NULL);
115: /* destroy libpng structures and close file */
116: png_destroy_write_struct(&png_ptr, &info_ptr);
117: PetscFClose(PETSC_COMM_SELF,fp);
118: return(0);
119: }
121: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
122: { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }
124: #endif/*!PETSC_HAVE_LIBPNG*/
127: /*
128: Code to write images in GIF format
129: */
130: #if defined(PETSC_HAVE_GIFLIB)
132: #include <gif_lib.h>
134: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
135: #define GifMakeMapObject MakeMapObject
136: #define GifFreeMapObject FreeMapObject
137: #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
138: #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
139: #define EGifCloseFile(f,err) EGifCloseFile(f)
140: #define DGifOpenFileName(n,err) DGifOpenFileName(n)
141: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
142: #define DGifCloseFile(f,err) DGifCloseFile(f)
143: #endif
147: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
148: {
149: int Row, Error;
150: int Width = (int)w;
151: int Height = (int)h;
152: int ColorRes = 8;
153: int ColorCount = 256;
154: ColorMapObject *GifCMap = NULL;
155: GifFileType *GifFile = NULL;
156: # define SETERRGIF(msg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
157: # define CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while(0)
164: GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
165: GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
166: Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
167: Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
168: for (Row = 0; Row < Height; Row++) {
169: Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
170: }
171: Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
172: GifFreeMapObject(GifCMap); GifCMap = NULL;
174: # undef SETERRGIF
175: # undef CHKERRGIF
176: return(0);
177: }
179: static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
180: { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
184: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
185: {
186: int i,j,Row;
187: char image[PETSC_MAX_PATH_LEN];
188: GifFileType *GifMovie = NULL;
189: GifFileType *GifImage = NULL;
191: # define SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)
196: if (count < 1) return(0);
198: for (i = 0; i < count; i++) {
199: PetscSNPrintf(image,sizeof(image),pattern,(int)i);
200: /* open and read image file */
201: if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
202: if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
203: /* open movie file and write header */
204: if (i == 0) {
205: if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
206: if (EGifPutScreenDesc(GifMovie,
207: GifImage->SWidth,
208: GifImage->SHeight,
209: GifImage->SColorResolution,
210: GifImage->SBackGroundColor,
211: GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,",movie);
212: }
213: /* loop over all frames in image */
214: for (j = 0; j < GifImage->ImageCount; j++) {
215: SavedImage *sp = &GifImage->SavedImages[j];
216: GifImageDesc *GifFrame = &sp->ImageDesc;
217: ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
218: if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
219: !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
220: (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
221: FrameColorMap = NULL;
222: /* add frame to movie */
223: if (EGifPutImageDesc(GifMovie,
224: GifFrame->Left,
225: GifFrame->Top,
226: GifFrame->Width,
227: GifFrame->Height,
228: GifFrame->Interlace,
229: FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
230: for (Row = 0; Row < GifFrame->Height; Row++) {
231: if (EGifPutLine(GifMovie,
232: sp->RasterBits + Row * GifFrame->Width,
233: GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
234: }
235: }
236: if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
237: }
238: if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);
240: # undef SETERRGIF
241: return(0);
242: }
244: #endif/*!PETSC_HAVE_GIFLIB*/
246: /*
247: Code to write images in JPEG format
248: */
249: #if defined(PETSC_HAVE_LIBJPEG)
251: #include <jpeglib.h>
253: #if defined(PETSC_HAVE_SETJMP_H)
254: #include <setjmp.h>
255: static jmp_buf petsc_jpeg_jumpbuf;
256: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
257: #endif
261: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
262: {
263: unsigned char *rgbpixels;
264: FILE *fp;
265: struct jpeg_compress_struct cinfo;
266: struct jpeg_error_mgr jerr;
267: PetscErrorCode ierr;
273: /* map pixels to RGB colors */
274: if (palette) {
275: int k,p,n = (int)(w*h);
276: const unsigned char *colordef;
277: PetscMalloc1(3*w*h,&rgbpixels);
278: for (k=p=0; k<n; k++) {
279: colordef = palette[pixels[k]];
280: rgbpixels[p++] = colordef[0];
281: rgbpixels[p++] = colordef[1];
282: rgbpixels[p++] = colordef[2];
283: }
284: } else { /* assume pixels are RGB colors */
285: rgbpixels = (unsigned char*)pixels;
286: }
287: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
289: cinfo.err = jpeg_std_error(&jerr);
290: #if defined(PETSC_HAVE_SETJMP_H)
291: jerr.error_exit = petsc_jpeg_error_longjmp;
292: if (setjmp(petsc_jpeg_jumpbuf)) {
293: char message[JMSG_LENGTH_MAX];
294: jerr.format_message((j_common_ptr)&cinfo,message);
295: jpeg_destroy_compress(&cinfo);
296: (void)PetscFClose(PETSC_COMM_SELF,fp);
297: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
298: }
299: #endif
300: jpeg_create_compress(&cinfo);
301: jpeg_stdio_dest(&cinfo,fp);
302: cinfo.image_width = w;
303: cinfo.image_height = h;
304: cinfo.input_components = 3;
305: cinfo.in_color_space = JCS_RGB;
306: jpeg_set_defaults(&cinfo);
307: jpeg_start_compress(&cinfo,TRUE);
308: while (cinfo.next_scanline < cinfo.image_height) {
309: unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
310: (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
311: }
312: jpeg_finish_compress(&cinfo);
313: jpeg_destroy_compress(&cinfo);
315: PetscFClose(PETSC_COMM_SELF,fp);
316: if (palette) {PetscFree(rgbpixels);}
317: return(0);
318: }
320: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
321: { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
323: #endif/*!PETSC_HAVE_LIBJPEG*/
325: static struct {
326: const char *extension;
327: PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
328: } PetscDrawImageSaveTable[] = {
329: #if defined(PETSC_HAVE_LIBPNG)
330: {".png", PetscDrawImageSave_PNG},
331: #endif
332: #if defined(PETSC_HAVE_GIFLIB)
333: {".gif", PetscDrawImageSave_GIF},
334: #endif
335: #if defined(PETSC_HAVE_LIBJPEG)
336: {".jpg", PetscDrawImageSave_JPG},
337: #endif
338: {".ppm", PetscDrawImageSave_PPM}
339: };
343: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
344: {
345: size_t k;
346: PetscBool match = PETSC_FALSE;
350: /* if extension is empty, return default format to caller */
352: if (!*ext || !**ext) {
353: *ext = PetscDrawImageSaveTable[0].extension;
354: return(0);
355: }
356: /* check the extension mathes a supported format otherwise */
358: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
359: PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
360: if (match && PetscDrawImageSaveTable[k].SaveImage) return(0);
361: }
362: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext);
363: PetscFunctionReturn(PETSC_ERR_SUP);
364: }
368: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
369: {
370: size_t k;
371: PetscBool match = PETSC_FALSE;
372: char filename[PETSC_MAX_PATH_LEN];
381: PetscDrawImageCheckFormat(&ext);
382: PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
383: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
384: PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
385: if (match && PetscDrawImageSaveTable[k].SaveImage) {
386: PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
387: return(0);
388: }
389: }
390: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
391: PetscFunctionReturn(PETSC_ERR_SUP);
392: }
396: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
397: {
400: if (!*ext || !**ext) *ext = ".m4v";
401: return(0);
402: }
406: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
407: {
408: char input[PETSC_MAX_PATH_LEN];
409: char output[PETSC_MAX_PATH_LEN];
410: PetscBool gifinput;
417: if (count < 1) return(0);
419: PetscStrcasecmp(imext,".gif",&gifinput);
420: PetscDrawMovieCheckFormat(&mvext);
421: PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
422: PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);
424: /* use GIFLIB to generate an intermediate GIF animation */
425: #if defined(PETSC_HAVE_GIFLIB)
426: if (gifinput) {
427: char gifmovie[PETSC_MAX_PATH_LEN];
428: PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
429: PetscDrawMovieSaveGIF(input,count,gifmovie);
430: PetscStrcpy(input,gifmovie);
431: }
432: #endif
434: /* use FFmpeg to generate a movie */
435: #if defined(PETSC_HAVE_POPEN)
436: {
437: FILE *fd; int err;
438: char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
439: char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
440: if (fps > 0) {PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);}
441: if (gifinput) {
442: PetscStrcat(options," -f gif");
443: PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
444: } else {
445: PetscStrcat(options," -f image2");
446: if (fps > 0) {PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);}
447: }
448: if (extraopts[0]) {PetscStrcat(options,extraopts);}
449: PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
450: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
451: PetscPClose(PETSC_COMM_SELF,fd,&err);
452: }
453: #endif
454: return(0);
455: }