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 #define DGifOpenFileName(n,err) DGifOpenFileName(n) 141 #define DGifOpenFileHandle(h,err) DGifOpenFileName(h) 142 #define DGifCloseFile(f,err) DGifCloseFile(f) 143 #endif 144 145 #undef __FUNCT__ 146 #define __FUNCT__ "PetscDrawImageSaveGIF" 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) 158 159 PetscFunctionBegin; 160 PetscValidCharPointer(filename,1); 161 PetscValidCharPointer(palette,2); 162 PetscValidCharPointer(pixels,5); 163 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; 173 174 # undef SETERRGIF 175 # undef CHKERRGIF 176 PetscFunctionReturn(0); 177 } 178 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); } 181 182 #undef __FUNCT__ 183 #define __FUNCT__ "PetscDrawMovieSaveGIF" 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; 190 PetscErrorCode ierr; 191 # define SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn) 192 193 PetscFunctionBegin; 194 PetscValidCharPointer(pattern,1); 195 PetscValidCharPointer(movie,3); 196 if (count < 1) PetscFunctionReturn(0); 197 198 for (i = 0; i < count; i++) { 199 ierr = PetscSNPrintf(image,sizeof(image),pattern,(int)i);CHKERRQ(ierr); 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); 239 240 # undef SETERRGIF 241 PetscFunctionReturn(0); 242 } 243 244 #endif/*!PETSC_HAVE_GIFLIB*/ 245 246 /* 247 Code to write images in JPEG format 248 */ 249 #if defined(PETSC_HAVE_LIBJPEG) 250 251 #include <jpeglib.h> 252 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 258 259 #undef __FUNCT__ 260 #define __FUNCT__ "PetscDrawImageSaveJPG" 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; 268 269 PetscFunctionBegin; 270 PetscValidCharPointer(filename,1); 271 if (palette) PetscValidCharPointer(palette,2); 272 PetscValidCharPointer(pixels,5); 273 /* map pixels to RGB colors */ 274 if (palette) { 275 int k,p,n = (int)(w*h); 276 const unsigned char *colordef; 277 ierr = PetscMalloc1(3*w*h,&rgbpixels);CHKERRQ(ierr); 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 ierr = PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);CHKERRQ(ierr); 288 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); 314 315 ierr = PetscFClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr); 316 if (palette) {ierr = PetscFree(rgbpixels);CHKERRQ(ierr);} 317 PetscFunctionReturn(0); 318 } 319 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); } 322 323 #endif/*!PETSC_HAVE_LIBJPEG*/ 324 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 }; 340 341 #undef __FUNCT__ 342 #define __FUNCT__ "PetscDrawImageCheckFormat" 343 PetscErrorCode PetscDrawImageCheckFormat(const char *ext[]) 344 { 345 size_t k; 346 PetscBool match = PETSC_FALSE; 347 PetscErrorCode ierr; 348 349 PetscFunctionBegin; 350 /* if extension is empty, return default format to caller */ 351 PetscValidPointer(ext,1); 352 if (!*ext || !**ext) { 353 *ext = PetscDrawImageSaveTable[0].extension; 354 PetscFunctionReturn(0); 355 } 356 /* check the extension mathes a supported format otherwise */ 357 PetscValidCharPointer(*ext,1); 358 for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) { 359 ierr = PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr); 360 if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(0); 361 } 362 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",*ext); 363 PetscFunctionReturn(PETSC_ERR_SUP); 364 } 365 366 #undef __FUNCT__ 367 #define __FUNCT__ "PetscDrawImageSave" 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]; 373 PetscErrorCode ierr; 374 375 PetscFunctionBegin; 376 PetscValidCharPointer(basename,1); 377 if (ext) PetscValidCharPointer(ext,2); 378 if (palette) PetscValidCharPointer(palette,3); 379 PetscValidCharPointer(pixels,6); 380 381 ierr = PetscDrawImageCheckFormat(&ext);CHKERRQ(ierr); 382 ierr = PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);CHKERRQ(ierr); 383 for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) { 384 ierr = PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr); 385 if (match && PetscDrawImageSaveTable[k].SaveImage) { 386 ierr = PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);CHKERRQ(ierr); 387 PetscFunctionReturn(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 } 393 394 #undef __FUNCT__ 395 #define __FUNCT__ "PetscDrawMovieCheckFormat" 396 PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[]) 397 { 398 PetscFunctionBegin; 399 PetscValidPointer(ext,1); 400 if (!*ext || !**ext) *ext = ".m4v"; 401 PetscFunctionReturn(0); 402 } 403 404 #undef __FUNCT__ 405 #define __FUNCT__ "PetscDrawMovieSave" 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; 411 PetscErrorCode ierr; 412 413 PetscFunctionBegin; 414 PetscValidCharPointer(basename,1); 415 PetscValidCharPointer(imext,3); 416 if (mvext) PetscValidCharPointer(mvext,4); 417 if (count < 1) PetscFunctionReturn(0); 418 419 ierr = PetscStrcasecmp(imext,".gif",&gifinput);CHKERRQ(ierr); 420 ierr = PetscDrawMovieCheckFormat(&mvext);CHKERRQ(ierr); 421 ierr = PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);CHKERRQ(ierr); 422 ierr = PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);CHKERRQ(ierr); 423 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 ierr = PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);CHKERRQ(ierr); 429 ierr = PetscDrawMovieSaveGIF(input,count,gifmovie);CHKERRQ(ierr); 430 ierr = PetscStrcpy(input,gifmovie);CHKERRQ(ierr); 431 } 432 #endif 433 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) {ierr = PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);CHKERRQ(ierr);} 441 if (gifinput) { 442 ierr = PetscStrcat(options," -f gif");CHKERRQ(ierr); 443 ierr = PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);CHKERRQ(ierr); 444 } else { 445 ierr = PetscStrcat(options," -f image2");CHKERRQ(ierr); 446 if (fps > 0) {ierr = PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);CHKERRQ(ierr);} 447 } 448 if (extraopts[0]) {ierr = PetscStrcat(options,extraopts);CHKERRQ(ierr);} 449 ierr = PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);CHKERRQ(ierr); 450 ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);CHKERRQ(ierr); 451 ierr = PetscPClose(PETSC_COMM_SELF,fd,&err);CHKERRQ(ierr); 452 } 453 #endif 454 PetscFunctionReturn(0); 455 } 456