fabmodules/src/core/gif_png.c

347 wiersze
12 KiB
C

//
// gif_png.c
// .gif to .png
//
// Neil Gershenfeld 9/20/13
// (c) Massachusetts Institute of Technology 2013
//
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose, but must
// acknowledge the fab modules project. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all
// liability.
//
#define MAX_LINE 10000
#define BIG 1e10
#include "fab.h"
int main(int argc, char **argv) {
//
// local vars
//
GifFileType *GIFfile;
GifRecordType GIFtype;
GifByteType *GIFextension;
GifPixelType *GIFline;
uint32_t **lower_array,**upper_array;
double **image_array;
double f,fmin,fmax;
int x,y,z,h,i,j,k,n,p;
int imin,imax,image_width,image_height,image_count,color_resolution,GIFcode,ret;
float pixel_size,arg,threshold,rx,ry,rz;
char type,comment[256];
struct fab_vars v;
init_vars(&v);
//
// command line args
//
if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 7) || (argc == 10))) {
printf("command line: gif_png in.gif out.png [type [arg [points [size [rx ry rz]]]]]\n");
printf(" in.gif = input gif file\n");
printf(" out.png = output PNG file\n");
printf(" type = 'z' of density, 'h' for height (default z)\n");
printf(" arg = type argument\n");
printf(" 'z': gamma (default 1)\n");
printf(" 'h': threshold (0 = min, 1 = max, default 0.5)\n");
printf(" points = points to interpolate per point (linear, default 0)\n");
printf(" size = voxel size (mm, default from file))\n");
printf(" to be implemented: rx,ry,rz = x,y,z rotation angles (degrees; default 0)\n");
exit(-1);
}
type = 'z';
p = 0;
rx = ry = rz = 0;
pixel_size = -1;
image_width = -1;
image_height = -1;
if (argc >= 4) {
sscanf(argv[3],"%c",&type);
if (!((type == 'z') || (type == 'h'))) {
printf("gif_png: oops -- type must be 'z' or 'h'\n");
exit(-1);
}
}
if (type == 'z') arg = 1.0;
else if (type == 'h') arg = 0.5;
if (argc >= 5)
sscanf(argv[4],"%f",&arg);
if (argc >= 6)
sscanf(argv[5],"%d",&p);
if (argc >= 7)
sscanf(argv[6],"%f",&pixel_size);
if (argc >= 10) {
sscanf(argv[7],"%f",&rx);
sscanf(argv[8],"%f",&ry);
sscanf(argv[9],"%f",&rz);
}
//
// scan the file
//
printf("read %s\n",argv[1]);
imin = 256;
imax = 0;
color_resolution = -1;
GIFfile = DGifOpenFileName(argv[1]);
if (GIFfile == NULL) {
printf("gif_png: oops -- can not open %s\n",argv[1]);
exit(-1);
}
GIFline = malloc(MAX_LINE*sizeof(GifPixelType));
do {
DGifGetRecordType(GIFfile,&GIFtype);
switch (GIFtype) {
case IMAGE_DESC_RECORD_TYPE:
DGifGetImageDesc(GIFfile);
image_width = GIFfile->SWidth;
image_height = GIFfile->SHeight;
image_count = GIFfile->ImageCount;
color_resolution = GIFfile->SColorResolution;
for (y = 0; y < GIFfile->SHeight; ++y) {
ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth);
if (ret != GIF_OK) {
printf("gif_png: oops -- error reading line\n");
exit(-1);
}
for (x = 0; x < GIFfile->SWidth; ++x) {
if (GIFline[x] < imin) imin = GIFline[x];
if (GIFline[x] > imax) imax = GIFline[x];
}
}
break;
case EXTENSION_RECORD_TYPE:
DGifGetExtension(GIFfile,&GIFcode,&GIFextension);
if (GIFcode == COMMENT_EXT_FUNC_CODE) {
n = GIFextension[0];
for (i = 1; i <= n; ++i)
comment[i-1] = GIFextension[i];
comment[n] = 0;
if (pixel_size == -1)
sscanf(comment,"mm per pixel: %f;",&pixel_size);
}
while (GIFextension != NULL)
DGifGetExtensionNext(GIFfile,&GIFextension);
break;
case SCREEN_DESC_RECORD_TYPE:
DGifGetScreenDesc(GIFfile);
break;
case TERMINATE_RECORD_TYPE:
break;
case UNDEFINED_RECORD_TYPE:
printf("gif_png: oops -- undefined GIF record type\n");
exit(-1);
break;
}
} while (GIFtype != TERMINATE_RECORD_TYPE);
if (GIFfile == NULL) {
printf("gif_png: oops -- can not open %s\n",argv[1]);
exit(-1);
}
if (pixel_size == -1) {
pixel_size = 1.0;
printf(" no pixel size found, assuming 1 mm\n");
}
printf(" pixel size (mm): %f, color resolution (bits): %d\n",pixel_size,color_resolution);
printf(" intensity min: %d max: %d\n",imin,imax);
printf(" number of images: %d, image width %d, image height %d\n",image_count,image_width,image_height);
//
// set threshold
//
if (type == 'h')
threshold = imin + arg*(imax-imin);
//
// check and set limits
//
v.nx = image_width + (image_width-1)*p;
v.ny = image_height + (image_height-1)*p;
v.nz = image_count + (image_count-1)*p;
v.dx = v.nx*pixel_size;
v.dy = v.ny*pixel_size;
v.dz = v.nz*pixel_size;
v.xmin = 0;
v.ymin = 0;
v.zmin = 0;
//
// allocate arrays
//
lower_array = malloc(image_height*sizeof(uint32_t *));
for (y = 0; y < image_height; ++y) {
lower_array[y] = malloc(image_width*sizeof(uint32_t));
for (x = 0; x < image_width; ++x)
lower_array[y][x] = 0;
}
upper_array = malloc(image_height*sizeof(uint32_t *));
for (y = 0; y < image_height; ++y) {
upper_array[y] = malloc(image_width*sizeof(uint32_t));
for (x = 0; x < image_width; ++x)
upper_array[y][x] = 0;
}
image_array = malloc(v.ny*sizeof(double *));
for (y = 0; y < v.ny; ++y) {
image_array[y] = malloc(v.nx*sizeof(double));
for (x = 0; x < v.nx; ++x)
image_array[y][x] = 0;
}
v.array = malloc(v.ny*sizeof(uint32_t *));
for (y = 0; y < v.ny; ++y) {
v.array[y] = malloc(v.nx*sizeof(uint32_t));
for (x = 0; x < v.nx; ++x)
v.array[y][x] = 0;
}
//
// read the file
//
DGifCloseFile(GIFfile);
GIFfile = DGifOpenFileName(argv[1]);
if (GIFfile == NULL) {
printf("gif_png: oops -- can not open %s\n",argv[1]);
exit(-1);
}
z = 0;
do {
DGifGetRecordType(GIFfile,&GIFtype);
switch (GIFtype) {
case IMAGE_DESC_RECORD_TYPE:
//
// read image
//
DGifGetImageDesc(GIFfile);
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z);
if (z == 0) {
//
// read first layer
//
for (y = 0; y < image_height; ++y) {
ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth);
if (ret != GIF_OK) {
printf("gif_png: oops -- error reading first line\n");
exit(-1);
}
for (x = 0; x < image_width; ++x)
upper_array[y][x] = GIFline[x];
}
}
else {
//
// read next layer
//
for (y = 0; y < image_height; ++y) {
ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth);
if (ret != GIF_OK) {
printf("gif_png: oops -- error reading line\n");
exit(-1);
}
for (x = 0; x < image_width; ++x) {
lower_array[y][x] = upper_array[y][x];
upper_array[y][x] = GIFline[x];
}
}
if (p == 0) {
//
// no interpolation, loop over layer voxels
//
for (x = 0; x < (image_width-1); ++x) {
for (y = 0; y < (image_height-1); ++y) {
if (type == 'z') {
image_array[y][x] += lower_array[y][x];
}
else if (type == 'h') {
if ((lower_array[y][x] >= threshold) && (upper_array[y][x] < threshold))
image_array[y][x] = z + (lower_array[y][x]-threshold)/(lower_array[y][x]-upper_array[y][x]);
}
}
}
}
else {
//
// yes interpolation, loop over layer sub-voxels
//
for (x = 0; x < (image_width-1); ++x) {
for (y = 0; y < (image_height-1); ++y) {
for (i = 0; i <= p; ++i) {
for (j = 0; j <= p; ++j) {
for (k = 0; k <= p; ++k) {
f = lower_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0))
+ lower_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0))
+ lower_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0))
+ lower_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0))
+ upper_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0))
+ upper_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0))
+ upper_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0))
+ upper_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0));
if (type == 'z') {
image_array[(1+p)*y+j][(1+p)*x+i] += f;
}
else if (type == 'h') {
h = (1+p)*z+k;
if ((f > threshold) && (h > image_array[(1+p)*y+j][(1+p)*x+i]))
image_array[(1+p)*y+j][(1+p)*x+i] = h;
}
}
}
}
}
}
}
}
z += 1;
break;
case EXTENSION_RECORD_TYPE:
DGifGetExtension(GIFfile,&GIFcode,&GIFextension);
while (GIFextension != NULL)
DGifGetExtensionNext(GIFfile,&GIFextension);
break;
case SCREEN_DESC_RECORD_TYPE:
DGifGetScreenDesc(GIFfile);
break;
case TERMINATE_RECORD_TYPE:
break;
case UNDEFINED_RECORD_TYPE:
printf("gif_png: oops -- undefined GIF record type\n");
exit(-1);
break;
}
} while (GIFtype != TERMINATE_RECORD_TYPE);
printf("\n");
//
// scale image and copy to PNG array
//
if (type == 'z') {
fmin = BIG;
fmax = 0;
for (x = 0; x < v.nx; ++x) {
for (y = 0; y < v.ny; ++y) {
if (image_array[y][x] > fmax) fmax = image_array[y][x];
if (image_array[y][x] < fmin) fmin = image_array[y][x];
}
}
if (arg == 1) {
for (x = 0; x < v.nx; ++x)
for (y = 0; y < v.ny; ++y)
v.array[y][x] = 65536*(image_array[y][x]-fmin)/(fmax-fmin);
}
else {
for (x = 0; x < v.nx; ++x)
for (y = 0; y < v.ny; ++y)
v.array[y][x] = 65536*pow((image_array[y][x]-fmin)/(fmax-fmin),arg);
}
}
else if (type == 'h') {
for (x = 0; x < v.nx; ++x)
for (y = 0; y < v.ny; ++y)
v.array[y][x] = 65536*image_array[y][x]/(v.nz-1.0);
}
//
// write PNG
//
v.bit_depth = 16;
fab_write_png_K(&v,argv[2]);
//
// exit
//
DGifCloseFile(GIFfile);
exit(0);
}