/* * luttool.c * * Utility to apply LUTs to images * * Author: Dario Rodriguez antartica@whereismybit.com * This program is licensed under the terms of the MIT license, * with an exception: the license text may be substituted for a * link to it. MIT license text: https://spdx.org/licenses/MIT.html */ #include #include #include #include #include #define DEFAULT_IDENTITYSIZE 12 /* Same as RawTherapee's HaldCLUTs, 1728x1728 AKA (12*12)*12x12*(12*12), equivalent to a cube with 144px wide sides*/ #define DEFAULT_QUALITY 85 /* #define JPEG_SUPPORTED */ int luttool_applylut(char *lutfilenamelist,char *infilename, char *outfilename,int quality,int identitysize); int util_pnginfo(char *filename, int *width, int *height); int util_pngload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height); int util_pngsave(char *filename, char *bufimg, int width, int height); int util_identitygen(char **bufimg, int *sizebufimg, int identitysize, int *width, int *height); int luttool_rgba2lut4096(char *rgba, int width, int height, char **lut4096, int *sizelut4096); int luttool_rgba2lut4096_interpolated(char *rgba, int width, int height, char **lut4096, int *sizelut4096); int luttool_applylut4096(char *lut4096,char *imgbuf,int imgwidth,int imgheight); int main(int argc, char *argv[]) { int firstarg,outfilenamearg; int identitysize; int quality; char *outfilename; char *lutlist; int i; int flagseveralinfile; char bufoutfilename[1024]; char *currentoutfilename; if(argc<2 || strcmp(argv[argc-1],"--help")==0) { #ifdef JPEG_SUPPORTED printf("Syntax: %s [-q jpegquality] [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]); printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]); printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]); printf("Example: %s -q 85 haldclut.png infile.png -o outfile.jpg\n",argv[0]); #else printf("Syntax: %s [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]); printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]); printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]); #endif return(1); } /* parse arguments */ identitysize=DEFAULT_IDENTITYSIZE; quality=DEFAULT_QUALITY; for(firstarg=1;firstarg<(argc-1) && (strcmp(argv[firstarg],"-n")==0 || (strcmp(argv[firstarg],"-q")==0));) { if(strcmp(argv[firstarg],"-n")==0) { identitysize=atoi(argv[firstarg+1]); if(identitysize<2 || identitysize>16) { fprintf(stderr,"%s: ERROR: the parameter to -n must be between 2 and 16 (default: %i)\n",argv[0],DEFAULT_IDENTITYSIZE); return(1); } } else if(strcmp(argv[firstarg],"-q")==0) { quality=atoi(argv[firstarg+1]); if(quality<1 || quality>100) { fprintf(stderr,"%s: ERROR: the parameter to -q must be between 1 and 100 (default: %i)\n",argv[0],DEFAULT_QUALITY); return(1); } } firstarg+=2; } for(outfilenamearg=-1,outfilename=NULL,i=1;i<(argc-1);i++) { if(strcmp(argv[i],"-o")==0) { outfilename=argv[i+1]; outfilenamearg=i; break; } } if(outfilename==NULL) { fprintf(stderr,"%s: ERROR: no output file specified\n",argv[0]); return(1); } firstarg+=((firstarg==outfilenamearg)?2:0); lutlist=argv[firstarg]; firstarg++; flagseveralinfile=((argc-firstarg-((outfilenamearg>=firstarg)?2:0))>1)?1:0; /* process files sequentially, skipping the "-o outputfilename" */ for(i=firstarg;i(sizeof(filename)-1))?(sizeof(filename)-1):l; memcpy(filename,curlut,l); filename[l]='\0'; if(strcmp(filename,"identity")==0) { if(util_identitygen(&lutbuf,&sizelutbuf,identitysize,&lutwidth,&lutheight)==-1) { in_error=1; break; /* couldn't generate identity lut */ } } else { if(util_pngload(filename,&lutbuf,&sizelutbuf,&lutwidth,&lutheight)==-1) { in_error=1; break; /* couldn't load lut */ } } if(luttool_rgba2lut4096(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf)!=0) { in_error=1; break; /* couldn't process lut */ } if(luttool_applylut4096(rgblutbuf,imgbuf,imgwidth,imgheight)!=0) { in_error=1; break; /* couldn't apply lut */ } } /* save the result */ if(in_error==0) { if(util_pngsave(outfilename,imgbuf,imgwidth,imgheight)!=0) in_error=1; /* couldn't write */ } /* cleanup and exit */ if(lutbuf!=NULL) free(lutbuf),lutbuf=NULL; if(imgbuf!=NULL) free(imgbuf),imgbuf=NULL; if(rgblutbuf!=NULL) free(rgblutbuf),rgblutbuf=NULL; return((in_error!=0)?-1:0); } int util_pnginfo(char *filename, int *width, int *height) { return(util_pngload(filename,NULL,NULL,width,height)); } int util_pngload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height) { FILE *f; png_structp png; png_infop info; png_byte color_type,bit_depth; png_bytep *rowpointers; int reqsize; int i,pitch; if(filename==NULL || (bufimg==NULL && sizebufimg!=NULL) || (bufimg!=NULL && sizebufimg==NULL) || width==NULL || height==NULL) return(-1); /* sanity check failed */ if((f=fopen(filename,"rb"))==NULL) return(-1); /* couldn't open file */ if((png=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL))==NULL || (info=png_create_info_struct(png))==NULL || setjmp(png_jmpbuf(png))) { if(png!=NULL) png_destroy_read_struct(&png,&info,NULL),png=NULL,info=NULL; fclose(f),f=NULL; return(-1); /* couldn't init png library */ } png_init_io(png,f); png_read_info(png,info); *width=png_get_image_width(png,info); *height=png_get_image_height(png,info); /* special case: if bufimg==NULL, we only want the width/height */ if(bufimg==NULL) { png_destroy_read_struct(&png,&info,NULL),png=NULL,info=NULL; fclose(f),f=NULL; return(0); /* all done */ } /* make sure we have enough space for the new image in 8-bit RGBA */ reqsize=(*width)*(*height)*4; if(*sizebufimg16 || width==NULL || height==NULL) return(-1); l=*width=*height=identitysize*identitysize*identitysize; reqsize=(*width)*(*height)*4; if(*sizebufimg16) return(-1); /* invalid size */ /* expand lut4096 as necessary */ reqsize=4096*4096*3; if(*sizelut4096