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;
21: /* map pixels to RGB colors */
22: if (palette) {
23: int k,p,n = (int)(w*h);
24: const unsigned char *colordef;
25: PetscMalloc1(3*w*h,&rgb);
26: for (k=p=0; k<n; k++) {
27: colordef = palette[pixels[k]];
28: rgb[p++] = colordef[0];
29: rgb[p++] = colordef[1];
30: rgb[p++] = colordef[2];
31: }
32: } else { /* assume pixels are RGB colors */
33: rgb = (unsigned char*)pixels;
34: }
35: /* open file and write PPM header */
36: PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);
37: PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n%c",(int)w,(int)h,'\0');
38: PetscStrlen(header,&hdrlen);
39: PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR);
40: /* write image data and close file */
41: PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR);
42: PetscBinaryClose(fd);
43: if (palette) PetscFree(rgb);
44: return 0;
45: }
47: static PetscErrorCode PetscDrawImageSave_PPM(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
48: { return PetscDrawImageSavePPM(filename,palette,w,h,pixels); }
50: /*
51: Code to write images in PNG format
52: */
53: #if defined(PETSC_HAVE_LIBPNG)
55: #include <png.h>
57: #if defined(PNG_SETJMP_SUPPORTED)
58: # ifndef png_jmpbuf
59: # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
60: # endif
61: #endif
63: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
64: {
65: FILE *fp;
66: png_struct *png_ptr;
67: png_info *info_ptr;
68: unsigned int row, stride = palette ? w : 3*w;
74: /* open file and create libpng structures */
75: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
76: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
78: info_ptr = png_create_info_struct(png_ptr);
81: /* setup libpng error handling */
82: #if defined(PNG_SETJMP_SUPPORTED)
83: if (setjmp(png_jmpbuf(png_ptr))) {
84: png_destroy_write_struct(&png_ptr,&info_ptr);
85: (void)PetscFClose(PETSC_COMM_SELF,fp);
86: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
87: }
88: #endif
90: /* setup PNG image metadata */
91: png_init_io(png_ptr, fp);
92: png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
93: palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
94: PNG_INTERLACE_NONE,
95: PNG_COMPRESSION_TYPE_DEFAULT,
96: PNG_FILTER_TYPE_DEFAULT);
97: if (palette)
98: png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);
100: /* write PNG image header and data */
101: png_write_info(png_ptr, info_ptr);
102: for (row = 0; row < h; row++)
103: png_write_row(png_ptr, pixels + row*stride);
104: png_write_end(png_ptr, NULL);
106: /* destroy libpng structures and close file */
107: png_destroy_write_struct(&png_ptr, &info_ptr);
108: PetscFClose(PETSC_COMM_SELF,fp);
109: return 0;
110: }
112: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
113: { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }
115: #endif/*!PETSC_HAVE_LIBPNG*/
117: /*
118: Code to write images in GIF format
119: */
120: #if defined(PETSC_HAVE_GIFLIB)
122: #include <gif_lib.h>
124: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
125: #define GifMakeMapObject MakeMapObject
126: #define GifFreeMapObject FreeMapObject
127: #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
128: #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
129: #define EGifCloseFile(f,err) EGifCloseFile(f)
130: #define DGifOpenFileName(n,err) DGifOpenFileName(n)
131: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
132: #define DGifCloseFile(f,err) DGifCloseFile(f)
133: #endif
135: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
136: {
137: int Row;
138: int Width = (int)w;
139: int Height = (int)h;
140: int ColorRes = 8;
141: int ColorCount = 256;
142: ColorMapObject *GifCMap = NULL;
143: GifFileType *GifFile = NULL;
144: # define SETERRGIF(msg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
145: # define PetscCallGIF(msg,...) do { \
146: int Error = __VA_ARGS__; \
147: if (PetscUnlikely(Error != GIF_OK)) SETERRGIF(msg); \
148: } while (0)
154: GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
155: GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
156: "Writing screen descriptor", EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap);
157: "Writing image descriptor", EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL);
158: for (Row = 0; Row < Height; Row++) {
159: "Writing image pixels", EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width);
160: }
161: "Closing", EGifCloseFile(GifFile, NULL);
162: GifFreeMapObject(GifCMap); GifCMap = NULL;
164: # undef SETERRGIF
165: # undef CHKERRGIF
166: return 0;
167: }
169: static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
170: { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
172: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
173: {
174: int i,j,Row;
175: char image[PETSC_MAX_PATH_LEN];
176: GifFileType *GifMovie = NULL;
177: GifFileType *GifImage = NULL;
178: # define SETERRGIF(msg,fn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)
182: if (count < 1) return 0;
184: for (i = 0; i < count; i++) {
185: PetscSNPrintf(image,sizeof(image),pattern,(int)i);
186: /* open and read image file */
187: if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
188: if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
189: /* open movie file and write header */
190: if (i == 0) {
191: if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
192: if (EGifPutScreenDesc(GifMovie,
193: GifImage->SWidth,
194: GifImage->SHeight,
195: GifImage->SColorResolution,
196: GifImage->SBackGroundColor,
197: GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,",movie);
198: }
199: /* loop over all frames in image */
200: for (j = 0; j < GifImage->ImageCount; j++) {
201: SavedImage *sp = &GifImage->SavedImages[j];
202: GifImageDesc *GifFrame = &sp->ImageDesc;
203: ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
204: if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
205: !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
206: (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
207: FrameColorMap = NULL;
208: /* add frame to movie */
209: if (EGifPutImageDesc(GifMovie,
210: GifFrame->Left,
211: GifFrame->Top,
212: GifFrame->Width,
213: GifFrame->Height,
214: GifFrame->Interlace,
215: FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
216: for (Row = 0; Row < GifFrame->Height; Row++) {
217: if (EGifPutLine(GifMovie,
218: sp->RasterBits + Row * GifFrame->Width,
219: GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
220: }
221: }
222: if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
223: }
224: if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);
226: # undef SETERRGIF
227: return 0;
228: }
230: #endif/*!PETSC_HAVE_GIFLIB*/
232: /*
233: Code to write images in JPEG format
234: */
235: #if defined(PETSC_HAVE_LIBJPEG)
237: #include <jpeglib.h>
239: #if defined(PETSC_HAVE_SETJMP_H)
240: #include <setjmp.h>
241: static jmp_buf petsc_jpeg_jumpbuf;
242: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
243: #endif
245: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
246: {
247: unsigned char *rgbpixels;
248: FILE *fp;
249: struct jpeg_compress_struct cinfo;
250: struct jpeg_error_mgr jerr;
255: /* map pixels to RGB colors */
256: if (palette) {
257: int k,p,n = (int)(w*h);
258: const unsigned char *colordef;
259: PetscMalloc1(3*w*h,&rgbpixels);
260: for (k=p=0; k<n; k++) {
261: colordef = palette[pixels[k]];
262: rgbpixels[p++] = colordef[0];
263: rgbpixels[p++] = colordef[1];
264: rgbpixels[p++] = colordef[2];
265: }
266: } else { /* assume pixels are RGB colors */
267: rgbpixels = (unsigned char*)pixels;
268: }
269: PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
271: cinfo.err = jpeg_std_error(&jerr);
272: #if defined(PETSC_HAVE_SETJMP_H)
273: jerr.error_exit = petsc_jpeg_error_longjmp;
274: if (setjmp(petsc_jpeg_jumpbuf)) {
275: char message[JMSG_LENGTH_MAX];
276: jerr.format_message((j_common_ptr)&cinfo,message);
277: jpeg_destroy_compress(&cinfo);
278: (void)PetscFClose(PETSC_COMM_SELF,fp);
279: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
280: }
281: #endif
282: jpeg_create_compress(&cinfo);
283: jpeg_stdio_dest(&cinfo,fp);
284: cinfo.image_width = w;
285: cinfo.image_height = h;
286: cinfo.input_components = 3;
287: cinfo.in_color_space = JCS_RGB;
288: jpeg_set_defaults(&cinfo);
289: jpeg_start_compress(&cinfo,TRUE);
290: while (cinfo.next_scanline < cinfo.image_height) {
291: unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
292: (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
293: }
294: jpeg_finish_compress(&cinfo);
295: jpeg_destroy_compress(&cinfo);
297: PetscFClose(PETSC_COMM_SELF,fp);
298: if (palette) PetscFree(rgbpixels);
299: return 0;
300: }
302: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
303: { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
305: #endif/*!PETSC_HAVE_LIBJPEG*/
307: static struct {
308: const char *extension;
309: PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
310: } PetscDrawImageSaveTable[] = {
311: #if defined(PETSC_HAVE_LIBPNG)
312: {".png", PetscDrawImageSave_PNG},
313: #endif
314: #if defined(PETSC_HAVE_GIFLIB)
315: {".gif", PetscDrawImageSave_GIF},
316: #endif
317: #if defined(PETSC_HAVE_LIBJPEG)
318: {".jpg", PetscDrawImageSave_JPG},
319: #endif
320: {".ppm", PetscDrawImageSave_PPM}
321: };
323: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
324: {
325: size_t k;
326: PetscBool match = PETSC_FALSE;
328: /* if extension is empty, return default format to caller */
330: if (!*ext || !**ext) {
331: *ext = PetscDrawImageSaveTable[0].extension;
332: return 0;
333: }
334: /* check the extension matches a supported format */
336: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
337: PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
338: if (match && PetscDrawImageSaveTable[k].SaveImage) return 0;
339: }
340: 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);
341: }
343: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
344: {
345: size_t k;
346: PetscBool match = PETSC_FALSE;
347: char filename[PETSC_MAX_PATH_LEN];
354: PetscDrawImageCheckFormat(&ext);
355: PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
356: for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
357: PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
358: if (match && PetscDrawImageSaveTable[k].SaveImage) {
359: PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
360: return 0;
361: }
362: }
363: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
364: }
366: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
367: {
369: if (!*ext || !**ext) *ext = ".m4v";
370: return 0;
371: }
373: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
374: {
375: char input[PETSC_MAX_PATH_LEN];
376: char output[PETSC_MAX_PATH_LEN];
377: PetscBool gifinput;
382: if (count < 1) return 0;
384: PetscStrcasecmp(imext,".gif",&gifinput);
385: PetscDrawMovieCheckFormat(&mvext);
386: PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
387: PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);
389: /* use GIFLIB to generate an intermediate GIF animation */
390: #if defined(PETSC_HAVE_GIFLIB)
391: if (gifinput) {
392: char gifmovie[PETSC_MAX_PATH_LEN];
393: PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
394: PetscDrawMovieSaveGIF(input,count,gifmovie);
395: PetscStrcpy(input,gifmovie);
396: }
397: #endif
399: /* use FFmpeg to generate a movie */
400: #if defined(PETSC_HAVE_POPEN)
401: {
402: FILE *fd;
403: char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
404: char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
405: if (fps > 0) PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);
406: if (gifinput) {
407: PetscStrlcat(options," -f gif",sizeof(options));
408: PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
409: } else {
410: PetscStrlcat(options," -f image2",sizeof(options));
411: if (fps > 0) PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);
412: }
413: if (extraopts[0]) PetscStrlcat(options,extraopts,sizeof(options));
414: PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
415: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
416: PetscPClose(PETSC_COMM_SELF,fd);
417: }
418: #endif
419: return 0;
420: }