/* * 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 <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <setjmp.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <math.h> #include <png.h> #include <jpeglib.h> #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 int luttool_applylut(char *lutfilenamelist,char *infilename, char *outfilename,int quality,int identitysize,int flaginterpolatelut); int util_imgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height); int util_imgsave(char *filename, char *bufimg, int width, int height,int quality); 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_jpgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height); int util_jpgsave(char *filename, char *bufimg, int width, int height,int quality); 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; int flaginterpolatelut; char bufoutfilename[1024]; char *currentoutfilename; if(argc<2 || strcmp(argv[argc-1],"--help")==0) { printf("Syntax: %s [-i] [-q jpegquality] [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]); printf("NOTE: -i makes the program interpolate the LUTs.\n"); printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]); printf("Example: %s -i 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]); return(1); } /* parse arguments */ identitysize=DEFAULT_IDENTITYSIZE; quality=DEFAULT_QUALITY; flaginterpolatelut=0; for(firstarg=1 ;firstarg<(argc-1) && (strcmp(argv[firstarg],"-n")==0 || strcmp(argv[firstarg],"-q")==0 || strcmp(argv[firstarg],"-i")==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); } } else if(strcmp(argv[firstarg],"-i")==0) { flaginterpolatelut=1; firstarg--; /* doesn't have param. */ } 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<argc;i++) { if(i==outfilenamearg) { i++; continue; } currentoutfilename=outfilename; if(flagseveralinfile) { char *ext; int l; strncpy(bufoutfilename,argv[i],sizeof(bufoutfilename)); bufoutfilename[sizeof(bufoutfilename)-1]='\0'; if((ext=strrchr(bufoutfilename,'.'))!=NULL) *ext='\0'; l=strlen(bufoutfilename); snprintf(bufoutfilename+l,sizeof(bufoutfilename)-l,"_%s",outfilename); bufoutfilename[sizeof(bufoutfilename)-1]='\0'; currentoutfilename=bufoutfilename; } if(luttool_applylut(lutlist,argv[i],currentoutfilename,quality,identitysize,flaginterpolatelut)!=0) { fprintf(stderr,"%s: ERROR: couldn't apply LUTs \"%s\" to \"%s\" or couldn't write \"%s\"\n",argv[0],lutlist,argv[i],currentoutfilename); return(1); } } return(0); } int luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,int identitysize,int flaginterpolatelut) { char *curlut,*next; char filename[1024]; int l; int in_error; char *lutbuf,*imgbuf,*rgblutbuf; int sizelutbuf,lutwidth,lutheight; int sizeimgbuf,imgwidth,imgheight; int sizergblutbuf; int res; lutbuf=imgbuf=rgblutbuf=NULL; sizelutbuf=sizeimgbuf=sizergblutbuf=0; lutwidth=lutheight=imgwidth=imgheight=0; if(lutlist==NULL || infilename==NULL || outfilename==NULL) return(-1); /* sanity check error */ in_error=0; /* load the image to process */ if(strcmp(infilename,"identity")==0) { if(util_identitygen(&imgbuf,&sizeimgbuf,identitysize,&imgwidth,&imgheight)==-1) in_error=1; } else { if(util_imgload(infilename,&imgbuf,&sizeimgbuf,&imgwidth,&imgheight)!=0) in_error=1; } /* apply all luts */ for(curlut=lutlist,next=strchr(curlut,','),next=((next==NULL)?(curlut+strlen(curlut)):next) ;in_error==0 && *curlut!='\0' ;curlut=next+((*next==',')?1:0),next=strchr(curlut,','),next=((next==NULL)?(curlut+strlen(curlut)):next)) { l=next-curlut; l=(l>(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_imgload(filename,&lutbuf,&sizelutbuf,&lutwidth,&lutheight)==-1) { in_error=1; break; /* couldn't load lut */ } } res=0; if(flaginterpolatelut==0) res=luttool_rgba2lut4096(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf); else res=luttool_rgba2lut4096_interpolated(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf); if(res!=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_imgsave(outfilename,imgbuf,imgwidth,imgheight,quality)!=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_imgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height) { int fd; char buf[8]; if((fd=open(filename,O_RDONLY))==-1 || read(fd,buf,sizeof(buf))<sizeof(buf)) { if(fd!=-1) close(fd),fd=-1; return(-1); /* couldn't open file for reading */ } close(fd),fd=-1; if(memcmp(buf,"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a",8)==0) { /* PNG magic */ return(util_pngload(filename,bufimg,sizebufimg,width,height)); } else if(memcmp(buf,"\xff\xd8",2)==0) { /* EXIF magic */ return(util_jpgload(filename,bufimg,sizebufimg,width,height)); } return(-1); /* file type not recognized */ } int util_imgsave(char *filename, char *bufimg, int width, int height,int quality) { int l; int flagjpeg; if(filename==NULL || bufimg==NULL || width<=0 || height<=0) return(-1); /* sanity check error */ l=strlen(filename); flagjpeg=0; if((l>=4 && filename[l-4]=='.' && (filename[l-3]=='J' || filename[l-3]=='j') && (filename[l-2]=='P' || filename[l-2]=='p') && (filename[l-1]=='G' || filename[l-1]=='g')) || (l>=5 && filename[l-5]=='.' && (filename[l-4]=='J' || filename[l-4]=='j') && (filename[l-3]=='P' || filename[l-3]=='p') && (filename[l-2]=='e' || filename[l-2]=='e') && (filename[l-1]=='G' || filename[l-1]=='g'))) { flagjpeg=1; } /* use png as default format; only use jpg if file extension says so */ if(flagjpeg) return(util_jpgsave(filename,bufimg,width,height,quality)); return(util_pngsave(filename,bufimg,width,height)); } 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(*sizebufimg<reqsize) { char *newbufimg; if((newbufimg=realloc(*bufimg,reqsize))==NULL) { png_destroy_read_struct(&png,&info,NULL),png=NULL,info=NULL; fclose(f),f=NULL; return(-1); /* insuf. mem. for resulting image */ } *bufimg=newbufimg; *sizebufimg=reqsize; } /* make sure we get 8-bit RGBA data, regardless of the file's bit_depth and color_type */ if((bit_depth=png_get_bit_depth(png,info))==16) png_set_strip_16(png); color_type=png_get_color_type(png,info); if(color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if(color_type==PNG_COLOR_TYPE_GRAY && bit_depth<8) png_set_expand_gray_1_2_4_to_8(png); if(png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); if(color_type==PNG_COLOR_TYPE_RGB || color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_PALETTE) { png_set_filler(png,0xff,PNG_FILLER_AFTER); } if(color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png); } /* read the image */ png_read_update_info(png,info); if((rowpointers=(png_bytep *)malloc(sizeof(png_bytep)*(*height)))==NULL) { png_destroy_read_struct(&png,&info,NULL),png=NULL,info=NULL; fclose(f),f=NULL; return(-1); /* insuf. mem. for temporary data */ } for(i=0,pitch=(*width)*4;i<(*height);i++) rowpointers[i]=(png_byte *)((*bufimg)+i*pitch); png_read_image(png,rowpointers); /* cleanup */ free(rowpointers),rowpointers=NULL; fclose(f),f=NULL; png_destroy_read_struct(&png,&info,NULL),png=NULL,info=NULL; return(0); } int util_pngsave(char *filename, char *bufimg, int width, int height) { FILE *f; png_structp png; png_infop info; int i,pitch; char *ptr; if((f=fopen(filename,"wb"))==NULL) return(-1); /* couldn't open file for writing */ if((png=png_create_write_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_write_struct(&png,&info),png=NULL,info=NULL; fclose(f),f=NULL; return(-1); /* couldn't init png library */ } png_init_io(png,f); png_set_IHDR(png,info,width,height,8,PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE); png_write_info(png,info); for(i=0,ptr=bufimg,pitch=width*4;i<height;i++,ptr+=pitch) png_write_row(png,(png_const_bytep)ptr); png_write_end(png,NULL); fclose(f),f=NULL; png_destroy_write_struct(&png,&info),png=NULL,info=NULL; return(0); } typedef struct jpegerrmgr_t { struct jpeg_error_mgr pub; jmp_buf setjmpbuf; } jpegerrmgr_t; static void util_jpgerrhandler(j_common_ptr cinfo) { jpegerrmgr_t *errmgr; errmgr=(jpegerrmgr_t *)cinfo->err; longjmp(errmgr->setjmpbuf,1); } int util_jpgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height) { FILE *f; struct jpeg_decompress_struct cinfo; jpegerrmgr_t errmgr; int reqsize; JSAMPROW rowptrs[1]; unsigned char *ptr,*orig,*dest; 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 */ memset(&cinfo,0,sizeof(cinfo)); cinfo.err=jpeg_std_error(&errmgr.pub); errmgr.pub.error_exit=util_jpgerrhandler; if(setjmp(errmgr.setjmpbuf)) { jpeg_destroy_decompress(&cinfo); if(f!=NULL) fclose(f),f=NULL; return(-1); /* libjpeg couldn't decompress stream */ } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo,f); jpeg_read_header(&cinfo,TRUE); jpeg_start_decompress(&cinfo); *width=cinfo.output_width; *height=cinfo.output_height; /* special case: if bufimg==NULL, we only want the width/height */ if(bufimg==NULL) { jpeg_destroy_decompress(&cinfo); return(0); /* all done */ } /* make sure is in a supported format */ if(cinfo.output_components!=3 && cinfo.output_components!=4) { jpeg_destroy_decompress(&cinfo); return(-1); /* we only support 8-bit RGB jpeg */ } /* make sure we have enough space for the new image in 8-bit RGBA */ reqsize=(*width)*(*height)*4; if(*sizebufimg<reqsize) { char *newbufimg; if((newbufimg=realloc(*bufimg,reqsize))==NULL) { jpeg_destroy_decompress(&cinfo); fclose(f),f=NULL; return(-1); /* insuf. mem. for resulting image */ } *bufimg=newbufimg; *sizebufimg=reqsize; } while(cinfo.output_scanline<cinfo.output_height) { ptr=(unsigned char *)((*bufimg)+cinfo.output_scanline*((*width)*4)); rowptrs[0]=ptr; jpeg_read_scanlines(&cinfo,rowptrs,1); if(cinfo.output_components==3) { orig=ptr+((*width)-1)*3; dest=ptr+((*width)-1)*4; for(;orig>=ptr;orig-=3,dest-=4) { dest[0]=orig[0]; dest[1]=orig[1]; dest[2]=orig[2]; dest[3]=0xff; } } } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(f),f=NULL; return(0); } int util_jpgsave(char *filename, char *bufimg, int width, int height,int quality) { FILE *f; struct jpeg_compress_struct cinfo; jpegerrmgr_t errmgr; char *rowdata; JSAMPROW rowptrs[1]; int i; unsigned char *ptr,*orig,*dest; if(filename==NULL || bufimg==NULL || width<=0 || height<=0 || quality<1 || quality>100) return(-1); /* sanity check failed */ if((rowdata=malloc(width*3))==NULL) return(-1); if((f=fopen(filename,"wb"))==NULL) { if(rowdata!=NULL) free(rowdata),rowdata=NULL; return(-1); /* couldn't open file for writing */ } memset(&cinfo,0,sizeof(cinfo)); cinfo.err=jpeg_std_error(&errmgr.pub); errmgr.pub.error_exit=util_jpgerrhandler; if(setjmp(errmgr.setjmpbuf)) { if(f!=NULL) fclose(f),f=NULL; if(rowdata!=NULL) free(rowdata),rowdata=NULL; jpeg_destroy_compress(&cinfo); return(-1); /* libjpeg couldn't compress stream */ } jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo,f); cinfo.image_width=width; cinfo.image_height=height; cinfo.input_components=3; cinfo.in_color_space=JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality,TRUE); jpeg_start_compress(&cinfo,TRUE); while(cinfo.next_scanline<cinfo.image_height) { ptr=(unsigned char *)(bufimg+cinfo.next_scanline*(width*4)); for(orig=ptr,dest=(unsigned char *)rowdata,i=0;i<width;i++,orig+=4,dest+=3) { dest[0]=orig[0]; dest[1]=orig[1]; dest[2]=orig[2]; } rowptrs[0]=(JSAMPROW) rowdata; jpeg_write_scanlines(&cinfo,rowptrs,1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(f),f=NULL; free(rowdata),rowdata=NULL; return(0); } int util_identitygen(char **bufimg, int *sizebufimg, int identitysize, int *width, int *height) { int x,y,r,g,b; int isizesq,isizesqminusone; int osizesqminusone; int reqsize; int l; unsigned char *ptr; if(bufimg==NULL || sizebufimg==NULL || identitysize<=1 || identitysize>16 || width==NULL || height==NULL) return(-1); l=*width=*height=identitysize*identitysize*identitysize; reqsize=(*width)*(*height)*4; if(*sizebufimg<reqsize) { char *newbufimg; if((newbufimg=realloc(*bufimg,reqsize))==NULL) return(-1); /* insuf. mem. for resulting image */ *bufimg=newbufimg; *sizebufimg=reqsize; } isizesq=identitysize*identitysize; isizesqminusone=isizesq-1; osizesqminusone=256-1; for(y=0,ptr=(unsigned char *)(*bufimg);y<l;y++) { for(x=0;x<l;x++,ptr+=4) { r=x%isizesq; g=(y%identitysize)*identitysize+(x/isizesq); b=y/identitysize; ptr[0]=r*osizesqminusone/isizesqminusone; ptr[1]=g*osizesqminusone/isizesqminusone; ptr[2]=b*osizesqminusone/isizesqminusone; ptr[3]=0xff; } } return(0); } int luttool_rgba2lut4096(char *rgba, int width, int height, char **lut4096, int *sizelut4096) { int n; int reqsize; int x,y; int r,g,b; int isize,isizesq,isizesqminusone; int osize,osizesq,osizesqminusone; unsigned char *orig,*dest; if(rgba==NULL || width!=height || lut4096==NULL || sizelut4096==NULL) return(-1); /* sanity check error */ /* check if size is a supported size */ for(n=2;n<=16 && width!=(n*n*n);n++) ; if(n>16) return(-1); /* invalid size */ /* expand lut4096 as necessary */ reqsize=4096*4096*3; if(*sizelut4096<reqsize) { char *newlut4096; if((newlut4096=realloc(*lut4096,reqsize))==NULL) return(-1); /* insuf. mem. for resulting lut */ *lut4096=newlut4096; *sizelut4096=reqsize; } /* do the conversion */ isize=n; isizesq=n*n; isizesqminusone=isizesq-1; osize=16; osizesq=osize*osize; osizesqminusone=osizesq-1; for(r=0;r<osizesq;r++) { for(g=0;g<osizesq;g++) { for(b=0;b<osizesq;b++) { x=((isizesqminusone*r)/osizesqminusone)+(((isizesqminusone*g)/osizesqminusone)%isize)*isizesq; y=((isizesqminusone*b)/osizesqminusone)*isize+(((isizesqminusone*g)/osizesqminusone)/isize); orig=(unsigned char *) (rgba+((y*width+x)<<2)); dest=(unsigned char *) ((*lut4096)+((r<<16)+(g<<8)+b)*3); dest[0]=orig[0]; dest[1]=orig[1]; dest[2]=orig[2]; } } } return(0); } int luttool_rgba2lut4096_interpolated(char *rgba, int width, int height, char **lut4096, int *sizelut4096) { int n; int reqsize; float fr,fg,fb; int ir,ig,ib; int incr,incg,incb; int posr,posg,posb; int myrgb[3]; int x,y; int r,g,b; int i; int isize,isizesq,isizesqminusone; int osize,osizesq,osizesqminusone; unsigned char *orig,*dest; if(rgba==NULL || width!=height || lut4096==NULL || sizelut4096==NULL) return(-1); /* sanity check error */ /* check if size is a supported size */ for(n=2;n<=16 && width!=(n*n*n);n++) ; if(n>16) return(-1); /* invalid size */ /* expand lut4096 as necessary */ reqsize=4096*4096*3; if(*sizelut4096<reqsize) { char *newlut4096; if((newlut4096=realloc(*lut4096,reqsize))==NULL) return(-1); /* insuf. mem. for resulting lut */ *lut4096=newlut4096; *sizelut4096=reqsize; } /* do the conversion */ isize=n; isizesq=n*n; isizesqminusone=isizesq-1; osize=16; osizesq=osize*osize; osizesqminusone=osizesq-1; for(r=0;r<osizesq;r++) { for(g=0;g<osizesq;g++) { for(b=0;b<osizesq;b++) { fr=((isizesqminusone*((float)r))/osizesqminusone); fg=((isizesqminusone*((float)g))/osizesqminusone); fb=((isizesqminusone*((float)b))/osizesqminusone); ir=floorf(fr); ig=floorf(fg); ib=floorf(fb); fr=fr-ir; fg=fg-ig; fb=fb-ib; myrgb[0]=myrgb[1]=myrgb[2]=0; for(i=0;i<2*2*2;i++) { incr=(i>>2)&1; incg=(i>>1)&1; incb=i&1; posr=ir+incr; posr=(posr<0)?0:(posr>=isizesq)?isizesqminusone:posr; posg=ig+incg; posg=(posg<0)?0:(posg>=isizesq)?isizesqminusone:posg; posb=ib+incb; posb=(posb<0)?0:(posb>=isizesq)?isizesqminusone:posb; x=posr+(posg%isize)*isizesq; y=posb*isize+(posg/isize); orig=(unsigned char *) (rgba+((y*width+x)<<2)); myrgb[0]+=orig[0]*((incr!=0)?fr:(1-fr)); myrgb[1]+=orig[1]*((incg!=0)?fg:(1-fg)); myrgb[2]+=orig[2]*((incb!=0)?fb:(1-fb)); } myrgb[0]/=(i/2); myrgb[0]=(myrgb[0]<0)?0:(myrgb[0]>255)?255:myrgb[0]; myrgb[1]/=(i/2); myrgb[1]=(myrgb[1]<0)?0:(myrgb[1]>255)?255:myrgb[1]; myrgb[2]/=(i/2); myrgb[2]=(myrgb[2]<0)?0:(myrgb[2]>255)?255:myrgb[2]; dest=(unsigned char *) ((*lut4096)+((r<<16)+(g<<8)+b)*3); dest[0]=myrgb[0]; dest[1]=myrgb[1]; dest[2]=myrgb[2]; } } } return(0); } int luttool_applylut4096(char *lut4096,char *imgbuf,int imgwidth,int imgheight) { int x,y; unsigned char *orig; unsigned char *lut; if(lut4096==NULL || imgbuf==NULL || imgwidth<=0 || imgheight<=0) return(-1); for(y=0,orig=(unsigned char *)imgbuf;y<imgheight ;y++) { for(x=0;x<imgwidth;x++,orig+=4) { lut=((unsigned char *)lut4096)+((((int)(orig[0]))<<16)+(((int)(orig[1]))<<8)+((int)(orig[2])))*3; orig[0]=lut[0]; orig[1]=lut[1]; orig[2]=lut[2]; } } return(0); }