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 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; 17 PetscErrorCode ierr; 18 19 PetscFunctionBegin; 20 PetscValidCharPointer(filename,1); 21 if (palette) PetscValidCharPointer(palette,2); 22 PetscValidCharPointer(pixels,5); 23 /* map pixels to RGB colors */ 24 if (palette) { 25 int k,p,n = (int)(w*h); 26 const unsigned char *colordef; 27 ierr = PetscMalloc1(3*w*h,&rgb);CHKERRQ(ierr); 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 ierr = PetscBinaryOpen(filename,FILE_MODE_WRITE,&fd);CHKERRQ(ierr); 39 ierr = PetscSNPrintf(header,sizeof(header),"P6\n%d %d\n255\n\0",(int)w,(int)h);CHKERRQ(ierr); 40 ierr = PetscStrlen(header,&hdrlen);CHKERRQ(ierr); 41 ierr = PetscBinaryWrite(fd,header,hdrlen,PETSC_CHAR);CHKERRQ(ierr); 42 /* write image data and close file */ 43 ierr = PetscBinaryWrite(fd,rgb,3*w*h,PETSC_CHAR);CHKERRQ(ierr); 44 ierr = PetscBinaryClose(fd);CHKERRQ(ierr); 45 if (palette) {ierr = PetscFree(rgb);CHKERRQ(ierr);} 46 PetscFunctionReturn(0); 47 } 48 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); } 51 52 53 /* 54 Code to write images in PNG format 55 */ 56 #if defined(PETSC_HAVE_LIBPNG) 57 58 #include <png.h> 59 60 #if defined(PNG_SETJMP_SUPPORTED) 61 # ifndef png_jmpbuf 62 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 63 # endif 64 #endif 65 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; 72 PetscErrorCode ierr; 73 74 PetscFunctionBegin; 75 PetscValidCharPointer(filename,1); 76 if (palette) PetscValidCharPointer(palette,2); 77 PetscValidCharPointer(pixels,5); 78 79 /* open file and create libpng structures */ 80 ierr = PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);CHKERRQ(ierr); 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"); 85 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 94 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); 104 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); 110 111 /* destroy libpng structures and close file */ 112 png_destroy_write_struct(&png_ptr, &info_ptr); 113 ierr = PetscFClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr); 114 PetscFunctionReturn(0); 115 } 116 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); } 119 120 #endif/*!PETSC_HAVE_LIBPNG*/ 121 122 123 /* 124 Code to write images in GIF format 125 */ 126 #if defined(PETSC_HAVE_GIFLIB) 127 128 #include <gif_lib.h> 129 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 140 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) 152 153 PetscFunctionBegin; 154 PetscValidCharPointer(filename,1); 155 PetscValidCharPointer(palette,2); 156 PetscValidCharPointer(pixels,5); 157 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; 167 168 # undef SETERRGIF 169 # undef CHKERRGIF 170 PetscFunctionReturn(0); 171 } 172 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); } 175 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; 182 PetscErrorCode ierr; 183 # define SETERRGIF(msg,fn) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,msg" GIF file %s",fn) 184 185 PetscFunctionBegin; 186 PetscValidCharPointer(pattern,1); 187 PetscValidCharPointer(movie,3); 188 if (count < 1) PetscFunctionReturn(0); 189 190 for (i = 0; i < count; i++) { 191 ierr = PetscSNPrintf(image,sizeof(image),pattern,(int)i);CHKERRQ(ierr); 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); 231 232 # undef SETERRGIF 233 PetscFunctionReturn(0); 234 } 235 236 #endif/*!PETSC_HAVE_GIFLIB*/ 237 238 /* 239 Code to write images in JPEG format 240 */ 241 #if defined(PETSC_HAVE_LIBJPEG) 242 243 #include <jpeglib.h> 244 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 250 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; 258 259 PetscFunctionBegin; 260 PetscValidCharPointer(filename,1); 261 if (palette) PetscValidCharPointer(palette,2); 262 PetscValidCharPointer(pixels,5); 263 /* map pixels to RGB colors */ 264 if (palette) { 265 int k,p,n = (int)(w*h); 266 const unsigned char *colordef; 267 ierr = PetscMalloc1(3*w*h,&rgbpixels);CHKERRQ(ierr); 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 ierr = PetscFOpen(PETSC_COMM_SELF,filename,"wb",&fp);CHKERRQ(ierr); 278 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); 304 305 ierr = PetscFClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr); 306 if (palette) {ierr = PetscFree(rgbpixels);CHKERRQ(ierr);} 307 PetscFunctionReturn(0); 308 } 309 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); } 312 313 #endif/*!PETSC_HAVE_LIBJPEG*/ 314 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 }; 330 331 PetscErrorCode PetscDrawImageCheckFormat(const char *ext[]) 332 { 333 size_t k; 334 PetscBool match = PETSC_FALSE; 335 PetscErrorCode ierr; 336 337 PetscFunctionBegin; 338 /* if extension is empty, return default format to caller */ 339 PetscValidPointer(ext,1); 340 if (!*ext || !**ext) { 341 *ext = PetscDrawImageSaveTable[0].extension; 342 PetscFunctionReturn(0); 343 } 344 /* check the extension matches a supported format */ 345 PetscValidCharPointer(*ext,1); 346 for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) { 347 ierr = PetscStrcasecmp(*ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr); 348 if (match && PetscDrawImageSaveTable[k].SaveImage) PetscFunctionReturn(0); 349 } 350 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm or see PetscDrawSetSave() for what ./configure option you may need",*ext); 351 PetscFunctionReturn(0); 352 } 353 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]; 359 PetscErrorCode ierr; 360 361 PetscFunctionBegin; 362 PetscValidCharPointer(basename,1); 363 if (ext) PetscValidCharPointer(ext,2); 364 if (palette) PetscValidCharPointer(palette,3); 365 PetscValidCharPointer(pixels,6); 366 367 ierr = PetscDrawImageCheckFormat(&ext);CHKERRQ(ierr); 368 ierr = PetscSNPrintf(filename,sizeof(filename),"%s%s",basename,ext);CHKERRQ(ierr); 369 for (k=0; k<sizeof(PetscDrawImageSaveTable)/sizeof(PetscDrawImageSaveTable[0]); k++) { 370 ierr = PetscStrcasecmp(ext,PetscDrawImageSaveTable[k].extension,&match);CHKERRQ(ierr); 371 if (match && PetscDrawImageSaveTable[k].SaveImage) { 372 ierr = PetscDrawImageSaveTable[k].SaveImage(filename,palette,w,h,pixels);CHKERRQ(ierr); 373 PetscFunctionReturn(0); 374 } 375 } 376 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Image extension %s not supported, use .ppm",ext); 377 } 378 379 PetscErrorCode PetscDrawMovieCheckFormat(const char *ext[]) 380 { 381 PetscFunctionBegin; 382 PetscValidPointer(ext,1); 383 if (!*ext || !**ext) *ext = ".m4v"; 384 PetscFunctionReturn(0); 385 } 386 387 PetscErrorCode PetscDrawMovieSave(const char basename[],PetscInt count,const char imext[],PetscInt fps,const char mvext[]) 388 { 389 char input[PETSC_MAX_PATH_LEN]; 390 char output[PETSC_MAX_PATH_LEN]; 391 PetscBool gifinput; 392 PetscErrorCode ierr; 393 394 PetscFunctionBegin; 395 PetscValidCharPointer(basename,1); 396 PetscValidCharPointer(imext,3); 397 if (mvext) PetscValidCharPointer(mvext,4); 398 if (count < 1) PetscFunctionReturn(0); 399 400 ierr = PetscStrcasecmp(imext,".gif",&gifinput);CHKERRQ(ierr); 401 ierr = PetscDrawMovieCheckFormat(&mvext);CHKERRQ(ierr); 402 ierr = PetscSNPrintf(input,sizeof(input),"%s/%s_%%d%s",basename,basename,imext);CHKERRQ(ierr); 403 ierr = PetscSNPrintf(output,sizeof(output),"%s%s",basename,mvext);CHKERRQ(ierr); 404 405 /* use GIFLIB to generate an intermediate GIF animation */ 406 #if defined(PETSC_HAVE_GIFLIB) 407 if (gifinput) { 408 char gifmovie[PETSC_MAX_PATH_LEN]; 409 ierr = PetscSNPrintf(gifmovie,sizeof(gifmovie),"%s/%s_movie.gif",basename,basename);CHKERRQ(ierr); 410 ierr = PetscDrawMovieSaveGIF(input,count,gifmovie);CHKERRQ(ierr); 411 ierr = PetscStrcpy(input,gifmovie);CHKERRQ(ierr); 412 } 413 #endif 414 415 /* use FFmpeg to generate a movie */ 416 #if defined(PETSC_HAVE_POPEN) 417 { 418 FILE *fd; 419 char options[64] = "-loglevel error -y", extraopts[32] = "", framerate[24] = ""; 420 char command[sizeof(options)+sizeof(extraopts)+sizeof(framerate)+PETSC_MAX_PATH_LEN*2]; 421 if (fps > 0) {ierr = PetscSNPrintf(framerate,sizeof(framerate),"-r %d",(int)fps);CHKERRQ(ierr);} 422 if (gifinput) { 423 ierr = PetscStrlcat(options," -f gif",sizeof(options));CHKERRQ(ierr); 424 ierr = PetscSNPrintf(extraopts,sizeof(extraopts)," -default_delay %d",(fps > 0) ? 100/(int)fps : 4);CHKERRQ(ierr); 425 } else { 426 ierr = PetscStrlcat(options," -f image2",sizeof(options));CHKERRQ(ierr); 427 if (fps > 0) {ierr = PetscSNPrintf(extraopts,sizeof(extraopts)," -framerate %d",(int)fps);CHKERRQ(ierr);} 428 } 429 if (extraopts[0]) {ierr = PetscStrlcat(options,extraopts,sizeof(options));CHKERRQ(ierr);} 430 ierr = PetscSNPrintf(command,sizeof(command),"ffmpeg %s -i \"%s\" %s \"%s\"",options,input,framerate,output);CHKERRQ(ierr); 431 ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);CHKERRQ(ierr); 432 ierr = PetscPClose(PETSC_COMM_SELF,fd);CHKERRQ(ierr); 433 } 434 #endif 435 PetscFunctionReturn(0); 436 } 437