Actual source code: image.c
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);
42: /* write image data and close file */
43: PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR);
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); }
52: /*
53: Code to write images in PNG format
54: */
55: #if defined(PETSC_HAVE_LIBPNG)
57: #include <png.h>
59: #if defined(PNG_SETJMP_SUPPORTED)
60: # ifndef png_jmpbuf
61: # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
62: # endif
63: #endif
65: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
66: {
67: FILE *fp;
68: png_struct *png_ptr;
69: png_info *info_ptr;
70: unsigned int row, stride = palette ? w : 3*w;
78: /* open file and create libpng structures */
79: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
80: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
81: if (!png_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
82: info_ptr = png_create_info_struct(png_ptr);
83: if (!info_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
85: /* setup libpng error handling */
86: #if defined(PNG_SETJMP_SUPPORTED)
87: if (setjmp(png_jmpbuf(png_ptr))) {
88: png_destroy_write_struct(&png_ptr,&info_ptr);
89: (void)PetscFClose(PETSC_COMM_SELF,fp);
90: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
91: }
92: #endif
94: /* setup PNG image metadata */
95: png_init_io(png_ptr, fp);
96: png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
97: palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
98: PNG_INTERLACE_NONE,
99: PNG_COMPRESSION_TYPE_DEFAULT,
100: PNG_FILTER_TYPE_DEFAULT);
101: if (palette)
102: png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);
104: /* write PNG image header and data */
105: png_write_info(png_ptr, info_ptr);
106: for (row = 0; row < h; row++)
107: png_write_row(png_ptr, pixels + row*stride);
108: png_write_end(png_ptr, NULL);
110: /* destroy libpng structures and close file */
111: png_destroy_write_struct(&png_ptr, &info_ptr);
112: PetscFClose(PETSC_COMM_SELF,fp);
113: return(0);
114: }
116: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
117: { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }
119: #endif/*!PETSC_HAVE_LIBPNG*/
121: /*
122: Code to write images in GIF format
123: */
124: #if defined(PETSC_HAVE_GIFLIB)
126: #include <gif_lib.h>
128: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
129: #define GifMakeMapObject MakeMapObject
130: #define GifFreeMapObject FreeMapObject
131: #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
132: #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
133: #define EGifCloseFile(f,err) EGifCloseFile(f)
134: #define DGifOpenFileName(n,err) DGifOpenFileName(n)
135: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
136: #define DGifCloseFile(f,err) DGifCloseFile(f)
137: #endif
139: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
140: {
141: int Row, Error;
142: int Width = (int)w;
143: int Height = (int)h;
144: int ColorRes = 8;
145: int ColorCount = 256;
146: ColorMapObject *GifCMap = NULL;
147: GifFileType *GifFile = NULL;
148: # define SETERRGIF(msg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
149: # define CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while (0)
156: GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
157: GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
158: Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
159: Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
160: for (Row = 0; Row < Height; Row++) {
161: Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
162: }
163: Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
164: GifFreeMapObject(GifCMap); GifCMap = NULL;
166: # undef SETERRGIF
167: # undef CHKERRGIF
168: return(0);
169: }
171: static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
172: { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
174: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
175: {
176: int i,j,Row;
177: char image[PETSC_MAX_PATH_LEN];
178: GifFileType *GifMovie = NULL;
179: GifFileType *GifImage = NULL;
181: # define SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)
186: if (count < 1) return(0);
188: for (i = 0; i < count; i++) {
189: PetscSNPrintf(image,sizeof(image),pattern,(int)i);
190: /* open and read image file */
191: if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
192: if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
193: /* open movie file and write header */
194: if (i == 0) {
195: if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
196: if (EGifPutScreenDesc(GifMovie,
197: GifImage->SWidth,
198: GifImage->SHeight,
199: GifImage->SColorResolution,
200: GifImage->SBackGroundColor,
201: GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,",movie);
202: }
203: /* loop over all frames in image */
204: for (j = 0; j < GifImage->ImageCount; j++) {
205: SavedImage *sp = &GifImage->SavedImages[j];
206: GifImageDesc *GifFrame = &sp->ImageDesc;
207: ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
208: if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
209: !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
210: (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
211: FrameColorMap = NULL;
212: /* add frame to movie */
213: if (EGifPutImageDesc(GifMovie,
214: GifFrame->Left,
215: GifFrame->Top,
216: GifFrame->Width,
217: GifFrame->Height,
218: GifFrame->Interlace,
219: FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
220: for (Row = 0; Row < GifFrame->Height; Row++) {
221: if (EGifPutLine(GifMovie,
222: sp->RasterBits + Row * GifFrame->Width,
223: GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
224: }
225: }
226: if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
227: }
228: if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);
230: # undef SETERRGIF
231: return(0);
232: }
234: #endif/*!PETSC_HAVE_GIFLIB*/
236: /*
237: Code to write images in JPEG format
238: */
239: #if defined(PETSC_HAVE_LIBJPEG)
241: #include <jpeglib.h>
243: #if defined(PETSC_HAVE_SETJMP_H)
244: #include <setjmp.h>
245: static jmp_buf petsc_jpeg_jumpbuf;
246: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
247: #endif
249: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
250: {
251: unsigned char *rgbpixels;
252: FILE *fp;
253: struct jpeg_compress_struct cinfo;
254: struct jpeg_error_mgr jerr;
255: PetscErrorCode ierr;
261: /* map pixels to RGB colors */
262: if (palette) {
263: int k,p,n = (int)(w*h);
264: const unsigned char *colordef;
265: PetscMalloc1(3*w*h,&rgbpixels);
266: for (k=p=0; k<n; k++) {
267: colordef = palette[pixels[k]];
268: rgbpixels[p++] = colordef[0];
269: rgbpixels[p++] = colordef[1];
270: rgbpixels[p++] = colordef[2];
271: }
272: } else { /* assume pixels are RGB colors */
273: rgbpixels = (unsigned char*)pixels;
274: }
275: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
277: cinfo.err = jpeg_std_error(&jerr);
278: #if defined(PETSC_HAVE_SETJMP_H)
279: jerr.error_exit = petsc_jpeg_error_longjmp;
280: if (setjmp(petsc_jpeg_jumpbuf)) {
281: char message[JMSG_LENGTH_MAX];
282: jerr.format_message((j_common_ptr)&cinfo,message);
283: jpeg_destroy_compress(&cinfo);
284: (void)PetscFClose(PETSC_COMM_SELF,fp);
285: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
286: }
287: #endif
288: jpeg_create_compress(&cinfo);
289: jpeg_stdio_dest(&cinfo,fp);
290: cinfo.image_width = w;
291: cinfo.image_height = h;
292: cinfo.input_components = 3;
293: cinfo.in_color_space = JCS_RGB;
294: jpeg_set_defaults(&cinfo);
295: jpeg_start_compress(&cinfo,TRUE);
296: while (cinfo.next_scanline < cinfo.image_height) {
297: unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
298: (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
299: }
300: jpeg_finish_compress(&cinfo);
301: jpeg_destroy_compress(&cinfo);
303: PetscFClose(PETSC_COMM_SELF,fp);
304: if (palette) {PetscFree(rgbpixels);}
305: return(0);
306: }
308: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
309: { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
311: #endif/*!PETSC_HAVE_LIBJPEG*/
313: static struct {
314: const char *extension;
315: PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
316: } PetscDrawImageSaveTable[] = {
317: #if defined(PETSC_HAVE_LIBPNG)
318: {".png", PetscDrawImageSave_PNG},
319: #endif
320: #if defined(PETSC_HAVE_GIFLIB)
321: {".gif", PetscDrawImageSave_GIF},
322: #endif
323: #if defined(PETSC_HAVE_LIBJPEG)
324: {".jpg", PetscDrawImageSave_JPG},
325: #endif
326: {".ppm", PetscDrawImageSave_PPM}
327: };
329: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
330: {
331: size_t k;
332: PetscBool match = PETSC_FALSE;
336: /* if extension is empty, return default format to caller */
338: if (!*ext || !**ext) {
339: *ext = PetscDrawImageSaveTable[0].extension;
340: return(0);
341: }
342: /* check the extension matches a supported format */
344: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
345: PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
346: if (match && PetscDrawImageSaveTable[k].SaveImage) return(0);
347: }
348: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm or see PetscDrawSetSave() for what ./configure option you may need",*ext);
349: }
351: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
352: {
353: size_t k;
354: PetscBool match = PETSC_FALSE;
355: char filename[PETSC_MAX_PATH_LEN];
364: PetscDrawImageCheckFormat(&ext);
365: PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
366: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
367: PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
368: if (match && PetscDrawImageSaveTable[k].SaveImage) {
369: PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
370: return(0);
371: }
372: }
373: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
374: }
376: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
377: {
380: if (!*ext || !**ext) *ext = ".m4v";
381: return(0);
382: }
384: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
385: {
386: char input[PETSC_MAX_PATH_LEN];
387: char output[PETSC_MAX_PATH_LEN];
388: PetscBool gifinput;
395: if (count < 1) return(0);
397: PetscStrcasecmp(imext,".gif",&gifinput);
398: PetscDrawMovieCheckFormat(&mvext);
399: PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
400: PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);
402: /* use GIFLIB to generate an intermediate GIF animation */
403: #if defined(PETSC_HAVE_GIFLIB)
404: if (gifinput) {
405: char gifmovie[PETSC_MAX_PATH_LEN];
406: PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
407: PetscDrawMovieSaveGIF(input,count,gifmovie);
408: PetscStrcpy(input,gifmovie);
409: }
410: #endif
412: /* use FFmpeg to generate a movie */
413: #if defined(PETSC_HAVE_POPEN)
414: {
415: FILE *fd;
416: char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
417: char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
418: if (fps > 0) {PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);}
419: if (gifinput) {
420: PetscStrlcat(options," -f gif",sizeof(options));
421: PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
422: } else {
423: PetscStrlcat(options," -f image2",sizeof(options));
424: if (fps > 0) {PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);}
425: }
426: if (extraopts[0]) {PetscStrlcat(options,extraopts,sizeof(options));}
427: PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
428: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
429: PetscPClose(PETSC_COMM_SELF,fd);
430: }
431: #endif
432: return(0);
433: }