Actual source code: image.c

petsc-3.9.4 2018-09-11
Report Typos and Errors
  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,PETSC_FALSE);
 42:   /* write image data and close file */
 43:   PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR,PETSC_FALSE);
 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); }


 53: /*
 54:    Code to write images in PNG format
 55: */
 56: #if defined(PETSC_HAVE_LIBPNG)

 58: #include <png.h>

 60: #if defined(PNG_SETJMP_SUPPORTED)
 61: # ifndef png_jmpbuf
 62: #   define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
 63: # endif
 64: #endif

 66: PETSC_EXTERN PetscErrorCode PetscDrawImageSavePNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
 67: {
 68:   FILE           *fp;
 69:   png_struct     *png_ptr;
 70:   png_info       *info_ptr;
 71:   unsigned int   row, stride = palette ? w : 3*w;


 79:   /* open file and create libpng structures */
 80:   PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
 81:   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
 82:   if (!png_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");
 83:   info_ptr = png_create_info_struct(png_ptr);
 84:   if (!info_ptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot create PNG context");

 86:   /* setup libpng error handling */
 87: #if defined(PNG_SETJMP_SUPPORTED)
 88:   if (setjmp(png_jmpbuf(png_ptr))) {
 89:     png_destroy_write_struct(&png_ptr,&info_ptr);
 90:     (void)PetscFClose(PETSC_COMM_SELF,fp);
 91:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing PNG file %s",filename);
 92:   }
 93: #endif

 95:   /* setup PNG image metadata */
 96:   png_init_io(png_ptr, fp);
 97:   png_set_IHDR(png_ptr, info_ptr, w, h, /*depth*/8,
 98:                palette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
 99:                PNG_INTERLACE_NONE,
100:                PNG_COMPRESSION_TYPE_DEFAULT,
101:                PNG_FILTER_TYPE_DEFAULT);
102:   if (palette)
103:     png_set_PLTE(png_ptr, info_ptr, (png_color*)palette, 256);

105:   /* write PNG image header and data */
106:   png_write_info(png_ptr, info_ptr);
107:   for (row = 0; row < h; row++)
108:     png_write_row(png_ptr, pixels + row*stride);
109:   png_write_end(png_ptr, NULL);

111:   /* destroy libpng structures and close file */
112:   png_destroy_write_struct(&png_ptr, &info_ptr);
113:   PetscFClose(PETSC_COMM_SELF,fp);
114:   return(0);
115: }

117: static PetscErrorCode PetscDrawImageSave_PNG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
118: { return PetscDrawImageSavePNG(filename,palette,w,h,pixels); }

120: #endif/*!PETSC_HAVE_LIBPNG*/


123: /*
124:    Code to write images in GIF format
125: */
126: #if defined(PETSC_HAVE_GIFLIB)

128: #include <gif_lib.h>

130: #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
131: #define GifMakeMapObject          MakeMapObject
132: #define GifFreeMapObject          FreeMapObject
133: #define EGifOpenFileName(n,b,err) EGifOpenFileName(n,b)
134: #define EGifOpenFileHandle(h,err) EGifOpenFileName(h)
135: #define EGifCloseFile(f,err)      EGifCloseFile(f)
136: #define DGifOpenFileName(n,err)   DGifOpenFileName(n)
137: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
138: #define DGifCloseFile(f,err)      DGifCloseFile(f)
139: #endif

141: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveGIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
142: {
143:   int            Row, Error;
144:   int            Width  = (int)w;
145:   int            Height = (int)h;
146:   int            ColorRes   = 8;
147:   int            ColorCount = 256;
148:   ColorMapObject *GifCMap = NULL;
149:   GifFileType    *GifFile = NULL;
150: # define         SETERRGIF(msg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg", GIF file: %s",filename)
151: # define         CHKERRGIF(msg) do {if (Error != GIF_OK) SETERRGIF(msg);} while(0)


158:   GifCMap = GifMakeMapObject(ColorCount, (GifColorType*)palette); if (!GifCMap) SETERRGIF("Allocating colormap");
159:   GifFile = EGifOpenFileName(filename, 0, NULL); if (!GifFile) SETERRGIF("Opening");
160:   Error = EGifPutScreenDesc(GifFile, Width, Height, ColorRes, 0, GifCMap); CHKERRGIF("Writing screen descriptor");
161:   Error = EGifPutImageDesc(GifFile, 0, 0, Width, Height, 0, NULL); CHKERRGIF("Writing image descriptor");
162:   for (Row = 0; Row < Height; Row++) {
163:     Error = EGifPutLine(GifFile, (GifPixelType*)pixels + Row*Width, Width); CHKERRGIF("Writing image pixels");
164:   }
165:   Error = EGifCloseFile(GifFile, NULL); CHKERRGIF("Closing");
166:   GifFreeMapObject(GifCMap); GifCMap = NULL;

168: # undef SETERRGIF
169: # undef CHKERRGIF
170:   return(0);
171: }

173: static PetscErrorCode PetscDrawImageSave_GIF(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
174: { return PetscDrawImageSaveGIF(filename,palette,w,h,pixels); }

176: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
177: {
178:   int            i,j,Row;
179:   char           image[PETSC_MAX_PATH_LEN];
180:   GifFileType    *GifMovie = NULL;
181:   GifFileType    *GifImage = NULL;
183: # define         SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)

188:   if (count < 1) return(0);

190:   for (i = 0; i < count; i++) {
191:     PetscSNPrintf(image,sizeof(image),pattern,(int)i);
192:     /* open and read image file */
193:     if ((GifImage = DGifOpenFileName(image, NULL)) == NULL) SETERRGIF("Opening input",image);
194:     if (DGifSlurp(GifImage) != GIF_OK) SETERRGIF("Reading input",image);
195:     /* open movie file and write header */
196:     if (i == 0) {
197:       if ((GifMovie = EGifOpenFileName(movie, 0, NULL)) == NULL) SETERRGIF("Opening output",movie);
198:       if (EGifPutScreenDesc(GifMovie,
199:                             GifImage->SWidth,
200:                             GifImage->SHeight,
201:                             GifImage->SColorResolution,
202:                             GifImage->SBackGroundColor,
203:                             GifImage->SColorMap) != GIF_OK) SETERRGIF("Writing screen descriptor,",movie);
204:     }
205:     /* loop over all frames in image */
206:     for (j = 0; j < GifImage->ImageCount; j++) {
207:       SavedImage *sp = &GifImage->SavedImages[j];
208:       GifImageDesc *GifFrame = &sp->ImageDesc;
209:       ColorMapObject *FrameColorMap = GifFrame->ColorMap ? GifFrame->ColorMap : GifImage->SColorMap;
210:       if (GifMovie->SColorMap && GifMovie->SColorMap->ColorCount == FrameColorMap->ColorCount &&
211:           !memcmp(GifMovie->SColorMap->Colors,FrameColorMap->Colors,
212:                   (size_t)FrameColorMap->ColorCount*sizeof(GifColorType)))
213:         FrameColorMap = NULL;
214:       /* add frame to movie */
215:       if (EGifPutImageDesc(GifMovie,
216:                            GifFrame->Left,
217:                            GifFrame->Top,
218:                            GifFrame->Width,
219:                            GifFrame->Height,
220:                            GifFrame->Interlace,
221:                            FrameColorMap) != GIF_OK) SETERRGIF("Writing image descriptor,",movie);
222:       for (Row = 0; Row < GifFrame->Height; Row++) {
223:         if (EGifPutLine(GifMovie,
224:                         sp->RasterBits + Row * GifFrame->Width,
225:                         GifFrame->Width) != GIF_OK) SETERRGIF("Writing image pixels,",movie);
226:       }
227:     }
228:     if (DGifCloseFile(GifImage, NULL) != GIF_OK) SETERRGIF("Closing input",image);
229:   }
230:   if (EGifCloseFile(GifMovie, NULL) != GIF_OK) SETERRGIF("Closing output",movie);

232: # undef SETERRGIF
233:   return(0);
234: }

236: #endif/*!PETSC_HAVE_GIFLIB*/

238: /*
239:    Code to write images in JPEG format
240: */
241: #if defined(PETSC_HAVE_LIBJPEG)

243: #include <jpeglib.h>

245: #if defined(PETSC_HAVE_SETJMP_H)
246: #include <setjmp.h>
247: static jmp_buf petsc_jpeg_jumpbuf;
248: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
249: #endif

251: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
252: {
253:   unsigned char               *rgbpixels;
254:   FILE                        *fp;
255:   struct jpeg_compress_struct cinfo;
256:   struct jpeg_error_mgr       jerr;
257:   PetscErrorCode              ierr;

263:   /* map pixels to RGB colors */
264:   if (palette) {
265:     int k,p,n = (int)(w*h);
266:     const unsigned char *colordef;
267:     PetscMalloc1(3*w*h,&rgbpixels);
268:     for (k=p=0; k<n; k++) {
269:       colordef = palette[pixels[k]];
270:       rgbpixels[p++] = colordef[0];
271:       rgbpixels[p++] = colordef[1];
272:       rgbpixels[p++] = colordef[2];
273:     }
274:   } else { /* assume pixels are RGB colors */
275:     rgbpixels = (unsigned char*)pixels;
276:   }
277:   PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);

279:   cinfo.err = jpeg_std_error(&jerr);
280: #if defined(PETSC_HAVE_SETJMP_H)
281:   jerr.error_exit = petsc_jpeg_error_longjmp;
282:   if (setjmp(petsc_jpeg_jumpbuf)) {
283:     char message[JMSG_LENGTH_MAX];
284:     jerr.format_message((j_common_ptr)&cinfo,message);
285:     jpeg_destroy_compress(&cinfo);
286:     (void)PetscFClose(PETSC_COMM_SELF,fp);
287:     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error writing JPEG file %s\n%s",filename,message);
288:   }
289: #endif
290:   jpeg_create_compress(&cinfo);
291:   jpeg_stdio_dest(&cinfo,fp);
292:   cinfo.image_width      = w;
293:   cinfo.image_height     = h;
294:   cinfo.input_components = 3;
295:   cinfo.in_color_space   = JCS_RGB;
296:   jpeg_set_defaults(&cinfo);
297:   jpeg_start_compress(&cinfo,TRUE);
298:   while (cinfo.next_scanline < cinfo.image_height) {
299:     unsigned char *rowptr = rgbpixels + cinfo.next_scanline * 3*w;
300:     (void)jpeg_write_scanlines(&cinfo,&rowptr,1);
301:   }
302:   jpeg_finish_compress(&cinfo);
303:   jpeg_destroy_compress(&cinfo);

305:   PetscFClose(PETSC_COMM_SELF,fp);
306:   if (palette) {PetscFree(rgbpixels);}
307:   return(0);
308: }

310: static PetscErrorCode PetscDrawImageSave_JPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
311: { return PetscDrawImageSaveJPG(filename,palette,w,h,pixels); }

313: #endif/*!PETSC_HAVE_LIBJPEG*/

315: static struct {
316:   const char      *extension;
317:   PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
318: } PetscDrawImageSaveTable[] = {
319: #if defined(PETSC_HAVE_LIBPNG)
320:   {".png", PetscDrawImageSave_PNG},
321: #endif
322: #if defined(PETSC_HAVE_GIFLIB)
323:   {".gif", PetscDrawImageSave_GIF},
324: #endif
325: #if defined(PETSC_HAVE_LIBJPEG)
326:   {".jpg", PetscDrawImageSave_JPG},
327: #endif
328:   {".ppm", PetscDrawImageSave_PPM}
329: };

331: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
332: {
333:   size_t         k;
334:   PetscBool      match = PETSC_FALSE;

338:   /* if extension is empty, return default format to caller */
340:   if (!*ext || !**ext) {
341:     *ext = PetscDrawImageSaveTable[0].extension;
342:     return(0);
343:   }
344:   /* check the extension mathes a supported format otherwise */
346:   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
347:     PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
348:     if (match && PetscDrawImageSaveTable[k].SaveImage) return(0);
349:   }
350:   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext);
351:   return(0);
352: }

