Actual source code: image.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      1: #include <petsc/private/petscimpl.h>         /*I "petscsys.h" I*/

      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: */
     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;

     25:   /* map pixels to RGB colors */
     26:   if (palette) {
     27:     int k,p,n = (int)(w*h);
     28:     const unsigned char *colordef;
     29:     PetscMalloc1(3*w*h,&rgb);
     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:   PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);
     41:   PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n\0",(int)w,(int)h);
     42:   PetscStrlen(header,&hdrlen);
     43:   PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR,PETSC_FALSE);
     44:   /* write image data and close file */
     45:   PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR,PETSC_FALSE);
     46:   PetscBinaryClose(fd);
     47:   if (palette) {PetscFree(rgb);}
     48:   return(0);
     49: }

     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); }

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

     60: #include <png.h>

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

     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;

     83:   /* open file and create libpng structures */
     84:   PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);
     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");

     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

     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);

    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);

    115:   /* destroy libpng structures and close file */
    116:   png_destroy_write_struct(&png_ptr, &info_ptr);
    117:   PetscFClose(PETSC_COMM_SELF,fp);
    118:   return(0);
    119: }

    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); }

    124: #endif/*!PETSC_HAVE_LIBPNG*/

    127: /*
    128:    Code to write images in GIF format
    129: */
    130: #if defined(PETSC_HAVE_GIFLIB)

    132: #include <gif_lib.h>

    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: #define DGifOpenFileName(n,err)   DGifOpenFileName(n)
    141: #define DGifOpenFileHandle(h,err) DGifOpenFileName(h)
    142: #define DGifCloseFile(f,err)      DGifCloseFile(f)
    143: #endif

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

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

    174: # undef SETERRGIF
    175: # undef CHKERRGIF
    176:   return(0);
    177: }

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

    184: PETSC_EXTERN PetscErrorCode PetscDrawMovieSaveGIF(const char pattern[],PetscInt count,const char movie[])
    185: {
    186:   int            i,j,Row;
    187:   char           image[PETSC_MAX_PATH_LEN];
    188:   GifFileType    *GifMovie = NULL;
    189:   GifFileType    *GifImage = NULL;
    191: # define         SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn)

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

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

    240: # undef SETERRGIF
    241:   return(0);
    242: }

    244: #endif/*!PETSC_HAVE_GIFLIB*/

    246: /*
    247:    Code to write images in JPEG format
    248: */
    249: #if defined(PETSC_HAVE_LIBJPEG)

    251: #include <jpeglib.h>

    253: #if defined(PETSC_HAVE_SETJMP_H)
    254: #include <setjmp.h>
    255: static jmp_buf petsc_jpeg_jumpbuf;
    256: static void petsc_jpeg_error_longjmp (j_common_ptr cinfo) { (void)cinfo; longjmp(petsc_jpeg_jumpbuf,1); }
    257: #endif

    261: PETSC_EXTERN PetscErrorCode PetscDrawImageSaveJPG(const char filename[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
    262: {
    263:   unsigned char               *rgbpixels;
    264:   FILE                        *fp;
    265:   struct jpeg_compress_struct cinfo;
    266:   struct jpeg_error_mgr       jerr;
    267:   PetscErrorCode              ierr;

    273:   /* map pixels to RGB colors */
    274:   if (palette) {
    275:     int k,p,n = (int)(w*h);
    276:     const unsigned char *colordef;
    277:     PetscMalloc1(3*w*h,&rgbpixels);
    278:     for (k=p=0; k<n; k++) {
    279:       colordef = palette[pixels[k]];
    280:       rgbpixels[p++] = colordef[0];
    281:       rgbpixels[p++] = colordef[1];
    282:       rgbpixels[p++] = colordef[2];
    283:     }
    284:   } else { /* assume pixels are RGB colors */
    285:     rgbpixels = (unsigned char*)pixels;
    286:   }
    287:   PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);

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

    315:   PetscFClose(PETSC_COMM_SELF,fp);
    316:   if (palette) {PetscFree(rgbpixels);}
    317:   return(0);
    318: }

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

    323: #endif/*!PETSC_HAVE_LIBJPEG*/

    325: static struct {
    326:   const char      *extension;
    327:   PetscErrorCode (*SaveImage)(const char[],unsigned char[][3],unsigned int,unsigned int,const unsigned char[]);
    328: } PetscDrawImageSaveTable[] = {
    329: #if defined(PETSC_HAVE_LIBPNG)
    330:   {".png", PetscDrawImageSave_PNG},
    331: #endif
    332: #if defined(PETSC_HAVE_GIFLIB)
    333:   {".gif", PetscDrawImageSave_GIF},
    334: #endif
    335: #if defined(PETSC_HAVE_LIBJPEG)
    336:   {".jpg", PetscDrawImageSave_JPG},
    337: #endif
    338:   {".ppm", PetscDrawImageSave_PPM}
    339: };

    343: PetscErrorCode PetscDrawImageCheckFormat(const char *ext[])
    344: {
    345:   size_t         k;
    346:   PetscBool      match = PETSC_FALSE;

    350:   /* if extension is empty, return default format to caller */
    352:   if (!*ext || !**ext) {
    353:     *ext = PetscDrawImageSaveTable[0].extension;
    354:     return(0);
    355:   }
    356:   /* check the extension mathes a supported format otherwise */
    358:   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
    359:     PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);
    360:     if (match && PetscDrawImageSaveTable[k].SaveImage) return(0);
    361:   }
    362:   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext);
    363:   PetscFunctionReturn(PETSC_ERR_SUP);
    364: }

    368: PetscErrorCode PetscDrawImageSave(const char basename[],const char ext[],unsigned char palette[][3],unsigned int w,unsigned int h,const unsigned char pixels[])
    369: {
    370:   size_t         k;
    371:   PetscBool      match = PETSC_FALSE;
    372:   char           filename[PETSC_MAX_PATH_LEN];

    381:   PetscDrawImageCheckFormat(&ext);
    382:   PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);
    383:   for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) {
    384:     PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);
    385:     if (match && PetscDrawImageSaveTable[k].SaveImage) {
    386:       PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);
    387:       return(0);
    388:     }
    389:   }
    390:   SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext);
    391:   PetscFunctionReturn(PETSC_ERR_SUP);
    392: }

    396: PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[])
    397: {
    400:   if (!*ext || !**ext) *ext = ".m4v";
    401:   return(0);
    402: }

    406: PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[])
    407: {
    408:   char           input[PETSC_MAX_PATH_LEN];
    409:   char           output[PETSC_MAX_PATH_LEN];
    410:   PetscBool      gifinput;

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

    419:   PetscStrcasecmp(imext,".gif",&gifinput);
    420:   PetscDrawMovieCheckFormat(&mvext);
    421:   PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);
    422:   PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);

    424:   /* use GIFLIB to generate an intermediate GIF animation */
    425: #if defined(PETSC_HAVE_GIFLIB)
    426:   if (gifinput) {
    427:     char gifmovie[PETSC_MAX_PATH_LEN];
    428:     PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);
    429:     PetscDrawMovieSaveGIF(input,count,gifmovie);
    430:     PetscStrcpy(input,gifmovie);
    431:   }
    432: #endif

    434:   /* use FFmpeg to generate a movie */
    435: #if defined(PETSC_HAVE_POPEN)
    436:   {
    437:     FILE *fd; int err;
    438:     char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = "";
    439:     char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2];
    440:     if (fps > 0) {PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);}
    441:     if (gifinput) {
    442:       PetscStrcat(options," -f gif");
    443:       PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);
    444:     } else {
    445:       PetscStrcat(options," -f image2");
    446:       if (fps > 0) {PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);}
    447:     }
    448:     if (extraopts[0]) {PetscStrcat(options,extraopts);}
    449:     PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);
    450:     PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);
    451:     PetscPClose(PETSC_COMM_SELF,fd,&err);
    452:   }
    453: #endif
    454:   return(0);
    455: }