| 51 |  | "ascii", | 
| 52 |  | COLRFMT, | 
| 53 |  | CIEFMT, | 
| 54 | + | SPECFMT, | 
| 55 |  | DEPTH16FMT, | 
| 56 |  | NORMAL32FMT, | 
| 57 |  | "float", | 
| 66 |  | NULL    /* terminator */ | 
| 67 |  | }; | 
| 68 |  | /* keep consistent with above */ | 
| 69 | < | enum {TYP_UNKNOWN, TYP_TEXT, TYP_ASCII, TYP_RGBE, TYP_XYZE, | 
| 69 | > | enum {TYP_UNKNOWN, TYP_TEXT, TYP_ASCII, TYP_RGBE, TYP_XYZE, TYP_SPEC, | 
| 70 |  | TYP_DEPTH, TYP_NORM, TYP_FLOAT, TYP_DOUBLE, | 
| 71 |  | TYP_RBFMESH, TYP_OCTREE, TYP_TMESH, | 
| 72 |  | TYP_ID8, TYP_ID16, TYP_ID24, TYP_BINARY}; | 
| 245 |  | return(real_check(colval(c1,p), colval(c2,p))); | 
| 246 |  | } | 
| 247 |  |  | 
| 248 | + | /* Compare two color spectra for equivalence */ | 
| 249 | + | static int | 
| 250 | + | spec_check(COLORV *sc1, COLORV *sc2) | 
| 251 | + | { | 
| 252 | + | int     p, k; | 
| 253 | + |  | 
| 254 | + | if (!real_check(scolor_mean(sc1), scolor_mean(sc2))) | 
| 255 | + | return(0); | 
| 256 | + |  | 
| 257 | + | p = 0;                          /* find max. component */ | 
| 258 | + | for (k = NCSAMP; --k; ) | 
| 259 | + | if (sc1[k] > sc1[p]) | 
| 260 | + | p = k; | 
| 261 | + |  | 
| 262 | + | return(real_check(sc1[p], sc2[p])); | 
| 263 | + | } | 
| 264 | + |  | 
| 265 |  | /* Compare two normal directions for equivalence */ | 
| 266 |  | static int | 
| 267 |  | norm_check(FVECT nv1, FVECT nv2) | 
| 668 |  | return(good_RMS());                     /* final check for reals */ | 
| 669 |  | } | 
| 670 |  |  | 
| 671 | + | /* Set resolution based on NROWS, NCOLS in header */ | 
| 672 | + | static int | 
| 673 | + | set_resolu(RESOLU *rs, LUTAB *htp) | 
| 674 | + | { | 
| 675 | + | const char      *val; | 
| 676 | + |  | 
| 677 | + | rs->rt = PIXSTANDARD; | 
| 678 | + | val = (const char *)lu_find(htp, "NROWS")->data; | 
| 679 | + | if (!val) return(0); | 
| 680 | + | rs->yr = atoi(val); | 
| 681 | + | if (rs->yr <= 0) return(-1); | 
| 682 | + | val = (const char *)lu_find(htp, "NCOLS")->data; | 
| 683 | + | if (!val) return(0); | 
| 684 | + | rs->xr = atoi(val); | 
| 685 | + | if (rs->xr <= 0) return(-1); | 
| 686 | + | return(1); | 
| 687 | + | } | 
| 688 | + |  | 
| 689 |  | /* Check image/map resolutions */ | 
| 690 |  | static int | 
| 691 |  | check_resolu(const char *class, RESOLU *r1p, RESOLU *r2p) | 
| 743 |  | if (color_check(scan1[x], scan2[x])) | 
| 744 |  | continue; | 
| 745 |  | if (report != REP_QUIET) { | 
| 746 | < | printf( | 
| 711 | < | "%s: pixels at scanline %d offset %d differ\n", | 
| 746 | > | printf("%s: pixels at scanline %d offset %d differ\n", | 
| 747 |  | progname, y, x); | 
| 748 |  | if (report >= REP_VERBOSE) { | 
| 749 |  | printf("%s: (R,G,B)=(%g,%g,%g)\n", | 
| 766 |  | return(good_RMS());                     /* final check of RMS */ | 
| 767 |  | } | 
| 768 |  |  | 
| 769 | + | /* Compare two inputs that are known to be spectral images */ | 
| 770 | + | static int | 
| 771 | + | compare_spec() | 
| 772 | + | { | 
| 773 | + | static char     NCstr[] = NCOMPSTR; | 
| 774 | + | RESOLU          rs1, rs2; | 
| 775 | + | COLORV          *scan1, *scan2; | 
| 776 | + | const char      *val; | 
| 777 | + | int             x, y; | 
| 778 | + |  | 
| 779 | + | if (report >= REP_VERBOSE) { | 
| 780 | + | fputs(progname, stdout); | 
| 781 | + | fputs(": comparing inputs as spectral images\n", stdout); | 
| 782 | + | } | 
| 783 | + | if (!(set_resolu(&rs1, &hdr1) || fgetsresolu(&rs1, f1in))) | 
| 784 | + | return(0); | 
| 785 | + | if (!(set_resolu(&rs2, &hdr2) || fgetsresolu(&rs2, f2in))) | 
| 786 | + | return(0); | 
| 787 | + | if (!check_resolu("Spectral image", &rs1, &rs2)) | 
| 788 | + | return(0); | 
| 789 | + | NCstr[LNCOMPSTR-1] = '\0'; | 
| 790 | + | val = (const char *)lu_find(&hdr1, NCstr)->data; | 
| 791 | + | if (!val || (NCSAMP = atoi(val)) < 3) { | 
| 792 | + | if (report != REP_QUIET) { | 
| 793 | + | if (val) | 
| 794 | + | printf("%s: illegal # components (%d) for spectral image\n", | 
| 795 | + | progname, NCSAMP); | 
| 796 | + | else | 
| 797 | + | printf("%s: missing %s in header for spectral image\n", | 
| 798 | + | progname, NCstr); | 
| 799 | + | } | 
| 800 | + | return(0); | 
| 801 | + | } | 
| 802 | + | scan1 = (COLORV *)malloc(sizeof(COLORV)*NCSAMP*scanlen(&rs1)); | 
| 803 | + | scan2 = (COLORV *)malloc(sizeof(COLORV)*NCSAMP*scanlen(&rs2)); | 
| 804 | + | if (!scan1 | !scan2) { | 
| 805 | + | fprintf(stderr, "%s: out of memory in compare_hdr()\n", progname); | 
| 806 | + | exit(2); | 
| 807 | + | } | 
| 808 | + | for (y = 0; y < numscans(&rs1); y++) { | 
| 809 | + | if ((freadsscan(scan1, NCSAMP, scanlen(&rs1), f1in) < 0) | | 
| 810 | + | (freadsscan(scan2, NCSAMP, scanlen(&rs2), f2in) < 0)) { | 
| 811 | + | if (report != REP_QUIET) | 
| 812 | + | printf("%s: unexpected end-of-file\n", progname); | 
| 813 | + | free(scan1); | 
| 814 | + | free(scan2); | 
| 815 | + | return(0); | 
| 816 | + | } | 
| 817 | + | for (x = 0; x < scanlen(&rs1); x++) { | 
| 818 | + | if (spec_check(scan1+x*NCSAMP, scan2+x*NCSAMP)) | 
| 819 | + | continue; | 
| 820 | + | if (report != REP_QUIET) { | 
| 821 | + | int     k; | 
| 822 | + | printf("%s: spectra at scanline %d offset %d differ\n", | 
| 823 | + | progname, y, x); | 
| 824 | + | if (report >= REP_VERBOSE) { | 
| 825 | + | printf("%s: spectrum =", f1name); | 
| 826 | + | for (k = 0; k < NCSAMP; k++) | 
| 827 | + | printf(" %g", scan1[x*NCSAMP+k]); | 
| 828 | + | fputc('\n', stdout); | 
| 829 | + | printf("%s: spectrum =", f2name); | 
| 830 | + | for (k = 0; k < NCSAMP; k++) | 
| 831 | + | printf(" %g", scan2[x*NCSAMP+k]); | 
| 832 | + | fputc('\n', stdout); | 
| 833 | + | } | 
| 834 | + | } | 
| 835 | + | free(scan1); | 
| 836 | + | free(scan2); | 
| 837 | + | return(0); | 
| 838 | + | } | 
| 839 | + | } | 
| 840 | + | free(scan1); | 
| 841 | + | free(scan2); | 
| 842 | + | return(good_RMS());                     /* final check of RMS */ | 
| 843 | + | } | 
| 844 | + |  | 
| 845 |  | /* Set reference depth based on header variable */ | 
| 846 |  | static int | 
| 847 |  | set_refdepth(DEPTHCODEC *dcp, LUTAB *htp) | 
| 1155 |  | case TYP_RGBE: | 
| 1156 |  | case TYP_XYZE: | 
| 1157 |  | return( !compare_hdr() ); | 
| 1158 | + | case TYP_SPEC: | 
| 1159 | + | return( !compare_spec() ); | 
| 1160 |  | case TYP_DEPTH: | 
| 1161 |  | return( !compare_depth() ); | 
| 1162 |  | case TYP_NORM: |