| 1 | < | /* Copyright (c) 1997 Regents of the University of California */ | 
| 1 | > | /* Copyright (c) 1999 Regents of the University of California */ | 
| 2 |  |  | 
| 3 |  | #ifndef lint | 
| 4 | < | static char SCCSid[] = "$SunId$ LBL"; | 
| 4 | > | static char SCCSid[] = "$SunId$ SGI"; | 
| 5 |  | #endif | 
| 6 |  |  | 
| 7 |  | /* | 
| 29 |  |  | 
| 30 |  | #undef  NOPROTO | 
| 31 |  | #define NOPROTO 1 | 
| 32 | + | #include  "color.h" | 
| 33 |  | #include  "tonemap.h" | 
| 34 |  | #include  "view.h" | 
| 35 |  | #include  "x11raster.h" | 
| 36 |  | #include  "random.h" | 
| 37 |  | #include  "resolu.h" | 
| 38 |  |  | 
| 38 | – | #ifndef  int4 | 
| 39 | – | #define  int4           int             /* most int's are 32-bit */ | 
| 40 | – | #endif | 
| 41 | – |  | 
| 39 |  | #define  FONTNAME       "8x13"          /* text font we'll use */ | 
| 40 |  |  | 
| 41 |  | #define  CTRL(c)        ((c)-'@') | 
| 44 |  |  | 
| 45 |  | #define  ICONSIZ        (8*10)          /* maximum icon dimension (even 8) */ | 
| 46 |  |  | 
| 47 | + | #define  FIXWEIGHT      20              /* weight to add for fixation points */ | 
| 48 | + |  | 
| 49 |  | #define  ourscreen      DefaultScreen(thedisplay) | 
| 50 |  | #define  ourroot        RootWindow(thedisplay,ourscreen) | 
| 51 |  |  | 
| 77 |  | char  *tout = "od";                     /* output of 't' command */ | 
| 78 |  | int  tinterv = 0;                       /* interval between mouse reports */ | 
| 79 |  |  | 
| 80 | < | int  tmflags = -1;                      /* tone mapping flags (-1 for none) */ | 
| 80 | > | int  tmflags = TM_F_LINEAR;             /* tone mapping flags */ | 
| 81 |  |  | 
| 82 |  | VIEW  ourview = STDVIEW;                /* image view parameters */ | 
| 83 |  | int  gotview = 0;                       /* got parameters from file */ | 
| 91 |  | int  xmax, ymax;                        /* picture dimensions */ | 
| 92 |  | int  width, height;                     /* window size */ | 
| 93 |  | char  *fname = NULL;                    /* input file name */ | 
| 94 | < | FILE  *fin = stdin;                     /* input file */ | 
| 94 | > | FILE  *fin = NULL;                      /* input file */ | 
| 95 |  | long  *scanpos = NULL;                  /* scan line positions in file */ | 
| 96 |  | int  cury = 0;                          /* current scan location */ | 
| 97 |  |  | 
| 143 |  | int  pid; | 
| 144 |  |  | 
| 145 |  | progname = argv[0]; | 
| 146 | + | fin = stdin; | 
| 147 |  |  | 
| 148 |  | for (i = 1; i < argc; i++) | 
| 149 |  | if (argv[i][0] == '-') | 
| 251 |  | } | 
| 252 |  |  | 
| 253 |  |  | 
| 254 | + | int | 
| 255 |  | headline(s)             /* get relevant info from header */ | 
| 256 |  | char  *s; | 
| 257 |  | { | 
| 263 |  | wrongformat = strcmp(fmt, COLRFMT); | 
| 264 |  | else if (isview(s) && sscanview(&ourview, s) > 0) | 
| 265 |  | gotview++; | 
| 266 | + | return(0); | 
| 267 |  | } | 
| 268 |  |  | 
| 269 |  |  | 
| 419 |  | return(-1); | 
| 420 |  | if (v1->depth == 32 && v2->depth == 24) | 
| 421 |  | return(1); | 
| 422 | < | return(0); | 
| 422 | > | /* go for maximum depth otherwise */ | 
| 423 | > | return(v2->depth - v1->depth); | 
| 424 |  | } | 
| 425 |  | /* don't be too greedy */ | 
| 426 |  | if (maxcolors <= 1<<v1->depth && maxcolors <= 1<<v2->depth) | 
| 427 |  | return(v1->depth - v2->depth); | 
| 428 |  | return(v2->depth - v1->depth); | 
| 429 |  | } | 
| 430 | < | /* prefer Pseudo when < 24-bit */ | 
| 430 | > | /* prefer Pseudo when < 15-bit */ | 
| 431 |  | if ((v1->class == TrueColor || v1->class == DirectColor) && | 
| 432 | < | v1->depth < 24) | 
| 432 | > | v1->depth < 15) | 
| 433 |  | bad1 = 1; | 
| 434 |  | if ((v2->class == TrueColor || v2->class == DirectColor) && | 
| 435 | < | v2->depth < 24) | 
| 435 | > | v2->depth < 15) | 
| 436 |  | bad2 = -1; | 
| 437 |  | if (bad1 | bad2) | 
| 438 |  | return(bad1+bad2); | 
| 543 |  | goto fail; | 
| 544 |  | getmono(); | 
| 545 |  | } else if (ourvis.class == TrueColor | ourvis.class == DirectColor) { | 
| 546 | < | ourdata = (unsigned char *)malloc(sizeof(int4)*xmax*ymax); | 
| 546 | > | int  datsiz = ourvis.depth>16 ? sizeof(int4) : sizeof(int2); | 
| 547 | > | ourdata = (unsigned char *)malloc(datsiz*xmax*ymax); | 
| 548 |  | if (ourdata == NULL) | 
| 549 |  | goto fail; | 
| 550 | < | ourras = make_raster(thedisplay, &ourvis, sizeof(int4)*8, | 
| 551 | < | ourdata, xmax, ymax, 32); | 
| 550 | > | ourras = make_raster(thedisplay, &ourvis, datsiz*8, | 
| 551 | > | ourdata, xmax, ymax, datsiz*8); | 
| 552 |  | if (ourras == NULL) | 
| 553 |  | goto fail; | 
| 554 |  | getfull(); | 
| 695 |  | case '\r': | 
| 696 |  | case 'l': | 
| 697 |  | case 'c':                               /* value */ | 
| 698 | < | if (avgbox(cval) == -1) | 
| 698 | > | if (!avgbox(cval)) | 
| 699 |  | return(-1); | 
| 700 |  | switch (com) { | 
| 701 |  | case '\n': | 
| 738 |  | case 't':                               /* trace */ | 
| 739 |  | return(traceray(ekey->x, ekey->y)); | 
| 740 |  | case 'a':                               /* auto exposure */ | 
| 741 | < | if (tmflags == TM_F_CAMERA) | 
| 742 | < | return(0); | 
| 741 | > | if (fname == NULL) | 
| 742 | > | return(-1); | 
| 743 |  | tmflags = TM_F_CAMERA; | 
| 744 |  | strcpy(buf, "auto exposure..."); | 
| 745 |  | goto remap; | 
| 746 |  | case 'h':                               /* human response */ | 
| 747 | < | if (tmflags == TM_F_HUMAN) | 
| 748 | < | return(0); | 
| 747 | > | if (fname == NULL) | 
| 748 | > | return(-1); | 
| 749 |  | tmflags = TM_F_HUMAN; | 
| 750 |  | strcpy(buf, "human exposure..."); | 
| 751 |  | goto remap; | 
| 752 |  | case '=':                               /* adjust exposure */ | 
| 753 |  | case '@':                               /* adaptation level */ | 
| 754 | < | if (avgbox(cval) == -1) | 
| 754 | > | if (!avgbox(cval)) | 
| 755 |  | return(-1); | 
| 756 |  | comp = bright(cval); | 
| 757 |  | if (comp < 1e-20) { | 
| 765 |  | comp = .5/comp; | 
| 766 |  | comp = log(comp)/.69315 - scale; | 
| 767 |  | n = comp < 0 ? comp-.5 : comp+.5 ;      /* round */ | 
| 768 | < | if (tmflags != -1) | 
| 769 | < | tmflags = -1;           /* turn off tone mapping */ | 
| 768 | > | if (tmflags != TM_F_LINEAR) | 
| 769 | > | tmflags = TM_F_LINEAR;  /* turn off tone mapping */ | 
| 770 |  | else { | 
| 771 |  | if (n == 0)             /* else check if any change */ | 
| 772 |  | return(0); | 
| 898 |  | } | 
| 899 |  |  | 
| 900 |  |  | 
| 901 | < | avgbox(clr)                             /* average color over current box */ | 
| 902 | < | COLOR  clr; | 
| 901 | > | int | 
| 902 | > | colavg(scn, n, cavg) | 
| 903 | > | register COLR   *scn; | 
| 904 | > | register int    n; | 
| 905 | > | COLOR   cavg; | 
| 906 |  | { | 
| 907 | < | static COLOR  lc; | 
| 908 | < | static int  ll, lr, lt, lb; | 
| 907 | > | COLOR   col; | 
| 908 | > |  | 
| 909 | > | while (n--) { | 
| 910 | > | colr_color(col, scn++); | 
| 911 | > | addcolor(cavg, col); | 
| 912 | > | } | 
| 913 | > | } | 
| 914 | > |  | 
| 915 | > |  | 
| 916 | > | int | 
| 917 | > | avgbox(cavg)                            /* average color over current box */ | 
| 918 | > | COLOR   cavg; | 
| 919 | > | { | 
| 920 | > | double  d; | 
| 921 | > | register int    rval; | 
| 922 | > |  | 
| 923 | > | setcolor(cavg, 0., 0., 0.); | 
| 924 | > | rval = dobox(colavg, (char *)cavg); | 
| 925 | > | if (rval > 0) { | 
| 926 | > | d = 1./rval; | 
| 927 | > | scalecolor(cavg, d); | 
| 928 | > | } | 
| 929 | > | return(rval); | 
| 930 | > | } | 
| 931 | > |  | 
| 932 | > |  | 
| 933 | > | int | 
| 934 | > | dobox(f, p)                             /* run function over box */ | 
| 935 | > | int     (*f)();                 /* function to call for each subscan */ | 
| 936 | > | char    *p;                     /* pointer to private data */ | 
| 937 | > | { | 
| 938 |  | int  left, right, top, bottom; | 
| 939 |  | int  y; | 
| 904 | – | double  d; | 
| 905 | – | COLOR  ctmp; | 
| 906 | – | register int  x; | 
| 940 |  |  | 
| 908 | – | setcolor(clr, 0.0, 0.0, 0.0); | 
| 941 |  | left = box.xmin - xoff; | 
| 942 |  | right = left + box.xsiz; | 
| 943 |  | if (left < 0) | 
| 945 |  | if (right > xmax) | 
| 946 |  | right = xmax; | 
| 947 |  | if (left >= right) | 
| 948 | < | return(-1); | 
| 948 | > | return(0); | 
| 949 |  | top = box.ymin - yoff; | 
| 950 |  | bottom = top + box.ysiz; | 
| 951 |  | if (top < 0) | 
| 953 |  | if (bottom > ymax) | 
| 954 |  | bottom = ymax; | 
| 955 |  | if (top >= bottom) | 
| 924 | – | return(-1); | 
| 925 | – | if (left == ll && right == lr && top == lt && bottom == lb) { | 
| 926 | – | copycolor(clr, lc); | 
| 956 |  | return(0); | 
| 928 | – | } | 
| 957 |  | for (y = top; y < bottom; y++) { | 
| 958 |  | if (getscan(y) == -1) | 
| 959 |  | return(-1); | 
| 960 | < | for (x = left; x < right; x++) { | 
| 933 | < | colr_color(ctmp, scanline[x]); | 
| 934 | < | addcolor(clr, ctmp); | 
| 935 | < | } | 
| 960 | > | (*f)(scanline+left, right-left, p); | 
| 961 |  | } | 
| 962 | < | d = 1.0/((right-left)*(bottom-top)); | 
| 938 | < | scalecolor(clr, d); | 
| 939 | < | ll = left; lr = right; lt = top; lb = bottom; | 
| 940 | < | copycolor(lc, clr); | 
| 941 | < | return(0); | 
| 962 | > | return((right-left)*(bottom-top)); | 
| 963 |  | } | 
| 964 |  |  | 
| 965 |  |  | 
| 966 | + | int | 
| 967 | + | addfix(scn, n)                  /* add fixation points to histogram */ | 
| 968 | + | COLR    *scn; | 
| 969 | + | int     n; | 
| 970 | + | { | 
| 971 | + | if (tmCvColrs(lscan, TM_NOCHROM, scn, n)) | 
| 972 | + | goto tmerr; | 
| 973 | + | if (tmAddHisto(lscan, n, FIXWEIGHT)) | 
| 974 | + | goto tmerr; | 
| 975 | + | return; | 
| 976 | + | tmerr: | 
| 977 | + | quiterr("tone mapping error"); | 
| 978 | + | } | 
| 979 | + |  | 
| 980 | + |  | 
| 981 |  | make_tonemap()                  /* initialize tone mapping */ | 
| 982 |  | { | 
| 983 |  | int  flags, y; | 
| 984 |  |  | 
| 985 | < | if (tmflags != -1 && fname == NULL) { | 
| 985 | > | if (tmflags != TM_F_LINEAR && fname == NULL) { | 
| 986 |  | fprintf(stderr, "%s: cannot adjust tone of standard input\n", | 
| 987 |  | progname); | 
| 988 | < | tmflags = -1; | 
| 988 | > | tmflags = TM_F_LINEAR; | 
| 989 |  | } | 
| 990 | < | if (tmflags == -1) { | 
| 990 | > | if (tmflags == TM_F_LINEAR) {   /* linear with clamping */ | 
| 991 |  | setcolrcor(pow, 1.0/gamcor); | 
| 992 |  | return; | 
| 993 |  | } | 
| 994 | < | if (tmTop != NULL)              /* already initialized? */ | 
| 959 | < | return; | 
| 960 | < | flags = tmflags; | 
| 994 | > | flags = tmflags;                /* histogram adjustment */ | 
| 995 |  | if (greyscale) flags |= TM_F_BW; | 
| 996 | < | /* initialize tm library */ | 
| 997 | < | if (tmInit(flags, stdprims, gamcor) == NULL) | 
| 998 | < | goto memerr; | 
| 999 | < | if (tmSetSpace(stdprims, WHTEFFICACY/exposure)) | 
| 1000 | < | goto tmerr; | 
| 967 | < | /* allocate encoding buffers */ | 
| 968 | < | if ((lscan = (TMbright *)malloc(xmax*sizeof(TMbright))) == NULL) | 
| 969 | < | goto memerr; | 
| 970 | < | if (greyscale) { | 
| 971 | < | cscan = TM_NOCHROM; | 
| 972 | < | if ((pscan = (BYTE *)malloc(sizeof(BYTE)*xmax)) == NULL) | 
| 996 | > | if (tmTop != NULL) {            /* reuse old histogram if one */ | 
| 997 | > | tmDone(tmTop); | 
| 998 | > | tmTop->flags = flags; | 
| 999 | > | } else {                        /* else initialize */ | 
| 1000 | > | if ((lscan = (TMbright *)malloc(xmax*sizeof(TMbright))) == NULL) | 
| 1001 |  | goto memerr; | 
| 1002 | < | } else if ((pscan=cscan = (BYTE *)malloc(3*sizeof(BYTE)*xmax)) == NULL) | 
| 1003 | < | goto memerr; | 
| 1004 | < | /* compute picture histogram */ | 
| 1005 | < | for (y = 0; y < ymax; y++) { | 
| 1006 | < | getscan(y); | 
| 1007 | < | if (tmCvColrs(lscan, TM_NOCHROM, scanline, xmax)) | 
| 1002 | > | if (greyscale) { | 
| 1003 | > | cscan = TM_NOCHROM; | 
| 1004 | > | if ((pscan = (BYTE *)malloc(sizeof(BYTE)*xmax)) == NULL) | 
| 1005 | > | goto memerr; | 
| 1006 | > | } else if ((pscan=cscan = (BYTE *)malloc(3*sizeof(BYTE)*xmax)) | 
| 1007 | > | == NULL) | 
| 1008 | > | goto memerr; | 
| 1009 | > | /* initialize tm library */ | 
| 1010 | > | if (tmInit(flags, stdprims, gamcor) == NULL) | 
| 1011 | > | goto memerr; | 
| 1012 | > | if (tmSetSpace(stdprims, WHTEFFICACY/exposure)) | 
| 1013 |  | goto tmerr; | 
| 1014 | < | if (tmAddHisto(lscan, xmax, 1)) | 
| 1015 | < | goto tmerr; | 
| 1014 | > | /* compute picture histogram */ | 
| 1015 | > | for (y = 0; y < ymax; y++) { | 
| 1016 | > | getscan(y); | 
| 1017 | > | if (tmCvColrs(lscan, TM_NOCHROM, scanline, xmax)) | 
| 1018 | > | goto tmerr; | 
| 1019 | > | if (tmAddHisto(lscan, xmax, 1)) | 
| 1020 | > | goto tmerr; | 
| 1021 | > | } | 
| 1022 |  | } | 
| 1023 | < | /* compute tone mapping */ | 
| 1023 | > | tmDup();                        /* add fixations to duplicate map */ | 
| 1024 | > | dobox(addfix, NULL); | 
| 1025 | > | /* (re)compute tone mapping */ | 
| 1026 |  | if (tmComputeMapping(gamcor, 0., 0.)) | 
| 1027 |  | goto tmerr; | 
| 1028 |  | return; | 
| 1039 |  | { | 
| 1040 |  | register BYTE  *ps; | 
| 1041 |  |  | 
| 1042 | < | if (tmflags == -1) { | 
| 1042 | > | if (tmflags == TM_F_LINEAR) { | 
| 1043 |  | if (scale) | 
| 1044 |  | shiftcolrs(scn, len, scale); | 
| 1045 |  | colrs_gambs(scn, len); | 
| 1160 |  | { | 
| 1161 |  | int     y; | 
| 1162 |  | register unsigned int4  *dp; | 
| 1163 | + | register unsigned int2  *dph; | 
| 1164 |  | register int    x; | 
| 1165 |  | /* initialize tone mapping */ | 
| 1166 |  | make_tonemap(); | 
| 1167 |  | /* read and convert file */ | 
| 1168 |  | dp = (unsigned int4 *)ourdata; | 
| 1169 | + | dph = (unsigned int2 *)ourdata; | 
| 1170 |  | for (y = 0; y < ymax; y++) { | 
| 1171 |  | getscan(y); | 
| 1172 |  | add2icon(y, scanline); | 
| 1173 |  | tmap_colrs(scanline, xmax); | 
| 1174 | < | if (ourras->image->blue_mask & 1) | 
| 1174 | > | switch (ourras->image->blue_mask) { | 
| 1175 | > | case 0xff:              /* 24-bit RGB */ | 
| 1176 |  | for (x = 0; x < xmax; x++) | 
| 1177 |  | *dp++ = (unsigned int4)scanline[x][RED] << 16 | | 
| 1178 |  | (unsigned int4)scanline[x][GRN] << 8 | | 
| 1179 |  | (unsigned int4)scanline[x][BLU] ; | 
| 1180 | < | else | 
| 1180 | > | break; | 
| 1181 | > | case 0xff0000:          /* 24-bit BGR */ | 
| 1182 |  | for (x = 0; x < xmax; x++) | 
| 1183 |  | *dp++ = (unsigned int4)scanline[x][RED] | | 
| 1184 |  | (unsigned int4)scanline[x][GRN] << 8 | | 
| 1185 |  | (unsigned int4)scanline[x][BLU] << 16 ; | 
| 1186 | + | break; | 
| 1187 | + | #if 0 | 
| 1188 | + | case 0x1f:              /* 15-bit RGB */ | 
| 1189 | + | for (x = 0; x < xmax; x++) | 
| 1190 | + | *dph++ =        (scanline[x][RED] << 7 & 0x7c00) | | 
| 1191 | + | (scanline[x][GRN] << 2 & 0x3e0) | | 
| 1192 | + | (unsigned)scanline[x][BLU] >> 3 ; | 
| 1193 | + | break; | 
| 1194 | + | case 0x7c00:            /* 15-bit BGR */ | 
| 1195 | + | for (x = 0; x < xmax; x++) | 
| 1196 | + | *dph++ =        (unsigned)scanline[x][RED] >> 3 | | 
| 1197 | + | (scanline[x][GRN] << 2 & 0x3e0) | | 
| 1198 | + | (scanline[x][BLU] << 7 & 0x7c00) ; | 
| 1199 | + | break; | 
| 1200 | + | #endif | 
| 1201 | + | default:                /* unknown */ | 
| 1202 | + | if (ourvis.depth > 16) | 
| 1203 | + | for (x = 0; x < xmax; x++) { | 
| 1204 | + | *dp = ourras->image->red_mask & | 
| 1205 | + | ourras->image->red_mask*scanline[x][RED]/255; | 
| 1206 | + | *dp |= ourras->image->green_mask & | 
| 1207 | + | ourras->image->green_mask*scanline[x][GRN]/255; | 
| 1208 | + | *dp++ |= ourras->image->blue_mask & | 
| 1209 | + | ourras->image->blue_mask*scanline[x][BLU]/255; | 
| 1210 | + | } | 
| 1211 | + | else | 
| 1212 | + | for (x = 0; x < xmax; x++) { | 
| 1213 | + | *dph = ourras->image->red_mask & | 
| 1214 | + | ourras->image->red_mask*scanline[x][RED]/255; | 
| 1215 | + | *dph |= ourras->image->green_mask & | 
| 1216 | + | ourras->image->green_mask*scanline[x][GRN]/255; | 
| 1217 | + | *dph++ |= ourras->image->blue_mask & | 
| 1218 | + | ourras->image->blue_mask*scanline[x][BLU]/255; | 
| 1219 | + | } | 
| 1220 | + | break; | 
| 1221 | + | } | 
| 1222 |  | } | 
| 1223 |  | } | 
| 1224 |  |  |