354: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
355: {
356:   size_t         k;
357:   PetscBool      match = PETSC_FALSE;
358:   char           filename[PETSC_MAX_PATH_LEN];


367:   PetscDrawImageCheckFormat(&ext);
368:   PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
369:   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
370:     PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
371:     if (match && PetscDrawImageSaveTable[k].SaveImage) {
372:       PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
373:       return(0);
374:     }
375:   }
376:   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
377:   return(0);
378: }

380: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
381: {
384:   if (!*ext || !**ext) *ext = ".m4v";
385:   return(0);
386: }

388: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
389: {
390:   char           input[PETSC_MAX_PATH_LEN];
391:   char           output[PETSC_MAX_PATH_LEN];
392:   PetscBool      gifinput;

399:   if (count < 1) return(0);

401:   PetscStrcasecmp(imext,".gif",&gifinput);
402:   PetscDrawMovieCheckFormat(&mvext);
403:   PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
404:   PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);

406:   /* use GIFLIB to generate an intermediate GIF animation */
407: #if defined(PETSC_HAVE_GIFLIB)
408:   if (gifinput) {
409:     char gifmovie[PETSC_MAX_PATH_LEN];
410:     PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
411:     PetscDrawMovieSaveGIF(input,count,gifmovie);
412:     PetscStrcpy(input,gifmovie);
413:   }
414: #endif

416:   /* use FFmpeg to generate a movie */
417: #if defined(PETSC_HAVE_POPEN)
418:   {
419:     FILE *fd;
420:     char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
421:     char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
422:     if (fps > 0) {PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);}
423:     if (gifinput) {
424:       PetscStrlcat(options," -f gif",sizeof(options));
425:       PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
426:     } else {
427:       PetscStrlcat(options," -f image2",sizeof(options));
428:       if (fps > 0) {PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);}
429:     }
430:     if (extraopts[0]) {PetscStrlcat(options,extraopts,sizeof(options));}
431:     PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
432:     PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
433:     PetscPClose(PETSC_COMM_SELF,fd);
434:   }
435: #endif
436:   return(0);
437: }