xref: /petsc/src/sys/classes/draw/utils/image.c (revision 3d242201b367197be0528dc78b79f34d6902871b)
1 #include <petsc/private/petscimpl.h>         /*I "petscsys.h" I*/
2 
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 *[]);
7 
8 /*
9    Code to write images in PPM format
10 */
11 #undef __FUNCT__
12 #define __FUNCT__ "PetscDrawImageSavePPM"
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;
19   PetscErrorCode ierr;
20 
21   PetscFunctionBegin;
22   PetscValidCharPointer(filename,1);
23   if (palette) PetscValidCharPointer(palette,2);
24   PetscValidCharPointer(pixels,5);
25   /* map pixels to RGB colors */
26   if (palette) {
27     int k,p,n = (int)(w*h);
28     const unsigned char *colordef;
29     ierr = PetscMalloc1(3*w*h,&rgb);CHKERRQ(ierr);
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   ierr = PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);CHKERRQ(ierr);
41   ierr = PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n\0",(int)w,(int)h);CHKERRQ(ierr);
42   ierr = PetscStrlen(header,&hdrlen);CHKERRQ(ierr);
43   ierr = PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
44   /* write image data and close file */
45   ierr = PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
46   ierr = PetscBinaryClose(fd);CHKERRQ(ierr);
47   if (palette) {ierr = PetscFree(rgb);CHKERRQ(ierr);}
48   PetscFunctionReturn(0);
49 }
50 
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); }
53 
54 
55 /*
56    Code to write images in PNG format
57 */
58 #if defined(PETSC_HAVE_LIBPNG)
59 
60 #include <png.h>
61 
62 #if defined(PNG_SETJMP_SUPPORTED)
63 # ifndef png_jmpbuf
64 #   define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
65 # endif
66 #endif
67 
68 #undef __FUNCT__
69 #define __FUNCT__ "PetscDrawImageSavePNG"
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;
76   PetscErrorCode ierr;
77 
78   PetscFunctionBegin;
79   PetscValidCharPointer(filename,1);
80   if (palette) PetscValidCharPointer(palette,2);
81   PetscValidCharPointer(pixels,5);
82 
83   /* open file and create libpng structures */
84   ierr = PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);CHKERRQ(ierr);
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");
89 
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
98 
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);
108 
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);
114 
115   /* destroy libpng structures and close file */
116   png_destroy_write_struct(&png_ptr, &info_ptr);
117   ierr = PetscFClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
118   PetscFunctionReturn(0);
119 }
120 
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); }
123 
124 #endif/*!PETSC_HAVE_LIBPNG*/
125 
126 
127 /*
128    Code to write images in GIF format
129 */
130 #if defined(PETSC_HAVE_GIFLIB)
131 
132 #include <gif_lib.h>
133 
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 #endif
141 
142 #undef __FUNCT__
143 #define __FUNCT__ "PetscDrawImageSaveGIF"
144 PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
145 {
146   int            Row, Error;
147   int            Width  = (int)w;
148   int            Height = (int)h;
149   int            ColorRes   = 8;
150   int            ColorCount = 256;
151   ColorMapObject *GifCMap = NULL;
152   GifFileType    *GifFile = NULL;
153 # define         SETERRGIF(msg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
154 # define         CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while(0)
155 
156   PetscFunctionBegin;
157   PetscValidCharPointer(filename,1);
158   PetscValidCharPointer(palette,2);
159   PetscValidCharPointer(pixels,5);
160 
161   GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
162   GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
163   Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
164   Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
165   for (Row = 0; Row < Height; Row++) {
166     Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
167   }
168   Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
169   GifFreeMapObject(GifCMap); GifCMap = NULL;
170 
171 # undef SETERRGIF
172 # undef CHKERRGIF
173   PetscFunctionReturn(0);
174 }
175 
176 static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
177 { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }
178 
179 #endif/*!PETSC_HAVE_GIFLIB*/
180 
181 /*
182    Code to write images in JPEG format
183 */
184 #if defined(PETSC_HAVE_LIBJPEG)
185 
186 #include <jpeglib.h>
187 
188 #if defined(PETSC_HAVE_SETJMP_H)
189 #include <setjmp.h>
190 static jmp_buf petsc_jpeg_jumpbuf;
191 static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
192 #endif
193 
194 #undef __FUNCT__
195 #define __FUNCT__ "PetscDrawImageSaveJPG"
196 PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
197 {
198   unsigned char               *rgbpixels;
199   FILE                        *fp;
200   struct jpeg_compress_struct cinfo;
201   struct jpeg_error_mgr       jerr;
202   PetscErrorCode              ierr;
203 
204   PetscFunctionBegin;
205   PetscValidCharPointer(filename,1);
206   if (palette) PetscValidCharPointer(palette,2);
207   PetscValidCharPointer(pixels,5);
208   /* map pixels to RGB colors */
209   if (palette) {
210     int k,p,n = (int)(w*h);
211     const unsigned char *colordef;
212     ierr = PetscMalloc1(3*w*h,&rgbpixels);CHKERRQ(ierr);
213     for (k=p=0; k<n; k++) {
214       colordef = palette[pixels[k]];
215       rgbpixels[p++] = colordef[0];
216       rgbpixels[p++] = colordef[1];
217       rgbpixels[p++] = colordef[2];
218     }
219   } else { /* assume pixels are RGB colors */
220     rgbpixels = (unsigned char*)pixels;
221   }
222   ierr = PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);CHKERRQ(ierr);
223 
224   cinfo.err = jpeg_std_error(&jerr);
225 #if defined(PETSC_HAVE_SETJMP_H)
226   jerr.error_exit = petsc_jpeg_error_longjmp;
227   if (setjmp(petsc_jpeg_jumpbuf)) {
228     char message[JMSG_LENGTH_MAX];
229     jerr.format_message((j_common_ptr)&cinfo,message);
230     jpeg_destroy_compress(&cinfo);
231     (void)PetscFClose(PETSC_COMM_SELF,fp);
232     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
233   }
234 #endif
235   jpeg_create_compress(&cinfo);
236   jpeg_stdio_dest(&cinfo,fp);
237   cinfo.image_width      = w;
238   cinfo.image_height     = h;
239   cinfo.input_components = 3;
240   cinfo.in_color_space   = JCS_RGB;
241   jpeg_set_defaults(&cinfo);
242   jpeg_start_compress(&cinfo,TRUE);
243   while (cinfo.next_scanline < cinfo.image_height) {
244     unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
245     (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
246   }
247   jpeg_finish_compress(&cinfo);
248   jpeg_destroy_compress(&cinfo);
249 
250   ierr = PetscFClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
251   if (palette) {ierr = PetscFree(rgbpixels);CHKERRQ(ierr);}
252   PetscFunctionReturn(0);
253 }
254 
255 static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
256 { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }
257 
258 #endif/*!PETSC_HAVE_LIBJPEG*/
259 
260 static struct {
261   const char      *extension;
262   PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
263 } PetscDrawImageSaveTable[] = {
264 #if defined(PETSC_HAVE_LIBPNG)
265   {".png", PetscDrawImageSave_PNG},
266 #endif
267 #if defined(PETSC_HAVE_GIFLIB)
268   {".gif", PetscDrawImageSave_GIF},
269 #endif
270 #if defined(PETSC_HAVE_LIBJPEG)
271   {".jpg", PetscDrawImageSave_JPG},
272 #endif
273   {".ppm", PetscDrawImageSave_PPM}
274 };
275 
276 #undef __FUNCT__
277 #define __FUNCT__ "PetscDrawImageCheckFormat"
278 PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
279 {
280   size_t         k;
281   PetscBool      match = PETSC_FALSE;
282   PetscErrorCode ierr;
283 
284   PetscFunctionBegin;
285   /* if extension is empty, return default format to caller */
286   PetscValidPointer(ext,1);
287   if (!*ext || !**ext) {
288     *ext = PetscDrawImageSaveTable[0].extension;
289     PetscFunctionReturn(0);
290   }
291   /* check the extension mathes a supported format otherwise */
292   PetscValidCharPointer(*ext,1);
293   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
294     ierr = PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr);
295     if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(0);
296   }
297   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext);
298   PetscFunctionReturn(PETSC_ERR_SUP);
299 }
300 
301 #undef __FUNCT__
302 #define __FUNCT__ "PetscDrawImageSave"
303 PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
304 {
305   size_t         k;
306   PetscBool      match = PETSC_FALSE;
307   char           filename[PETSC_MAX_PATH_LEN];
308   PetscErrorCode ierr;
309 
310   PetscFunctionBegin;
311   PetscValidCharPointer(basename,1);
312   if (ext) PetscValidCharPointer(ext,2);
313   if (palette) PetscValidCharPointer(palette,3);
314   PetscValidCharPointer(pixels,6);
315 
316   ierr = PetscDrawImageCheckFormat(&ext);CHKERRQ(ierr);
317   ierr = PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);CHKERRQ(ierr);
318   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
319     ierr = PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr);
320     if (match && PetscDrawImageSaveTable[k].SaveImage) {
321       ierr = PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);CHKERRQ(ierr);
322       PetscFunctionReturn(0);
323     }
324   }
325   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
326   PetscFunctionReturn(PETSC_ERR_SUP);
327 }
328 
329 #undef __FUNCT__
330 #define __FUNCT__ "PetscDrawMovieCheckFormat"
331 PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
332 {
333   PetscFunctionBegin;
334   PetscValidPointer(ext,1);
335   if (!*ext || !**ext) *ext = ".m4v";
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "PetscDrawMovieSave"
341 PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
342 {
343   PetscBool      imgif;
344   PetscErrorCode ierr;
345 
346   PetscFunctionBegin;
347   PetscValidCharPointer(basename,1);
348   PetscValidCharPointer(imext,3);
349   if (mvext) PetscValidCharPointer(mvext,4);
350   if (count < 1) PetscFunctionReturn(0);
351 
352   ierr = PetscStrcasecmp(imext,".gif",&imgif);CHKERRQ(ierr);
353   ierr = PetscDrawMovieCheckFormat(&mvext);CHKERRQ(ierr);
354 
355 #if defined(PETSC_HAVE_POPEN)
356   /* use ffmpeg to generate a movie */
357   {
358     PetscInt i;
359     FILE     *fd;
360     char     ffmpeg[64] = "ffmpeg -loglevel error -y", framerate[24] = "";
361     char     input[PETSC_MAX_PATH_LEN], output[PETSC_MAX_PATH_LEN];
362     char     command[sizeof(ffmpeg)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
363     if (fps > 0 && !imgif) { /* ffmpeg seems to have trouble with non-animated GIF input */
364       ierr = PetscSNPrintf(framerate,sizeof(framerate)," -framerate %d",(int)fps);CHKERRQ(ierr);
365       ierr = PetscStrcat(ffmpeg,framerate);CHKERRQ(ierr);
366     }
367     ierr = PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);CHKERRQ(ierr);
368     ierr = PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);CHKERRQ(ierr);
369     if (imgif) {
370       ierr = PetscStrcat(ffmpeg," -f concat");CHKERRQ(ierr);
371       ierr = PetscSNPrintf(input,sizeof(input),"%s/%s.filelist",basename,basename);CHKERRQ(ierr);
372       ierr = PetscFOpen(PETSC_COMM_SELF,input,"w",&fd);CHKERRQ(ierr);
373       ierr = PetscFPrintf(PETSC_COMM_SELF,fd,"# ffmpeg%s -f concat -i \"%s.filelist\" \"%s\"\n",framerate,basename,output);CHKERRQ(ierr);
374       for (i=0; i<count; i++) {ierr = PetscFPrintf(PETSC_COMM_SELF,fd,"file '%s_%d%s'\n",basename,i,imext);CHKERRQ(ierr);}
375       ierr = PetscFClose(PETSC_COMM_SELF,fd);CHKERRQ(ierr);
376     }
377     ierr = PetscSNPrintf(command,sizeof(command),"%s -i \"%s\" \"%s\"",ffmpeg,input,output);CHKERRQ(ierr);
378     ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);CHKERRQ(ierr);
379     ierr = PetscPClose(PETSC_COMM_SELF,fd,NULL);CHKERRQ(ierr);
380   }
381 #endif
382   PetscFunctionReturn(0);
383 }
384