Back to index

radiance  4R0+20100331
ra_ps.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: ra_ps.c,v 2.28 2004/03/28 20:33:14 schorsch Exp $";
00003 #endif
00004 /*
00005  *  Radiance picture to PostScript file translator -- one way!
00006  */
00007 
00008 #include  <stdio.h>
00009 #include  <string.h>
00010 #include  <math.h>
00011 #include  <ctype.h>
00012 
00013 #include  "platform.h"
00014 #include  "color.h"
00015 #include  "resolu.h"
00016 
00017 #define UPPER(c)     ((c)&~0x20)          /* ASCII trick */
00018 
00019 #define CODE6GAM     1.47                 /* gamma for 6-bit codes */
00020 #define DEFGGAM             1.0                  /* greyscale device gamma */
00021 #define DEFCGAM             1.8                  /* color device gamma */
00022 
00023 #define GRY          -1                   /* artificial index for grey */
00024 
00025 #define DEFMARG             0.5                  /* default margin (inches) */
00026 #define DEFWIDTH     8.5                  /* default page width */
00027 #define DEFHEIGHT    11                   /* default page height */
00028 #define HMARGIN             (hmarg*72)           /* horizontal margin */
00029 #define VMARGIN             (vmarg*72)           /* vertical margin */
00030 #define PWIDTH              (width*72-2*HMARGIN) /* width of device */
00031 #define PHEIGHT             (height*72-2*VMARGIN)       /* height of device */
00032 
00033 #define RUNCHR              '*'                  /* character to start rle */
00034 #define MINRUN              4                    /* minimum run-length */
00035 #define RSTRT        '!'                  /* character for MINRUN */
00036 #define MAXRUN              (MINRUN+'~'-RSTRT)   /* maximum run-length */
00037 
00038 char  code[] =                     /* 6-bit code lookup table */
00039        "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@+";
00040 
00041 int  wrongformat = 0;                     /* input in wrong format? */
00042 double pixaspect = 1.0;            /* pixel aspect ratio */
00043 
00044 double  devgam = 0.;               /* device gamma response */
00045 double  hmarg = DEFMARG,
00046        vmarg = DEFMARG;            /* horizontal and vertical margins */
00047 double width = DEFWIDTH,
00048        height = DEFHEIGHT;         /* default paper width and height */
00049 double  dpi = 0;                   /* print density (0 if unknown) */
00050 int  docolor = 1;                  /* produce color image? */
00051 int  bradj = 0;                           /* brightness adjustment */
00052 int  ncopies = 1;                  /* number of copies */
00053 
00054 char  *progname;
00055 int  xmax, ymax;                   /* input image dimensions */
00056 
00057 typedef void putprimf_t(COLR *scn, int pri);
00058 
00059 static gethfunc headline;
00060 static putprimf_t Aputprim, Bputprim, Cputprim;
00061 
00062 static double unit2inch(register char *s);
00063 static int matchid(char *name, char *id);
00064 static void parsepaper(char *ps);
00065 static void quiterr(char *err);
00066 static void PSheader(int ac, char **av);
00067 static void PStrailer(void);
00068 static void PSprocdef(char *nam);
00069 static void ra2ps(void);
00070 static void putrle(int cnt, int cod);
00071 
00072 
00073 putprimf_t *putprim = Aputprim;           /* function for writing scanline */
00074 
00075 
00076 static int
00077 headline(            /* check header line */
00078        char   *s,
00079        void   *p
00080 )
00081 {
00082        char  fmt[32];
00083 
00084        if (isformat(s)) {
00085               formatval(fmt, s);
00086               wrongformat = strcmp(fmt, COLRFMT);
00087        } else if (isaspect(s))
00088               pixaspect *= aspectval(s);
00089        return(0);
00090 }
00091 
00092 int
00093 main(int  argc, char  *argv[])
00094 {
00095        int  i;
00096        double d;
00097        
00098        progname = argv[0];
00099 
00100        for (i = 1; i < argc; i++)
00101               if (argv[i][0] == '-')
00102                      switch (argv[i][1]) {
00103                      case 'b':            /* produce b&w PostScript */
00104                             docolor = 0;
00105                             break;
00106                      case 'c':            /* produce color PostScript */
00107                             docolor = 1;
00108                             break;
00109                      case 'A':            /* standard ASCII encoding */
00110                             putprim = Aputprim;
00111                             break;
00112                      case 'B':            /* standard binary encoding */
00113                             putprim = Bputprim;
00114                             break;
00115                      case 'C':            /* compressed ASCII encoding */
00116                             putprim = Cputprim;
00117                             break;
00118                      case 'd':            /* print density */
00119                             dpi = atof(argv[++i]);
00120                             break;
00121                      case 'g':            /* device gamma adjustment */
00122                             devgam = atof(argv[++i]);
00123                             break;
00124                      case 'p':            /* paper size */
00125                             parsepaper(argv[++i]);
00126                             break;
00127                      case 'm':            /* margin */
00128                             d = atof(argv[i+1]);
00129                             d *= unit2inch(argv[i+1]);
00130                             switch (argv[i][2]) {
00131                             case '\0':
00132                                    hmarg = vmarg = d;
00133                                    break;
00134                             case 'h':
00135                                    hmarg = d;
00136                                    break;
00137                             case 'v':
00138                                    vmarg = d;
00139                                    break;
00140                             default:
00141                                    goto userr;
00142                             }
00143                             i++;
00144                             break;
00145                      case 'e':            /* exposure adjustment */
00146                             if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
00147                                    goto userr;
00148                             bradj = atoi(argv[++i]);
00149                             break;
00150                      case 'n':            /* number of copies */
00151                             ncopies = atoi(argv[++i]);
00152                             break;
00153                      default:
00154                             goto userr;
00155                      }
00156               else
00157                      break;
00158 
00159        if (i < argc-2)
00160               goto userr;
00161        if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) {
00162               fprintf(stderr, "%s: can't open input \"%s\"\n",
00163                             progname, argv[i]);
00164               exit(1);
00165        }
00166        if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) {
00167               fprintf(stderr, "%s: can't open output \"%s\"\n",
00168                             progname, argv[i+1]);
00169               exit(1);
00170        }
00171        SET_FILE_BINARY(stdin);
00172                             /* get our header */
00173        getheader(stdin, headline, NULL);
00174        if (wrongformat || fgetresolu(&xmax, &ymax, stdin) < 0)
00175               quiterr("bad picture format");
00176                             /* gamma compression */
00177        if (devgam <= 0.05)
00178               devgam = docolor ? DEFCGAM : DEFGGAM;
00179        if (putprim == Cputprim)
00180               setcolrgam(CODE6GAM);
00181        else if (devgam != 1.)
00182               setcolrgam(devgam);
00183                             /* write header */
00184        PSheader(argc, argv);
00185                             /* convert file */
00186        ra2ps();
00187                             /* write trailer */
00188        PStrailer();
00189        exit(0);
00190 userr:
00191        fprintf(stderr,
00192 "Usage: %s [-b|c][-A|B|C][-e +/-stops][-p paper][-m[h|v] margin][-d dpi][-g gamma] [input [output]]\n",
00193                      progname);
00194        exit(1);
00195 }
00196 
00197 
00198 static double
00199 unit2inch(           /* determine unit */
00200        register char *s
00201 )
00202 {
00203        static struct unit {char n; float f;} u[] = {
00204               {'i', 1.},
00205               {'m', 1./25.4},
00206               {'c', 1./2.54},
00207               {'\0',0} };
00208        register struct unit *up;
00209 
00210        while (*s && !isalpha(*s))
00211               s++;
00212        for (up = u; up->n; up++)
00213               if (up->n == *s)
00214                      return(up->f);
00215        return(1.);
00216 }
00217 
00218 
00219 static int
00220 matchid(      /* see if name matches id (case insensitive) */
00221        char   *name,
00222        register char *id
00223 )
00224 {
00225        register char *s = name;
00226 
00227        while (*s) {
00228               if (isalpha(*s)) {
00229                      if (!isalpha(*id) || UPPER(*s) != UPPER(*id))
00230                             return(0);
00231               } else if (*s != *id)
00232                      return(0);
00233               s++; id++;
00234        }
00235        return(!*id || s-name >= 3);       /* substrings >= 3 chars OK */
00236 }
00237 
00238 
00239 static void
00240 parsepaper(          /* determine paper size from name */
00241        char   *ps
00242 )
00243 {
00244        static struct psize {char n[12]; float w,h;} p[] = {
00245               {"envelope", 4.12, 9.5},
00246               {"executive", 7.25, 10.5},
00247               {"letter", 8.5, 11.},
00248               {"lettersmall", 7.68, 10.16},
00249               {"legal", 8.5, 14.},
00250               {"monarch", 3.87, 7.5},
00251               {"statement", 5.5, 8.5},
00252               {"tabloid", 11., 17.},
00253               {"A3", 11.69, 16.54},
00254               {"A4", 8.27, 11.69},
00255               {"A4small", 7.47, 10.85},
00256               {"A5", 6.00, 8.27},
00257               {"A6", 4.13, 6.00},
00258               {"B4", 10.12, 14.33},
00259               {"B5", 7.17, 10.12},
00260               {"C5", 6.38, 9.01},
00261               {"C6", 4.49, 6.38},
00262               {"DL", 4.33, 8.66},
00263               {"hagaki", 3.94, 5.83},
00264               {"",0.0,0.0} };
00265        register struct psize       *pp;
00266        register char *s = ps;
00267        double d;
00268 
00269        if (isdigit(*s)) {          /* check for WWxHH specification */
00270               width = atof(s);
00271               while (*s && !isalpha(*s))
00272                      s++;
00273               d = unit2inch(s);
00274               height = atof(++s);
00275               width *= d;
00276               height *= d;
00277               if ((width >= 1.) & (height >= 1.))
00278                      return;
00279        } else                      /* check for match to standard size */
00280               for (pp = p; pp->n[0]; pp++)
00281                      if (matchid(s, pp->n)) {
00282                             width = pp->w;
00283                             height = pp->h;
00284                             return;
00285                      }
00286        fprintf(stderr, "%s: unknown paper size \"%s\" -- known sizes:\n",
00287                      progname, ps);
00288        fprintf(stderr, "_Name________Width_Height_(inches)\n");
00289        for (pp = p; pp->n[0]; pp++)
00290               fprintf(stderr, "%-11s  %5.2f  %5.2f\n", pp->n, pp->w, pp->h);
00291        fprintf(stderr, "Or use WWxHH size specification\n");
00292        exit(1);
00293 }
00294 
00295 
00296 static void
00297 quiterr(             /* print message and exit */
00298        char  *err
00299 )
00300 {
00301        if (err != NULL) {
00302               fprintf(stderr, "%s: %s\n", progname, err);
00303               exit(1);
00304        }
00305        exit(0);
00306 }
00307 
00308 
00309 static void
00310 PSheader(            /* print PostScript header */
00311        int  ac,
00312        char  **av
00313 )
00314 {
00315        char  *rstr;
00316        int  landscape, rotate, n;
00317        double pwidth, pheight;
00318        double iwidth, iheight;
00319                                    /* EPS comments */
00320        puts("%!PS-Adobe-2.0 EPSF-2.0");
00321        printf("%%%%Title: "); printargs(ac, av, stdout);
00322        printf("%%%%Creator: %s\n", progname);
00323        printf("%%%%Pages: %d\n", ncopies);
00324        if ( (landscape = xmax > pixaspect*ymax) )
00325               puts("%%Orientation: Landscape");
00326        else
00327               puts("%%Orientation: Portrait");
00328        if ( (rotate = (PWIDTH > PHEIGHT) ^ landscape) ) {
00329               pwidth = PHEIGHT;
00330               pheight = PWIDTH;
00331        } else {
00332               pwidth = PWIDTH;
00333               pheight = PHEIGHT;
00334        }
00335        if (dpi > 100 && (pixaspect >= 0.99) & (pixaspect <= 1.01))
00336               if (pheight/pwidth > ymax/xmax) {
00337                      n = pwidth*dpi/xmax; /* floor */
00338                      iwidth = n > 0 ? (double)(n*xmax)/dpi : pwidth;
00339                      iheight = iwidth*ymax/xmax;
00340               } else {
00341                      n = pheight*dpi/ymax;       /* floor */
00342                      iheight = n > 0 ? (double)(n*ymax)/dpi : pheight;
00343                      iwidth = iheight*xmax/ymax;
00344               }
00345        else
00346               if (pheight/pwidth > pixaspect*ymax/xmax) {
00347                      iwidth = pwidth;
00348                      iheight = iwidth*pixaspect*ymax/xmax;
00349               } else {
00350                      iheight = pheight;
00351                      iwidth = iheight*xmax/(pixaspect*ymax);
00352               }
00353        if (rotate)
00354               printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
00355                             HMARGIN+(pheight-iheight)*.5,
00356                             VMARGIN+(pwidth-iwidth)*.5,
00357                             HMARGIN+(pheight-iheight)*.5+iheight,
00358                             VMARGIN+(pwidth-iwidth)*.5+iwidth);
00359        else
00360               printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
00361                             HMARGIN+(pwidth-iwidth)*.5,
00362                             VMARGIN+(pheight-iheight)*.5,
00363                             HMARGIN+(pwidth-iwidth)*.5+iwidth,
00364                             VMARGIN+(pheight-iheight)*.5+iheight);
00365        puts("%%EndComments");
00366        puts("gsave save");
00367        puts("17 dict begin");
00368                                    /* define image reader */
00369        if (docolor) {
00370               printf("/redline %d string def\n", xmax);
00371               printf("/grnline %d string def\n", xmax);
00372               printf("/bluline %d string def\n", xmax);
00373        } else
00374               printf("/gryline %d string def\n", xmax);
00375                                    /* use compressed encoding? */
00376        if (putprim == Cputprim)
00377               PSprocdef("read6bitRLE");
00378                                    /* set up transformation matrix */
00379        printf("%f %f translate\n", HMARGIN, VMARGIN);
00380        if (rotate) {
00381               printf("%f 0 translate\n", PWIDTH);
00382               puts("90 rotate");
00383        }
00384        printf("%f %f translate\n", (pwidth-iwidth)*.5, (pheight-iheight)*.5);
00385        printf("%f %f scale\n", iwidth, iheight);
00386        puts("%%EndProlog");
00387                                    /* start image procedure */
00388        printf("%d %d 8 [%d 0 0 %d 0 %d]\n", xmax, ymax, xmax, -ymax, ymax);
00389        if (putprim == Cputprim) {
00390               if (docolor) {
00391                      puts("{redline read6bitRLE}");
00392                      puts("{grnline read6bitRLE}");
00393                      puts("{bluline read6bitRLE}");
00394                      puts("true 3 colorimage");
00395               } else
00396                      puts("{gryline read6bitRLE} image");
00397        } else {
00398               rstr = putprim==Aputprim ? "readhexstring" : "readstring";
00399               if (docolor) {
00400                      printf("{currentfile redline %s pop}\n", rstr);
00401                      printf("{currentfile grnline %s pop}\n", rstr);
00402                      printf("{currentfile bluline %s pop}\n", rstr);
00403                      puts("true 3 colorimage");
00404               } else
00405                      printf("{currentfile gryline %s pop} image\n", rstr);
00406        }
00407 }
00408 
00409 
00410 static void
00411 PStrailer(void)                    /* print PostScript trailer */
00412 {
00413        puts("%%Trailer");
00414        if (ncopies > 1)
00415               printf("/#copies %d def\n", ncopies);
00416        puts("showpage");
00417        puts("end");
00418        puts("restore grestore");
00419        puts("%%EOF");
00420 }
00421 
00422 
00423 static void
00424 PSprocdef(                  /* define PS procedure to read image */
00425        char  *nam
00426 )
00427 {
00428        short  itab[128];
00429        register int  i;
00430                             /* assign code values */
00431        for (i = 0; i < 128; i++)   /* clear */
00432               itab[i] = -1;
00433        for (i = 1; i < 63; i++)    /* assign greys */
00434               itab[(int)code[i]] = 256.0*pow((i+.5)/64.0, CODE6GAM/devgam);
00435        itab[(int)code[0]] = 0;            /* black is black */
00436        itab[(int)code[63]] = 255;         /* and white is white */
00437        printf("/codetab [");
00438        for (i = 0; i < 128; i++) {
00439               if (!(i & 0xf))
00440                      putchar('\n');
00441               printf(" %3d", itab[i]);
00442        }
00443        printf("\n] def\n");
00444        printf("/nrept 0 def\n");
00445        printf("/readbyte { currentfile read not {stop} if } bind def\n");
00446        printf("/decode { codetab exch get } bind def\n");
00447        printf("/%s {\t%% scanbuffer\n", nam);
00448        printf("\t/scanline exch def\n");
00449        printf("\t{ 0 1 %d { scanline exch\n", xmax-1);
00450        printf("\t\tnrept 0 le\n");
00451        printf("\t\t\t{ { readbyte dup %d eq\n", RUNCHR);
00452        printf("\t\t\t\t\t{ pop /nrept readbyte %d sub def\n", RSTRT-MINRUN+1);
00453        printf("\t\t\t\t\t\t/reptv readbyte decode def\n");
00454        printf("\t\t\t\t\t\treptv exit }\n");
00455        printf("\t\t\t\t\t{ decode dup 0 lt {pop} {exit} ifelse }\n");
00456        printf("\t\t\t\tifelse } loop }\n");
00457        printf("\t\t\t{ /nrept nrept 1 sub def reptv }\n");
00458        printf("\t\tifelse put\n");
00459        printf("\t\t} for\n");
00460        printf("\t} stopped {pop pop 0 string} {scanline} ifelse\n");
00461        printf("} bind def\n");
00462 }
00463 
00464 
00465 static void
00466 ra2ps(void)                        /* convert Radiance scanlines to 6-bit */
00467 {
00468        register COLR *scanin;
00469        int    y;
00470                                           /* allocate scanline */
00471        scanin = (COLR *)malloc(xmax*sizeof(COLR));
00472        if (scanin == NULL)
00473               quiterr("out of memory in ra2ps");
00474                                           /* convert image */
00475        for (y = ymax-1; y >= 0; y--) {
00476               if (freadcolrs(scanin, xmax, stdin) < 0)
00477                      quiterr("error reading Radiance picture");
00478               if (putprim == Cputprim || devgam != 1.) {
00479                      if (bradj)                  /* adjust exposure */
00480                             shiftcolrs(scanin, xmax, bradj);
00481                      colrs_gambs(scanin, xmax);  /* gamma compression */
00482               } else
00483                      normcolrs(scanin, xmax, bradj);
00484               if (docolor) {
00485                      (*putprim)(scanin, RED);
00486                      (*putprim)(scanin, GRN);
00487                      (*putprim)(scanin, BLU);
00488               } else
00489                      (*putprim)(scanin, GRY);
00490               if (ferror(stdout))
00491                      quiterr("error writing PostScript file");
00492        }
00493        putchar('\n');
00494                                           /* free scanline */
00495        free((void *)scanin);
00496 }
00497 
00498 
00499 static void
00500 Aputprim(            /* put out hex ASCII primary from scanline */
00501        COLR   *scn,
00502        int    pri
00503 )
00504 {
00505        static char   hexdigit[] = "0123456789ABCDEF";
00506        static int    col = 0;
00507        register int  x, c;
00508 
00509        for (x = 0; x < xmax; x++) {
00510               if (pri == GRY)
00511                      c = normbright(scn[x]);
00512               else
00513                      c = scn[x][pri];
00514               if (c > 255) c = 255;
00515               putchar(hexdigit[c>>4]);
00516               putchar(hexdigit[c&0xf]);
00517               if ((col += 2) >= 72) {
00518                      putchar('\n');
00519                      col = 0;
00520               }
00521        }
00522 }
00523 
00524 
00525 static void
00526 Bputprim(            /* put out binary primary from scanline */
00527        COLR   *scn,
00528        int    pri
00529 )
00530 {
00531        register int  x, c;
00532 
00533        for (x = 0; x < xmax; x++) {
00534               if (pri == GRY)
00535                      c = normbright(scn[x]);
00536               else
00537                      c = scn[x][pri];
00538               if (c > 255) c = 255;
00539               putchar(c);
00540        }
00541 }
00542 
00543 
00544 static void
00545 Cputprim(            /* put out compressed primary from scanline */
00546        COLR   *scn,
00547        int    pri
00548 )
00549 {
00550        register int  c;
00551        register int  x;
00552        int    lastc, cnt;
00553 
00554        lastc = -1; cnt = 0;
00555        for (x = 0; x < xmax; x++) {
00556               if (pri == GRY)
00557                      c = normbright(scn[x]) + 2;
00558               else
00559                      c = scn[x][pri] + 2;
00560               if (c > 255) c = 255;
00561               c = code[c>>2];
00562               if (c == lastc && cnt < MAXRUN)
00563                      cnt++;
00564               else {
00565                      putrle(cnt, lastc);
00566                      lastc = c;
00567                      cnt = 1;
00568               }
00569        }
00570        putrle(cnt, lastc);
00571 }
00572 
00573 
00574 static void
00575 putrle(              /* put out cnt of cod */
00576        register int  cnt,
00577        register int  cod
00578 )
00579 {
00580        static int    col = 0;
00581 
00582        if (cnt >= MINRUN) {
00583               col += 3;
00584               putchar(RUNCHR);
00585               putchar(RSTRT-MINRUN+cnt);
00586               putchar(cod);
00587        } else {
00588               col += cnt;
00589               while (cnt-- > 0)
00590                      putchar(cod);
00591        }
00592        if (col >= 72) {
00593               putchar('\n');
00594               col = 0;
00595        }
00596 }