INLINE void * gif_save(const Image *image, const ColorMapObject *color_map, Frame *frames, int count, int *size) { GifBuffer buf = {0,}; int estimated = count * (image->columns * image->rows); buf.alloc = estimated; buf.data = malloc(estimated); GifFileType *gif_file = EGifOpen(&buf, gif_buffer_write); if (!gif_file) { return NULL; } if (EGifPutScreenDesc(gif_file, image->columns, image->rows, NCOLORS, 0, color_map) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } if (EGifPutExtensionFirst(gif_file, APPLICATION_EXT_FUNC_CODE, strlen(GIF_APP), GIF_APP) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } unsigned char meta[] = { 0x01, // data sub-block index (always 1) 0xFF, 0xFF // 65535 repetitions - unsigned }; if (EGifPutExtensionLast(gif_file, APPLICATION_EXT_FUNC_CODE, sizeof(meta), meta) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } int ii; for (ii = 0; ii < count; ii++) { Frame *frame = &frames[ii]; // GCE unsigned char gce[] = { 0x08, // no transparency frame->duration % 256, // LSB of delay frame->duration / 256, // MSB of delay in millisecs 0x00, // no transparent color }; if (EGifPutExtension(gif_file, GRAPHICS_EXT_FUNC_CODE, sizeof(gce), gce) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } if (EGifPutImageDesc(gif_file, frame->x, frame->y, frame->width, frame->height, 0, NULL) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } int yy; GifPixelType *p = frame->data; for (yy = 0; yy < frame->height; yy++, p += frame->width) { if (EGifPutLine(gif_file, p, frame->width) == GIF_ERROR) { EGifCloseFile(gif_file); return NULL; } } } EGifCloseFile(gif_file); *size = buf.size; return buf.data; }
int main(int argc, char **argv) { FILE *input_file; float arg,size,rx,ry,rz; float f,fmin=1e10,fmax=-1e10; uint16_t i; uint64_t count; int xi,yi,zi,xo,yo,zo,nx,ny,nz,dx,dy,dz,x0,y0,z0,h; int **image; char format,type,comment[256]; GifFileType *GIFfile; ColorMapObject *GIFcmap; GifPixelType *GIFline; // // command line args // if (!((argc == 6) || (argc == 7) || (argc == 8) || (argc == 9) || (argc == 10) || (argc == 13) || (argc == 16) || (argc == 19))) { printf("command line: vol_gif in.vol out.gif nx ny nz [format [type [arg [size [dx dy dz [x0 y0 z0 [rx ry rz]]]]]]]\n"); printf(" in.vol = input volume file\n"); printf(" out.gif = output GIF file\n"); printf(" nx,ny,nz = x,y,z input voxel number\n"); printf(" format = 'f' for float 32, 'i' for uint16_t (default 'f')\n"); printf(" type = 's' for section, 'h' for height (default 's')\n"); printf(" arg = gamma for 's', threshold for 'h' (default 1)\n"); printf(" size = mm per voxel (default 1)\n"); printf(" dx,dy,dz = x,y,z output voxel number (default all)\n"); printf(" x0,y0,z0 = x,y,z output voxel origin (default 0)\n"); printf(" to be implemented: rx,ry,rz = view rotation angles (degrees; default 0)\n"); exit(-1); } format = 'f'; type = 's'; arg = 1; size = 1.0; rx = ry = rz = 0; sscanf(argv[3],"%d",&nx); sscanf(argv[4],"%d",&ny); sscanf(argv[5],"%d",&nz); dx = nx; dy = ny; dz = nz; x0 = y0 = z0 = 0; if (argc >= 7) { sscanf(argv[6],"%c",&format); if (!((format == 'f') || (format == 'i'))) { printf("vol_gif: oops -- format must be 'f' or 'i'\n"); exit(-1); } } if (argc >= 8) { sscanf(argv[7],"%c",&type); if (!((type == 's') || (type == 'h'))) { printf("vol_gif: oops -- type must be 's' or 'h'\n"); exit(-1); } } if (argc >= 9) { sscanf(argv[8],"%f",&arg); } if (argc >= 10) { sscanf(argv[9],"%f",&size); } if (argc >= 13) { sscanf(argv[10],"%d",&x0); sscanf(argv[11],"%d",&y0); sscanf(argv[12],"%d",&z0); } if (argc >= 16) { sscanf(argv[13],"%d",&dx); sscanf(argv[14],"%d",&dy); sscanf(argv[15],"%d",&dz); } if (argc >= 19) { sscanf(argv[16],"%f",&rx); sscanf(argv[17],"%f",&ry); sscanf(argv[18],"%f",&rz); } // // check and find limits // input_file = fopen(argv[1],"rb"); if (input_file == NULL) { printf("vol_gif: oops -- can not open %s\n",argv[1]); exit(-1); } if (((x0 + dx) > nx) || ((y0 + dy) > ny) || ((z0 + dz) > nz)) { printf("vol_gif: oops -- region too large\n"); exit(-1); } printf("read %s\n",argv[1]); if (format == 'f') { count = 0; while (fread(&f,sizeof(f),1,input_file) != 0) { if (f > fmax) fmax = f; if (f < fmin) fmin = f; count += 1; } } else if (format == 'i') { count = 0; while (fread(&i,sizeof(i),1,input_file) != 0) { if (i > fmax) fmax = i; if (i < fmin) fmin = i; count += 1; } } printf(" %" PRIu64 " points, min %f, max %f\n",count,fmin,fmax); printf(" nx ny nz: %d %d %d\n",nx,ny,nz); rewind(input_file); // // set up color map // #if GIFLIB_MAJOR >= 5 GIFcmap = GifMakeMapObject(256, NULL); #else GIFcmap = MakeMapObject(256, NULL); #endif for (i = 0; i < 256; i++) { GIFcmap->Colors[i].Red = i; GIFcmap->Colors[i].Green = i; GIFcmap->Colors[i].Blue = i; } // // open GIF file // printf("write %s\n",argv[2]); EGifPutScreenDesc(GIFfile,dx,dy,8,0,GIFcmap); unsigned char loop_count[] = {1,0,0}; #if GIFLIB_MAJOR >= 5 GIFfile = EGifOpenFileName(argv[2], 0, NULL); EGifPutExtension(GIFfile, APPLICATION_EXT_FUNC_CODE, 11, "NETSCAPE2.0"); EGifPutExtension(GIFfile, APPLICATION_EXT_FUNC_CODE, 3, loop_count); #else GIFfile = EGifOpenFileName(argv[2], 0); EGifPutExtensionFirst(GIFfile, APPLICATION_EXT_FUNC_CODE, 11, "NETSCAPE2.0"); EGifPutExtensionLast(GIFfile, APPLICATION_EXT_FUNC_CODE, 3, loop_count); #endif unsigned char delay_count[5] = { 0, // no transparency 0, // delay time 0, // delay time 0 // transparent index not used }; // // allocate image // image = malloc(dy*sizeof(int *)); for (yo = 0; yo < dy; ++yo) { image[yo] = malloc(dx*sizeof(int)); for (xo = 0; xo < dx; ++xo) image[yo][xo] = 0; } GIFline = malloc(dx*sizeof(GifPixelType)); // // scan file // xi = yi = zi = 0; for (zo = 0; zo < dz; ++zo) { printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",zo); EGifPutExtension(GIFfile,GRAPHICS_EXT_FUNC_CODE,4,delay_count); EGifPutImageDesc(GIFfile,0,0,dx,dy,0,NULL); // // read layer // for (yo = 0; yo < dy; ++yo) { for (xo = 0; xo < dx; ++xo) { if (format == 'f') { read_voxel_f(input_file,&f,xo+x0,yo+y0,zo+z0,&xi,&yi,&zi,nx,ny,nz); if (type == 'h') { h = 255*zo/(nz-1.0); if ((h > image[yo][xo]) && (f > arg)) image[yo][xo] = h; GIFline[xo] = image[yo][xo]*(nz-1.0)/zo; } else if (type == 's') { GIFline[xo] = 255*pow((f-fmin)/(fmax-fmin),arg); } } else if (format == 'i') { read_voxel_i(input_file,&i,xo+x0,yo+y0,zo+z0,&xi,&yi,&zi,nx,ny,nz); if (type == 'h') { h = 255*zo/(nz-1.0); if ((h > image[yo][xo]) && (i > arg)) image[yo][xo] = h; GIFline[xo] = image[yo][xo]*(nz-1.0)/zo; } else if (type == 's') { GIFline[xo] = 255*pow((i-fmin)/(fmax-fmin),arg); } } } EGifPutLine(GIFfile,GIFline,dx); } } printf("\n"); // // put mm per pixel in comment // sprintf(comment,"mm per pixel: %f;",size); EGifPutComment(GIFfile,comment); // // exit // fclose(input_file); EGifCloseFile(GIFfile); exit(0); }
static int write_gif_info(const psx_image* image, image_writer_fn func, void* param, float quality, psx_image_header* header) { size_t buf_size; #if GIFLIB_MAJOR >= 5 int errorcode = 0; #endif struct gif_image_ctx* ctx = (struct gif_image_ctx*)calloc(1, sizeof(struct gif_image_ctx)); if (!ctx) { return -1; // out of memory. } ctx->writer = func; ctx->writer_param = param; #if GIFLIB_MAJOR >= 5 if ((ctx->gif = EGifOpen((void*)ctx, write_gif_from_memory, &errorcode)) == NULL) { free(ctx); return -1; } if (image->num_frames > 1) { EGifSetGifVersion(ctx->gif, true); } #else if ((ctx->gif = EGifOpen((void*)ctx, write_gif_from_memory)) == NULL) { free(ctx); return -1; } if (image->num_frames > 1) { EGifSetGifVersion("89a"); } else { EGifSetGifVersion("87a"); } #endif if (EGifPutScreenDesc(ctx->gif, image->width, image->height, 8, 0, NULL) == GIF_ERROR) { GIF_CLOSE_EFILE(ctx->gif); free(ctx); return -1; } if (image->num_frames > 1) { // add netscape2.0 application extension to an animation gif. #if GIFLIB_MAJOR >= 5 EGifPutExtensionLeader(ctx->gif, APPLICATION_EXT_FUNC_CODE); EGifPutExtensionBlock(ctx->gif, 11, "NETSCAPE2.0"); EGifPutExtensionBlock(ctx->gif, 3, "\x01\x00\x00"); EGifPutExtensionTrailer(ctx->gif); #else EGifPutExtensionFirst(ctx->gif, APPLICATION_EXT_FUNC_CODE, 11, "NETSCAPE2.0"); EGifPutExtensionLast(ctx->gif, APPLICATION_EXT_FUNC_CODE, 3, "\x01\x00\x00"); #endif } buf_size = image->width * image->height * sizeof(GifByteType); ctx->red_buf = (GifByteType*)malloc(buf_size); ctx->green_buf = (GifByteType*)malloc(buf_size); ctx->blue_buf = (GifByteType*)malloc(buf_size); ctx->output_buffer = (GifByteType*)malloc(buf_size); if (!ctx->red_buf || !ctx->green_buf || !ctx->blue_buf || !ctx->output_buffer) { GIF_CLOSE_EFILE(ctx->gif); if (ctx->red_buf) free(ctx->red_buf); if (ctx->green_buf) free(ctx->green_buf); if (ctx->blue_buf) free(ctx->blue_buf); if (ctx->output_buffer) free(ctx->output_buffer); free(ctx); return -1; } header->priv = ctx; header->width = image->width; header->height = image->height; header->pitch = image->pitch; header->depth = get_depth(image->format); header->bpp = get_bpp(image->format); header->format = (int)image->format; header->alpha = 1; header->frames = (int)image->num_frames; return 0; }