home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / xloadimage.c < prev    next >
C/C++ Source or Header  |  1996-03-18  |  16KB  |  563 lines

  1. /* xloadimage.c:
  2.  *
  3.  * generic image loader for X11
  4.  *
  5.  * jim frost 09.27.89
  6.  *
  7.  * Copyright 1989, 1990, 1991 Jim Frost.
  8.  * See included file "copyright.h" for complete copyright information.
  9.  */
  10.  
  11. #include "copyright.h"
  12. #include "xloadimage.h"
  13. #ifdef VMS
  14. #include "patchlevel."
  15. #define NO_FORK
  16. #else
  17. #include "patchlevel"
  18. #endif
  19. #include <signal.h>
  20.  
  21. extern double atof();
  22.  
  23. char *ProgramName= "xloadimage";
  24.  
  25. /* if an image loader needs to have our display and screen, it will get
  26.  * them from here.  this is done to keep most of the image routines
  27.  * clean
  28.  */
  29.  
  30. Display      *Disp= NULL;
  31. int           Scrn= 0;
  32. int           _Xdebug = 0;
  33. char         *BuildDate = "18/3/96";
  34. char         *BuildUser = "Filippo Sartori";
  35. char         *BuildSystem = "OS/2";
  36.  
  37.  
  38. /* used for the -default option.  this is the root weave bitmap with
  39.  * the bits in the order that xloadimage likes.
  40.  */
  41.  
  42. #define root_weave_width 4
  43. #define root_weave_height 4
  44. static byte root_weave_bits[] = {
  45.   0xe0, 0xb0, 0xd0, 0x70
  46. };
  47.  
  48. static Image *doProcessOnImage(image, option, verbose)
  49.      Image *image;
  50.      Option *option;
  51. { Image  *retimage= image;
  52.   XColor  xcolor; /* color for foreground/background */
  53.  
  54.   switch (option->type) {
  55.   case BACKGROUND:
  56.     if (image->depth > 1)
  57.       break;
  58.     XParseColor(Disp, DefaultColormap(Disp, Scrn), option->info.background,
  59.         &xcolor);
  60.     image->rgb.red[0]= xcolor.red;
  61.     image->rgb.green[0]= xcolor.green;
  62.     image->rgb.blue[0]= xcolor.blue;
  63.     break;
  64.  
  65.   case BRIGHT:
  66.     brighten(image, option->info.bright, verbose);
  67.     break;
  68.  
  69.   case CLIP:
  70.     retimage= clip(image, option->info.clip.x, option->info.clip.y,
  71.            option->info.clip.w, option->info.clip.h, verbose);
  72.     break;
  73.  
  74.   case COLORS:
  75.     retimage= reduce(image, option->info.colors, verbose);
  76.     break;
  77.  
  78.   case DITHER:
  79.     retimage= dither(image, verbose);
  80.     break;
  81.  
  82.   case FOREGROUND:
  83.     if (image->depth > 1)
  84.       break;
  85.     XParseColor(Disp, DefaultColormap(Disp, Scrn), option->info.foreground,
  86.         &xcolor);
  87.     image->rgb.red[1]= xcolor.red;
  88.     image->rgb.green[1]= xcolor.green;
  89.     image->rgb.blue[1]= xcolor.blue;
  90.     break;
  91.  
  92.   case GAMMA:
  93.     gammacorrect(image, option->info.gamma, verbose);
  94.     break;
  95.  
  96.   case GRAY:
  97.     if (BITMAPP(image))
  98.       retimage= undither(image, verbose);
  99.     else
  100.       gray(image, verbose);
  101.     break;
  102.  
  103.   case HALFTONE:
  104.     retimage= halftone(image, verbose);
  105.     break;
  106.  
  107.   case NORMALIZE:
  108.     retimage= normalize(image, verbose);
  109.     break;
  110.  
  111.   case ROTATE:
  112.     retimage= rotate(image, option->info.rotate, verbose);
  113.     break;
  114.  
  115.   case SMOOTH:
  116.     retimage= smooth(image, 1, verbose);
  117.     break;
  118.  
  119.   case TITLE:
  120.     if (image->title)
  121.       lfree((byte *)image->title);
  122.     image->title= dupString(option->info.title);
  123.     break;
  124.  
  125.   case ZOOM:
  126.     retimage= zoom(image, option->info.zoom.x, option->info.zoom.y, verbose);
  127.     break;
  128.   }
  129.   return(retimage);
  130. }
  131.  
  132. /* process a list of options on an image
  133.  */
  134. static Image *processImage(image, global_options, image_options)
  135.      Image *image;
  136.      OptionSet *global_options;
  137.      OptionSet *image_options;
  138. { Option       *opt;
  139.   Image        *tmpimage;
  140.   unsigned int  verbose;
  141.  
  142.   verbose= (getOption(global_options, VERBOSE) != NULL);
  143.  
  144.   /* go through the global options and process them
  145.    */
  146.   for (opt= global_options->options; opt; opt= opt->next) {
  147.  
  148.     /* if option already exists locally for this image, ignore it
  149.      */
  150.     if (getOption(image_options, opt->type))
  151.       continue;
  152.     tmpimage= doProcessOnImage(image, opt, verbose);
  153.     if (tmpimage != image) {
  154.       freeImage(image);
  155.       image= tmpimage;
  156.     }
  157.   }
  158.  
  159.   /* go through local options
  160.    */
  161.   for (opt= image_options->options; opt; opt= opt->next) {
  162.     tmpimage= doProcessOnImage(image, opt, verbose);
  163.     if (tmpimage != image) {
  164.       freeImage(image);
  165.       image= tmpimage;
  166.     }
  167.   }
  168.   return(image);
  169. }
  170.  
  171. /* the real thing
  172.  */
  173.  
  174. main(argc, argv)
  175.      int argc;
  176.      char *argv[];
  177. { Option *opt;
  178.   char         *dname;
  179.   Image        *dispimage;      /* image that will be sent to the display */
  180.   Image        *newimage;       /* new image we're loading */
  181.   Image        *tmpimage;
  182.   Display      *disp;           /* display we're sending to */
  183.   int           scrn;           /* screen we're sending to */
  184.   char         *border;         /* name of border color */
  185.   XColor        xcolor;         /* color for border option */
  186.   OptionSet    *global_options; /* set of global options */
  187.   OptionSet    *image_options;  /* set of image options */
  188.   OptionSet    *optset, *tmpset;
  189.   Option       *dump;
  190.   unsigned int  fullscreen;
  191.   unsigned int  onroot;
  192.   unsigned int  verbose;
  193.   unsigned int  winwidth, winheight; /* geometry of image */
  194.   unsigned int  shrinktofit;
  195.  
  196.   /* set up internal error handlers
  197.    */
  198.  
  199.   signal(SIGSEGV, internalError);
  200.   signal(SIGBUS, internalError);
  201.   signal(SIGFPE, internalError);
  202.   signal(SIGILL, internalError);
  203. #if defined(_AIX) && defined(_IBMR2)
  204.   /* the RS/6000 (AIX 3.1) has a new signal, SIGDANGER, which you get
  205.    * when memory is exhausted.  since malloc() can overcommit, it's a good
  206.    * idea to trap this one.
  207.    */
  208.   signal(SIGDANGER, memoryExhausted);
  209. #endif
  210.  
  211.   ProgramName= argv[0];
  212.   if (argc < 2)
  213.     usage();
  214.  
  215.   /* defaults and other initial settings.  some of these depend on what
  216.    * our name was when invoked.
  217.    */
  218.  
  219.   loadPathsAndExts();
  220.  
  221.   processOptions(argc, argv, &global_options, &image_options);
  222.  
  223.   verbose= (getOption(global_options, VERBOSE) != NULL);
  224.  
  225.   /* if no images are specified and we're not setting the default root,
  226.    * this invocation is a no-op
  227.    */
  228.   if ((image_options->next == NULL) &&
  229.       (getOption(image_options, NAME) == NULL) &&
  230.       (getOption(global_options, DEFAULT) == NULL)) {
  231.     fprintf(stderr, "%s: No images were specified.\n", argv[0]);
  232.     usageHelp();
  233.     /* NOTREACHED */
  234.   }
  235.  
  236.   if (getOption(global_options, IDENTIFY)) {
  237.     for (optset= image_options; optset; optset= optset->next) {
  238.       if (opt= getOption(optset, NAME))
  239.     identifyImage(opt->info.name);
  240.     }
  241.     exit(0);
  242.   }
  243.  
  244.   /* start talking to the display
  245.    */
  246.  
  247.   opt= getOption(global_options, DISPLAY);
  248.   dname= (opt ? opt->info.display : NULL);
  249.   if (! (Disp= disp= XOpenDisplay(dname))) {
  250.     printf("%s: Cannot open display\n", XDisplayName(dname));
  251.     exit(1);
  252.   }
  253.   Scrn= scrn= DefaultScreen(disp);
  254.   XSetErrorHandler(errorHandler);
  255.  
  256.   /* background ourselves if the user asked us to
  257.    */
  258.  
  259. #ifndef NO_FORK
  260.   if (getOption(global_options, FORK))
  261.     switch(fork()) {
  262.     case -1:
  263.       perror("fork");
  264.       /* FALLTHRU */
  265.     case 0:
  266.       break;
  267.     default:
  268.       exit(0);
  269.     }
  270. #endif /* !NO_FORK */
  271.  
  272.   dispimage= NULL;
  273.  
  274.   onroot= (getOption(global_options, ONROOT) != NULL);
  275.   fullscreen= (getOption(global_options, FULLSCREEN) != NULL);
  276.   shrinktofit= (getOption(global_options, SHRINKTOFIT) != NULL);
  277.   if (opt= getOption(global_options, GEOMETRY)) {
  278.     winwidth= opt->info.geometry.w;
  279.     winheight= opt->info.geometry.h;
  280.   }
  281.   else {
  282.     winwidth= 0;
  283.     winheight= 0;
  284.   }
  285.  
  286.   /* find out if we're supposed to dump this silly thing
  287.    */
  288.   dump= getOption(global_options, DUMP);
  289.  
  290.   if (!getOption(global_options, DEFAULT) &&
  291.       (dump || onroot) && (winwidth || winheight ||
  292.                getOption(image_options, CENTER) ||
  293.                getOption(image_options, AT) ||
  294.                fullscreen)) {
  295.     if (!winwidth)
  296.       winwidth= DisplayWidth(disp, scrn);
  297.     if (!winheight)
  298.       winheight= DisplayHeight(disp, scrn);
  299.     opt= getOption(global_options, BORDER);
  300.     border= (opt ? opt->info.border : NULL);
  301.     if (border)
  302.       XParseColor(disp, DefaultColormap(disp, scrn), border, &xcolor);
  303.     else
  304.       xcolor.red= xcolor.green= xcolor.blue = 65535;
  305.     if (DefaultDepth(disp, scrn) == 1) {
  306.       dispimage= newBitImage(winwidth, winheight);
  307.       *(dispimage->rgb.red)= xcolor.red;
  308.       *(dispimage->rgb.green)= xcolor.green;
  309.       *(dispimage->rgb.blue)= xcolor.blue;
  310.       if (xcolor.red || xcolor.blue || xcolor.green) {
  311.     *(dispimage->rgb.red + 1)= 0;
  312.     *(dispimage->rgb.green + 1)= 0;
  313.     *(dispimage->rgb.blue + 1)= 0;
  314.       }
  315.       else {
  316.     *(dispimage->rgb.red + 1)= 65535;
  317.     *(dispimage->rgb.green + 1)= 65535;
  318.     *(dispimage->rgb.blue + 1)= 65535;
  319.       }
  320.       fill(dispimage, 0, 0, winwidth, winheight, 0);
  321.     }
  322.     else {
  323.       dispimage= newTrueImage(winwidth, winheight);
  324.       dispimage->rgb.used= 1;
  325.       fill(dispimage, 0, 0, winwidth, winheight,
  326.        RGB_TO_TRUE(xcolor.red, xcolor.green, xcolor.blue));
  327.     }
  328.     dispimage->title= dupString("Root Image");
  329.   }
  330.  
  331.   /* load in each named image
  332.    */
  333.  
  334.   for (optset= image_options; optset; optset= optset->next) {
  335.   get_another_image:
  336.  
  337.     /* handle -default option.  this creates a base image using the
  338.      * default tile weave.
  339.      */
  340.     if (getOption(image_options, DEFAULT)) {
  341.       newimage= newBitImage(root_weave_width, root_weave_height);
  342.       bcopy(root_weave_bits, newimage->data,
  343.         ((root_weave_width / 8) + (root_weave_width % 8 ? 1 : 0)) *
  344.         root_weave_height);
  345.     }
  346.     else if (! (opt= getOption(optset, NAME))) {
  347.  
  348.       /* this gets post-processing accomplished for -dump and -onroot.
  349.        */
  350.       if (dispimage)
  351.     dispimage= processImage(dispimage, global_options, optset);
  352.       continue;
  353.     }
  354.     else if (! (newimage= loadImage(global_options, optset, opt->info.name, verbose)))
  355.       continue;
  356.  
  357.     /* retitle the image if we were asked to
  358.      */
  359.     if (opt= getOption(optset, TITLE)) {
  360.       if (newimage->title)
  361.     lfree((byte *)newimage->title);
  362.       newimage->title= dupString(opt->info.title);
  363.     }
  364.  
  365.     /* if this is the first image and we're putting it on the root window
  366.      * in fullscreen mode, set the zoom factors and
  367.      * location to something reasonable.
  368.      */
  369.  
  370.     if ((optset == image_options) && onroot && fullscreen &&
  371.     !getOption(optset, ZOOM) && !getOption(optset, AT) &&
  372.     !getOption(optset, CENTER)) {
  373.  
  374.       opt= newOption(ZOOM);
  375.       if ((newimage->width > DisplayWidth(disp, scrn)) ||
  376.       (newimage->height > DisplayHeight(disp, scrn))) {
  377.     opt->info.zoom.x= opt->info.zoom.y= 
  378.       (newimage->width - DisplayWidth(disp, scrn) >
  379.        newimage->height - DisplayHeight(disp, scrn) ?
  380.        (float)DisplayWidth(disp, scrn) / (float)newimage->width * 100.0 :
  381.        (float)DisplayHeight(disp, scrn) / (float)newimage->height * 100.0);
  382.       }
  383.       else {
  384.     opt->info.zoom.x= opt->info.zoom.y=
  385.       (DisplayWidth(disp, scrn) - newimage->width <
  386.        DisplayHeight(disp, scrn) - newimage->height ?
  387.        (float)DisplayWidth(disp, scrn) / (float)newimage->width * 100.0 :
  388.        (float)DisplayHeight(disp, scrn) / (float)newimage->height * 100.0);
  389.       }
  390.       addOption(optset, opt);
  391.       opt= newOption(CENTER);
  392.       addOption(optset, opt);
  393.     }
  394.  
  395.     if ((optset == image_options) && shrinktofit && !onroot &&
  396.     !getOption(optset, ZOOM)) {
  397.  
  398.       opt= newOption(ZOOM);
  399.  
  400.       opt->info.zoom.x= opt->info.zoom.y= 
  401.     (newimage->width - (DisplayWidth(disp, scrn) * 0.9) >
  402.      newimage->height - (DisplayHeight(disp, scrn) * 0.9) ?
  403.      ((float)DisplayWidth(disp, scrn) * 0.9)
  404.      / (float)newimage->width * 100.0 :
  405.      ((float)DisplayHeight(disp, scrn) * 0.9)
  406.      / (float)newimage->height * 100.0);
  407.       addOption(optset, opt);
  408.     }
  409.  
  410.     newimage= processImage(newimage, global_options, optset);
  411.  
  412.     /* handle -center
  413.      */
  414.     if (dispimage && getOption(optset, CENTER)) {
  415.       tmpimage= merge(dispimage, newimage,
  416.               (int)(dispimage->width - newimage->width) / 2,
  417.               (int)(dispimage->height - newimage->height) / 2,
  418.               verbose);
  419.       if (dispimage != tmpimage) {
  420.     freeImage(dispimage);
  421.     dispimage= tmpimage;
  422.       }
  423.     }
  424.  
  425.     /* merge onto previous image
  426.      */
  427.     else if (dispimage) {
  428.       if (! dispimage->title)
  429.     dispimage->title= dupString(newimage->title);
  430.  
  431.       /* handle -at
  432.        */
  433.       if (opt= getOption(optset, AT))
  434.     tmpimage= merge(dispimage, newimage,
  435.             opt->info.at.x, opt->info.at.y, verbose);
  436.       else
  437.     tmpimage= merge(dispimage, newimage, 0, 0, verbose);
  438.       if (dispimage != tmpimage) {
  439.     freeImage(dispimage);
  440.     dispimage= tmpimage;
  441.       }
  442.       freeImage(newimage);
  443.     }
  444.     else
  445.       dispimage= newimage;
  446.  
  447.     /* if the user asked for tiling we tile the image now
  448.      */
  449.     if (getOption(optset, TILE)) {
  450.       if (!winwidth)
  451.     winwidth= DisplayWidth(disp, scrn);
  452.       if (!winheight)
  453.     winheight= DisplayHeight(disp, scrn);
  454.       dispimage= tile(newimage, 0, 0, winwidth, winheight, verbose);
  455.     }
  456.  
  457.     /* if next image is to be merged onto this one, read it
  458.      */
  459.     if (dump || onroot || (getOption(optset->next, MERGE)))
  460.       continue;
  461.  
  462.   redisplay_in_window:
  463.     switch(imageInWindow(disp, scrn, dispimage, global_options,
  464.              optset, argc, argv, verbose)) {
  465.     case '\0': /* window got nuked by someone */
  466.       XCloseDisplay(disp);
  467.       exit(1);
  468.     case '\003':
  469.     case 'q':  /* user quit */
  470.       cleanUpWindow(disp);
  471.       XCloseDisplay(disp);
  472.       exit(0);
  473.     case ' ':
  474.     case 'n':  /* next image */
  475.       if (opt= getOption(optset->next, GOTO)) {
  476.     char *tag= opt->info.go_to;
  477.  
  478.     for (tmpset= image_options; tmpset; tmpset= tmpset->next) {
  479.       if ((opt= getOption(tmpset, NAME)) &&
  480.           !strcmp(tag, opt->info.name)) {
  481.         optset= tmpset;
  482.         freeImage(dispimage);
  483.         dispimage= NULL;
  484.         goto get_another_image; /* ick */
  485.       }
  486.     }
  487.     fprintf(stderr, "Target for -goto %s was not found\n", tag);
  488.       }
  489.       break;
  490.     case 'p':  /* previous image */
  491.       for (tmpset= image_options; tmpset && (tmpset->next != optset);
  492.        tmpset= tmpset->next)
  493.     /* EMPTY */
  494.     ;
  495.       if (!tmpset)
  496.     goto redisplay_in_window; /* ick */
  497.       optset= tmpset;
  498.       goto get_another_image; /* ick */
  499.     case '<':
  500.       if ((opt = getOption(optset,ZOOM)) == NULL) {
  501.     opt= newOption(ZOOM);
  502.     opt->info.zoom.x= opt->info.zoom.y= 50.0;
  503.     addOption(optset, opt);
  504.       } else {
  505.     opt->info.zoom.x= opt->info.zoom.x ? opt->info.zoom.x * 0.5 : 50;
  506.     opt->info.zoom.y= opt->info.zoom.y ? opt->info.zoom.y * 0.5 : 50;
  507.       }
  508.       tmpimage= dispimage;
  509.       dispimage=
  510.     zoom(dispimage, 50, 50,
  511.          (getOption(global_options, VERBOSE) != NULL));
  512.       if (tmpimage != dispimage)
  513.     free(tmpimage);
  514.       goto redisplay_in_window; /* ick */
  515.     case '>':
  516.       if ((opt = getOption(optset,ZOOM)) == NULL) {
  517.     opt= newOption(ZOOM);
  518.     opt->info.zoom.x= opt->info.zoom.y= 200.0;
  519.     addOption(optset, opt);
  520.       } else {
  521.     opt->info.zoom.x= opt->info.zoom.x ? opt->info.zoom.x * 2.0 : 200;
  522.     opt->info.zoom.y= opt->info.zoom.y ? opt->info.zoom.y * 2.0 : 200;
  523.       }
  524.       tmpimage= dispimage;
  525.       dispimage=
  526.     zoom(dispimage, 200, 200,
  527.          (getOption(global_options, VERBOSE) != NULL));
  528.       if (tmpimage != dispimage)
  529.     free(tmpimage);
  530.       goto redisplay_in_window; /* ick */
  531.     }
  532.     freeImage(dispimage);
  533.     dispimage= NULL;
  534.   }
  535.  
  536.   /* dump image into a NIFF file rather than displaying
  537.    */
  538.   if (dump && dispimage) {
  539.     for (optset= image_options; optset && optset->next; optset= optset->next)
  540.       /* EMPTY */
  541.       ;
  542.     if (opt= getOption(optset, NAME)) {
  543.       if (dispimage->title)
  544.     lfree((byte *)dispimage->title);
  545.       dispimage->title= dupString(opt->info.title);
  546.     }
  547.     dumpImage(dispimage, dump->info.dump.type, dump->info.dump.file, verbose);
  548.     freeImage(dispimage);
  549.     dispimage= NULL;
  550.     exit(0);
  551.   }
  552.  
  553.   /* display image on root
  554.    */
  555.   if (onroot && dispimage)
  556.     imageOnRoot(disp, scrn, dispimage, global_options, verbose);
  557.  
  558.   /* shut down
  559.    */
  560.   XCloseDisplay(disp);
  561.   exit(0);
  562. }
  563.