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