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: {
49: return PetscDrawImageSavePPM(filename, palette, w, h, pixels);
50: }
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;
76: /* open file and create libpng structures */
77: PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp);
78: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
80: info_ptr = png_create_info_struct(png_ptr);
83: /* setup libpng error handling */
84: #if defined(PNG_SETJMP_SUPPORTED)
85: if (setjmp(png_jmpbuf(png_ptr))) {
86: png_destroy_write_struct(&png_ptr, &info_ptr);
87: (void)PetscFClose(PETSC_COMM_SELF, fp);
88: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing PNG file %s", filename);
89: }
90: #endif
92: /* setup PNG image metadata */
93: png_init_io(png_ptr, fp);
94: png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/ 8, palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
95: if (palette) png_set_PLTE(png_ptr, info_ptr, (png_color *)palette, 256);
97: /* write PNG image header and data */
98: png_write_info(png_ptr, info_ptr);
99: for (row = 0; row < h; row++) png_write_row(png_ptr, pixels + row * stride);
100: png_write_end(png_ptr, NULL);
102: /* destroy libpng structures and close file */
103: png_destroy_write_struct(&png_ptr, &info_ptr);
104: PetscFClose(PETSC_COMM_SELF, fp);
105: return 0;
106: }
108: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
109: {
110: return PetscDrawImageSavePNG(filename, palette, w, h, pixels);
111: }
113: #endif /*!PETSC_HAVE_LIBPNG*/
115: /*
116: Code to write images in GIF format
117: */
118: #if defined(PETSC_HAVE_GIFLIB)
120: #include <gif_lib.h>
122: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
123: #define GifMakeMapObject MakeMapObject
124: #define GifFreeMapObject FreeMapObject
125: #define EGifOpenFileName(n, b, err) EGifOpenFileName(n, b)
126: #define EGifOpenFileHandle(h, err) EGifOpenFileName(h)
127: #define EGifCloseFile(f, err) EGifCloseFile(f)
128: #define DGifOpenFileName(n, err) DGifOpenFileName(n)
129: #define DGifOpenFileHandle(h, err) DGifOpenFileName(h)
130: #define DGifCloseFile(f, err) DGifCloseFile(f)
131: #endif
133: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
134: {
135: int Row;
136: int Width = (int)w;
137: int Height = (int)h;
138: int ColorRes = 8;
139: int ColorCount = 256;
140: ColorMapObject *GifCMap = NULL;
141: GifFileType *GifFile = NULL;
142: #define SETERRGIF(msg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg ", GIF file: %s", filename)
143: #define PetscCallGIF(msg, ...) \
144: do { \
145: int Error = __VA_ARGS__; \
146: if (PetscUnlikely(Error != GIF_OK)) SETERRGIF(msg); \
147: } while (0)
153: GifCMap = GifMakeMapObject(ColorCount, (GifColorType *)palette);
154: if (!GifCMap) SETERRGIF("Allocating colormap");
155: GifFile = EGifOpenFileName(filename, 0, NULL);
156: if (!GifFile) SETERRGIF("Opening");
157: "Writing screen descriptor", EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap);
158: "Writing image descriptor", EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL);
159: for (Row = 0; Row < Height; Row++) "Writing image pixels", EGifPutLine(GifFile, (GifPixelType *)pixels + Row * Width, Width);
160: "Closing", EGifCloseFile(GifFile, NULL);
161: GifFreeMapObject(GifCMap);
162: 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: {
171: return PetscDrawImageSaveGIF(filename, palette, w, h, pixels);
172: }
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;
180: #define SETERRGIF(msg, fn) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, msg " GIF file %s", fn)
184: if (count < 1) return 0;
186: for (i = 0; i < count; i++) {
187: PetscSNPrintf(image, sizeof(image), pattern, (int)i);
188: /* open and read image file */
189: if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input", image);
190: if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input", image);
191: /* open movie file and write header */
192: if (i == 0) {
193: if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output", movie);
194: if (EGifPutScreenDesc(GifMovie, GifImage->SWidth, GifImage->SHeight, GifImage->SColorResolution, GifImage->SBackGroundColor, GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,", movie);
195: }
196: /* loop over all frames in image */
197: for (j = 0; j < GifImage->ImageCount; j++) {
198: SavedImage *sp = &GifImage->SavedImages[j];
199: GifImageDesc *GifFrame = &sp->ImageDesc;
200: ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
201: if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount && !memcmp(GifMovie->SColorMap->Colors, FrameColorMap->Colors, (size_t)FrameColorMap->ColorCount * sizeof(GifColorType))) FrameColorMap = NULL;
202: /* add frame to movie */
203: if (EGifPutImageDesc(GifMovie, GifFrame->Left, GifFrame->Top, GifFrame->Width, GifFrame->Height, GifFrame->Interlace, FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,", movie);
204: for (Row = 0; Row < GifFrame->Height; Row++) {
205: if (EGifPutLine(GifMovie, sp->RasterBits + Row * GifFrame->Width, GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,", movie);
206: }
207: }
208: if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input", image);
209: }
210: if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output", movie);
212: #undef SETERRGIF
213: return 0;
214: }
216: #endif /*!PETSC_HAVE_GIFLIB*/
218: /*
219: Code to write images in JPEG format
220: */
221: #if defined(PETSC_HAVE_LIBJPEG)
223: #include <jpeglib.h>
225: #if defined(PETSC_HAVE_SETJMP_H)
226: #include <setjmp.h>
227: static jmp_buf petsc_jpeg_jumpbuf;
228: static void petsc_jpeg_error_longjmp(j_common_ptr cinfo)
229: {
230: (void)cinfo;
231: longjmp(petsc_jpeg_jumpbuf, 1);
232: }
233: #endif
235: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
236: {
237: unsigned char *rgbpixels;
238: FILE *fp;
239: struct jpeg_compress_struct cinfo;
240: struct jpeg_error_mgr jerr;
245: /* map pixels to RGB colors */
246: if (palette) {
247: int k, p, n = (int)(w * h);
248: const unsigned char *colordef;
249: PetscMalloc1(3 * w * h, &rgbpixels);
250: for (k = p = 0; k < n; k++) {
251: colordef = palette[pixels[k]];
252: rgbpixels[p++] = colordef[0];
253: rgbpixels[p++] = colordef[1];
254: rgbpixels[p++] = colordef[2];
255: }
256: } else { /* assume pixels are RGB colors */
257: rgbpixels = (unsigned char *)pixels;
258: }
259: PetscFOpen(PETSC_COMM_SELF, filename, "wb", &fp);
261: cinfo.err = jpeg_std_error(&jerr);
262: #if defined(PETSC_HAVE_SETJMP_H)
263: jerr.error_exit = petsc_jpeg_error_longjmp;
264: if (setjmp(petsc_jpeg_jumpbuf)) {
265: char message[JMSG_LENGTH_MAX];
266: jerr.format_message((j_common_ptr)&cinfo, message);
267: jpeg_destroy_compress(&cinfo);
268: (void)PetscFClose(PETSC_COMM_SELF, fp);
269: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error writing JPEG file %s\n%s", filename, message);
270: }
271: #endif
272: jpeg_create_compress(&cinfo);
273: jpeg_stdio_dest(&cinfo, fp);
274: cinfo.image_width = w;
275: cinfo.image_height = h;
276: cinfo.input_components = 3;
277: cinfo.in_color_space = JCS_RGB;
278: jpeg_set_defaults(&cinfo);
279: jpeg_start_compress(&cinfo, TRUE);
280: while (cinfo.next_scanline < cinfo.image_height) {
281: unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3 * w;
282: (void)jpeg_write_scanlines(&cinfo, &rowptr, 1);
283: }
284: jpeg_finish_compress(&cinfo);
285: jpeg_destroy_compress(&cinfo);
287: PetscFClose(PETSC_COMM_SELF, fp);
288: if (palette) PetscFree(rgbpixels);
289: return 0;
290: }
292: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
293: {
294: return PetscDrawImageSaveJPG(filename, palette, w, h, pixels);
295: }
297: #endif /*!PETSC_HAVE_LIBJPEG*/
299: static struct {
300: const char *extension;
301: PetscErrorCode (*SaveImage)(const char[], unsigned char[][3], unsigned int, unsigned int, const unsigned char[]);
302: } PetscDrawImageSaveTable[] = {
303: #if defined(PETSC_HAVE_LIBPNG)
304: {".png", PetscDrawImageSave_PNG},
305: #endif
306: #if defined(PETSC_HAVE_GIFLIB)
307: {".gif", PetscDrawImageSave_GIF},
308: #endif
309: #if defined(PETSC_HAVE_LIBJPEG)
310: {".jpg", PetscDrawImageSave_JPG},
311: #endif
312: {".ppm", PetscDrawImageSave_PPM}
313: };
315: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
316: {
317: size_t k;
318: PetscBool match = PETSC_FALSE;
320: /* if extension is empty, return default format to caller */
322: if (!*ext || !**ext) {
323: *ext = PetscDrawImageSaveTable[0].extension;
324: return 0;
325: }
326: /* check the extension matches a supported format */
328: for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
329: PetscStrcasecmp(*ext, PetscDrawImageSaveTable[k].extension, &match);
330: if (match && PetscDrawImageSaveTable[k].SaveImage) return 0;
331: }
332: 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);
333: }
335: PetscErrorCode PetscDrawImageSave(const char basename[], const char ext[], unsigned char palette[][3], unsigned int w, unsigned int h, const unsigned char pixels[])
336: {
337: size_t k;
338: PetscBool match = PETSC_FALSE;
339: char filename[PETSC_MAX_PATH_LEN];
346: PetscDrawImageCheckFormat(&ext);
347: PetscSNPrintf(filename, sizeof(filename), "%s%s", basename, ext);
348: for (k = 0; k < PETSC_STATIC_ARRAY_LENGTH(PetscDrawImageSaveTable); k++) {
349: PetscStrcasecmp(ext, PetscDrawImageSaveTable[k].extension, &match);
350: if (match && PetscDrawImageSaveTable[k].SaveImage) {
351: PetscDrawImageSaveTable[k].SaveImage(filename, palette, w, h, pixels);
352: return 0;
353: }
354: }
355: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Image extension %s not supported, use .ppm", ext);
356: }
358: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
359: {
361: if (!*ext || !**ext) *ext = ".m4v";
362: return 0;
363: }
365: PetscErrorCode PetscDrawMovieSave(const char basename[], PetscInt count, const char imext[], PetscInt fps, const char mvext[])
366: {
367: char input[PETSC_MAX_PATH_LEN];
368: char output[PETSC_MAX_PATH_LEN];
369: PetscBool gifinput;
374: if (count < 1) return 0;
376: PetscStrcasecmp(imext, ".gif", &gifinput);
377: PetscDrawMovieCheckFormat(&mvext);
378: PetscSNPrintf(input, sizeof(input), "%s/%s_%%d%s", basename, basename, imext);
379: PetscSNPrintf(output, sizeof(output), "%s%s", basename, mvext);
381: /* use GIFLIB to generate an intermediate GIF animation */
382: #if defined(PETSC_HAVE_GIFLIB)
383: if (gifinput) {
384: char gifmovie[PETSC_MAX_PATH_LEN];
385: PetscSNPrintf(gifmovie, sizeof(gifmovie), "%s/%s_movie.gif", basename, basename);
386: PetscDrawMovieSaveGIF(input, count, gifmovie);
387: PetscStrcpy(input, gifmovie);
388: }
389: #endif
391: /* use FFmpeg to generate a movie */
392: #if defined(PETSC_HAVE_POPEN)
393: {
394: FILE *fd;
395: char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
396: char command[sizeof(options) + sizeof(extraopts) + sizeof(framerate) + PETSC_MAX_PATH_LEN * 2];
397: if (fps > 0) PetscSNPrintf(framerate, sizeof(framerate), "-r %d", (int)fps);
398: if (gifinput) {
399: PetscStrlcat(options, " -f gif", sizeof(options));
400: PetscSNPrintf(extraopts, sizeof(extraopts), " -default_delay %d", (fps > 0) ? 100 / (int)fps : 4);
401: } else {
402: PetscStrlcat(options, " -f image2", sizeof(options));
403: if (fps > 0) PetscSNPrintf(extraopts, sizeof(extraopts), " -framerate %d", (int)fps);
404: }
405: if (extraopts[0]) PetscStrlcat(options, extraopts, sizeof(options));
406: PetscSNPrintf(command, sizeof(command), "ffmpeg %s -i \"%s\" %s \"%s\"", options, input, framerate, output);
407: PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", &fd);
408: PetscPClose(PETSC_COMM_SELF, fd);
409: }
410: #endif
411: return 0;
412: }