home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_11_08 / weber / display.c < prev    next >
Text File  |  1993-03-13  |  32KB  |  794 lines

  1. /***************************************************************
  2.  * file: DISPLAY.C
  3.  * purpose: display a PCX file
  4.  * contains:
  5.  *  display_file() - displays a file.
  6.  *  display_sample() -  gets a pointer to a sample of the displayed file.
  7.  * copyright: 1993 by David Weber.  All rights reserved.
  8.  *  This software can be used for any purpose as object, library or executable.
  9.  *  It cannot be sold for profit as source code.
  10.  * history:
  11.  *  02-26-93 - initial code, cobbled from various stuff
  12.  **************************************************************/
  13.  
  14. #include <stdio.h>
  15. #include <io.h>
  16. #include <fcntl.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "gui.h"
  20. #include "display.h"
  21. #include "zone.h"
  22.  
  23. /* local prototypes */
  24. static int get_pcx_header(int fh);
  25. static unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes);
  26. static unsigned int read_source_buffer(void);
  27. static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file);
  28. static int scaler(unsigned char *buffer);
  29. static void close_scaler(void);
  30. static int open_sampler(DISPLAY_BOX *file);
  31. static void get_sample(unsigned char *scaler_buffer,int ylines);
  32.  
  33. /* local data */
  34.                     /* PCX */
  35. static int src_fh;                      /* file handle of source */
  36. static unsigned int bytes_per_line;     /* byte width of image */
  37. static unsigned int lines_per_page;     /* pixel length of image */
  38. static unsigned int src_bytes;          /* byte count in buffer */
  39. static unsigned int src_size;           /* size of buffer */
  40. static unsigned char *src_buffer;       /* buffer pointer */
  41.                     /* SCALER */
  42. static unsigned char *scaler_buffer;    /* buffer for scaler operations */
  43. static int scaler_in_bytes_per_line;    /* input bytes per line */
  44. static int scaler_out_bytes_per_line;   /* output bytes per line */
  45. static int scaler_error;                /* scaler y error */
  46. static int scaler_delta;                /* scale ratio delat error */
  47. static unsigned int scaler_buffer_size; /* minimum buffer size */
  48. static int scaler_lines;                /* minimum lines in buffer */
  49. static short *scaler_offset;            /* offset from line start for scaler_mask */
  50. static unsigned short *scaler_mask;     /* bit mask of input line */
  51. static int scaler_xscale;               /* x scale value in fixed point .00 */
  52. static int scaler_yscale;               /* y scale value in fixed point .00 */
  53.                     /* DISPLAY */
  54. static unsigned char *display_buffers[MAX_DISPLAY_BUFFERS]; /* array of buffers for display */
  55. static int display_buffer_count = 0;    /* number of allocated buffers */
  56. static int display_lines_per_buffer;    /* number of lines in a buffer */
  57. static int display_bytes_per_line;      /* number of bytes in a display_buffer line */
  58. static DISPLAY_BOX display_screen_box;  /* screen info */
  59. static NUMBERED_BOX *numbered_boxes = NULL; /* numbered boxes outside of image */
  60.                     /* IMAGE SAMPLING */
  61. static int xsample,ysample,xdelta,ydelta;           /* scaled image dimensions */
  62. static int sample_line;                             /* current sample line */
  63. static unsigned char *display_sample_ptr = NULL;    /* pointer to sampled image */
  64.  
  65. /************************************************
  66.  * function: int display_file(char *filename)
  67.  *  Opens PCX file and displays same, displays error box
  68.  *  if it fails
  69.  * parameters: pointer to file name
  70.  * returns: 1 if done or 0 if failed
  71.  ************************************************/
  72. int display_file(char *filename)
  73.     {
  74.     fg_box_t box;
  75.     DISPLAY_BOX screen;
  76.     int screen_aspect_ratio;
  77.     DISPLAY_BOX file;
  78.     int file_aspect_ratio;
  79.     int xscale,yscale,i,skip_it;
  80.     unsigned char *p;
  81.  
  82.     if (display_buffer_count > 0)
  83.         {                   /* clear out previous buffers */
  84.         for (i = 0 ; i < display_buffer_count ; i++)
  85.             free(display_buffers[i]);
  86.         display_buffer_count = 0;
  87.         }
  88.     if (display_sample_ptr != NULL)
  89.         free(display_sample_ptr);
  90.     screen.x = 0;           /* size the display area on screen */
  91.     screen.y = 0;
  92.     screen.width = gui_screen_width;
  93.     screen.height = gui_screen_height - 2 * gui_char_height;
  94.     fg_make_box(box,0,0,screen.width-1,screen.height-1);    /* clear screen */
  95.     fg_msm_hidecursor();
  96.     fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  97.     fg_msm_showcursor();
  98.     if ((src_buffer = (unsigned char *) malloc(PCX_READ_BUFFER)) == NULL)
  99.         {                   /* file read buffer */
  100.         message_box("Out of memory.");
  101.         return 0;
  102.         }
  103.     if ((src_fh = open(filename,O_RDONLY | O_BINARY)) == -1)        /* open file */
  104.         {
  105.         message_box("Cannot open file.");
  106.         free(src_buffer);
  107.         return 0;
  108.         }
  109.     if (!get_pcx_header(src_fh))                    /* decode header */
  110.         {
  111.         message_box("Not a valid monochrome PCX file.");
  112.         free(src_buffer);
  113.         close(src_fh);
  114.         return 0;
  115.         }                   /* the following calculations are fixed point .00 */
  116.     screen_aspect_ratio = (int) (((long)gui_screen_width * 100L) / (long)gui_screen_height);
  117.     file.x = file.y = 0;    /* display area of file */
  118.     file.width = bytes_per_line * 8;
  119.     file.height = lines_per_page;
  120.     file_aspect_ratio = (int) (((long)file.width * 100L) / (long)file.height);
  121.     if (file.width < screen.width || file.height < screen.height)
  122.         {   /* if it has to be scaled up, it has too little info for region finding */
  123.         message_box("PCX file too small for region finding.");
  124.         free(src_buffer);
  125.         close(src_fh);
  126.         return 0;
  127.         }
  128.     if (IDEAL_SCREEN_ASPECT > file_aspect_ratio)
  129.         {   /* y major scaling */
  130.         yscale = (int) (((long)file.height * 100L) / (long)screen.height);
  131.         xscale = (int) (((long)yscale * (long)IDEAL_SCREEN_ASPECT) / (long)screen_aspect_ratio);
  132.         screen.width = (int) (((long)file.width * 100L) / (long)xscale);
  133.         screen.x = (gui_screen_width - screen.width) / 2;
  134.         }
  135.     else
  136.         {   /* x major scaling */
  137.         xscale = (int) (((long)file.width * 100L) / (long)screen.width);
  138.         yscale = (int) (((long)xscale * (long)screen_aspect_ratio) / (long)IDEAL_SCREEN_ASPECT);
  139.         screen.height = (int) (((long)file.height * 100L) / (long)yscale);
  140.         screen.y = (gui_screen_height - 2 * gui_char_height - screen.height) / 2;
  141.         }
  142.     src_bytes = src_size = 0;
  143.     if (!open_scaler(xscale,yscale,&screen,&file))      /* set up scaler */
  144.         {
  145.         free(src_buffer);
  146.         close(src_fh);
  147.         message_box("Out of memory.");
  148.         return 0;
  149.         }
  150.     display_screen_box = screen;                /* set up display parameters */
  151.     display_bytes_per_line = scaler_out_bytes_per_line;
  152.     display_screen_box.width = display_bytes_per_line * 8;
  153.     display_lines_per_buffer = DISPLAY_BUFFER_SIZE / display_bytes_per_line;
  154.     fg_make_box(box,screen.x,screen.y,screen.x+screen.width-1,screen.y+screen.height-1);
  155.     fg_msm_hidecursor();
  156.     fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box);    /* draw blank page */
  157.     fg_make_box(box,0,0,screen.width-1,0);
  158.     for (i = skip_it = 0 ; i < screen.height ; i++) /* scale file to screen */
  159.         {
  160.         if ((i % display_lines_per_buffer) == 0)
  161.             {           /* need another array */
  162.             if ((display_buffers[display_buffer_count] = (unsigned char *) malloc(DISPLAY_BUFFER_SIZE)) == NULL)
  163.                 {
  164.                 display_free();
  165.                 close_scaler();
  166.                 free(src_buffer);
  167.                 close(src_fh);
  168.                 fg_msm_showcursor();
  169.                 message_box("Out of memory.");
  170.                 return 0;
  171.                 }
  172.             p = display_buffers[display_buffer_count];
  173.             display_buffer_count++;
  174.             }
  175.         if (skip_it)
  176.             memset(p,0,scaler_out_bytes_per_line);
  177.         else if (!scaler(p))
  178.             skip_it = 1;
  179.         fg_drawmatrix(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,screen.x,screen.y+screen.height-i-1,(char *)p,box,fg.displaybox);
  180.         p += scaler_out_bytes_per_line;
  181.         }
  182.     fg_msm_showcursor();
  183.     fg_flush();
  184.     close_scaler();
  185.     free(src_buffer);
  186.     close(src_fh);
  187.     return 1;
  188.     }
  189.  
  190.  
  191. /************************************************
  192.  * function: void display_free(void)
  193.  *      free display resources
  194.  * parameters: none
  195.  * returns: nothing
  196.  ************************************************/
  197. void display_free(void)
  198.     {
  199.     int i;
  200.  
  201.     if (display_buffer_count > 0)
  202.         {                   /* clear out previous buffers */
  203.         for (i = 0 ; i < display_buffer_count ; i++)
  204.             free(display_buffers[i]);
  205.         display_buffer_count = 0;
  206.         }
  207.     if (display_sample_ptr != NULL) /* clear sample buffer */
  208.         free(display_sample_ptr);
  209.     }
  210.  
  211.  
  212. /************************************************
  213.  * function: unsigned char *display_sample(int *samplex,int *sampley,int *dx,int *dy)
  214.  *  gets info on image sampled while scaling
  215.  * parameters: pointers to x/y samples and x/y extents
  216.  * returns: pointer to image base or NULL if none
  217.  ************************************************/
  218. unsigned char *display_sample(int *samplex,int *sampley,int *dx,int *dy)
  219.     {
  220.     *samplex = xsample;
  221.     *sampley = ysample;
  222.     *dx = xdelta;
  223.     *dy = ydelta;
  224.     return display_sample_ptr;
  225.     }
  226.  
  227.  
  228. /************************************************
  229.  * function: void display_numbered_box_close(void)
  230.  *  clean up resources for numbered boxes
  231.  * parameters: none
  232.  * returns: nothing
  233.  ************************************************/
  234. void display_numbered_box_close(void)
  235.     {
  236.     NUMBERED_BOX *p,*q;
  237.  
  238.     for (p = numbered_boxes ; p != NULL ; p = q)
  239.         {
  240.         q = p->next;
  241.         free(p);
  242.         }
  243.     numbered_boxes = NULL;
  244.     }
  245.  
  246.  
  247. /************************************************
  248.  * function: void display_numbered_box(int x1,int y1,int x2,int y2,int num)
  249.  *  draws a numbered box around a region, coordinates are relative to file
  250.  * parameters: x/y corners of the box and number of box
  251.  * returns: nothing
  252.  ************************************************/
  253. void display_numbered_box(int x1,int y1,int x2,int y2,int num)
  254.     {
  255.     fg_box_t box;
  256.     fg_line_t line;
  257.     char str[16];
  258.     int len,x,y,wide_screen,num_width,num_height,retry,pass;
  259.     NUMBERED_BOX *p,*q;
  260.  
  261.     /* scale to screen */
  262.     x1 = (int) (((long)x1 * 100L + 50L) / (long) scaler_xscale);
  263.     y1 = (int) (((long)y1 * 100L + 50L) / (long) scaler_yscale);
  264.     x2 = (int) (((long)x2 * 100L + 50L) / (long) scaler_xscale);
  265.     y2 = (int) (((long)y2 * 100L + 50L) / (long) scaler_yscale);
  266.     /* outline box */
  267.     fg_msm_hidecursor();
  268.     fg_make_box(box,display_screen_box.x+x1,
  269.                 display_screen_box.y+display_screen_box.height-y2-1,
  270.                 display_screen_box.x+x2,
  271.                 display_screen_box.y+display_screen_box.height-y1-1);
  272.     if (fg.nsimulcolor < 16)
  273.         fg_drawbox(FG_BLACK,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,box,fg.displaybox);
  274.     else
  275.         fg_drawbox(FG_LIGHT_RED,FG_MODE_SET,~0,FG_LINE_SOLID,box,fg.displaybox);
  276.     sprintf(str,"%d",num);
  277.     len = strlen(str);
  278.     num_width = len * gui_char_width;
  279.     num_height = gui_char_height;
  280.     if (x2-x1+1 >= num_width && y2-y1+1 >= (2*num_height)/3)
  281.         {   /* put number in upper left of box */
  282.         fg_make_box(box,display_screen_box.x+x1,
  283.                     display_screen_box.y+display_screen_box.height-y1-num_height,
  284.                     display_screen_box.x+x1+num_width-1,
  285.                     display_screen_box.y+display_screen_box.height-y1-1);
  286.         fg_boxclip(fg.displaybox,box,box);
  287.         if (fg.nsimulcolor < 16)
  288.             {
  289.             fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  290.             fg_puts(FG_WHITE,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x+x1,
  291.                         display_screen_box.y+display_screen_box.height-y1-num_height,str,box);
  292.             }
  293.         else
  294.             {
  295.             fg_fillbox(FG_RED,FG_MODE_SET,~0,box);
  296.             fg_puts(FG_YELLOW,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x+x1,
  297.                         display_screen_box.y+display_screen_box.height-y1-num_height,str,box);
  298.             }
  299.         }
  300.     else
  301.         {   /* draw line between number and box */
  302.         if (display_screen_box.x == 0)
  303.             {   /* wide screen */
  304.             wide_screen = 1;
  305.             x = x1;
  306.             if (y1 < display_screen_box.height/2)   /* above */
  307.                 y = display_screen_box.y + display_screen_box.height + gui_char_height;
  308.             else                                    /* underneath */
  309.                 y = display_screen_box.y - 2 * gui_char_height;
  310.             }
  311.         else
  312.             {   /* tall screen */
  313.             wide_screen = 0;
  314.             y = display_screen_box.height-y1-1-gui_char_height;
  315.             if (x1 < display_screen_box.width/2)    /* left */
  316.                 x = display_screen_box.x - 4 * gui_char_width;
  317.             else                                    /* right */
  318.                 x = display_screen_box.x + display_screen_box.width + 2 * gui_char_width;
  319.             }
  320.         if (x < 0)  /* size to screen */
  321.             x = 0;
  322.         if (x > gui_screen_width-2*gui_char_width)
  323.             x = gui_screen_width-2*gui_char_width;
  324.         if (y < 0)
  325.             y = 0;
  326.         if (y > gui_screen_height-3*gui_char_height)
  327.             y = gui_screen_height-3*gui_char_height;
  328.         for (p=numbered_boxes, pass=retry=0 ; pass < 64 ; p = p->next)
  329.             {               /* resolve overlaps */
  330.             if (p->next == NULL)
  331.                 q = p;
  332.             if (p == NULL)
  333.                 {
  334.                 if (retry == 0)
  335.                     break;
  336.                 retry = 0;
  337.                 p = numbered_boxes;
  338.                 }
  339.             if (abs(p->x - x) < num_width && abs(p->y - y) < num_height)
  340.                 {           /* have an overlap */
  341.                 if (wide_screen == 1)
  342.                     {
  343.                     x = p->x + p->width + gui_char_width;   /* move right */
  344.                     if (x > gui_screen_width-num_width)
  345.                         {                       /* no more room */
  346.                         if (pass == 0)
  347.                             y = p->x - num_width - gui_char_width;
  348.                         else
  349.                             x = display_screen_box.width/2;
  350.                         }
  351.                     }
  352.                 else
  353.                     {
  354.                     y = p->y - num_height - 1;              /* move down */
  355.                     if (y < 0)
  356.                         {                       /* no more room */
  357.                         if (pass == 0)
  358.                             y = p->y + num_height + 1;
  359.                         else
  360.                             y = display_screen_box.height/2;
  361.                         }
  362.                     }
  363.                 retry = 1;
  364.                 pass++;
  365.                 }
  366.             }
  367.         p = (NUMBERED_BOX *) malloc(sizeof(NUMBERED_BOX));
  368.         if (p != NULL)
  369.             {
  370.             if (numbered_boxes == NULL)
  371.                 numbered_boxes = p;
  372.             else
  373.                 q->next = p;
  374.             p->next = NULL;
  375.             p->x = x;
  376.             p->y = y;
  377.             p->width = num_width;
  378.             p->height = num_height;
  379.             fg_make_line(line,p->x+p->width/2,p->y+p->height/2,
  380.                     display_screen_box.x+x1+(x2-x1)/2,
  381.                     display_screen_box.y+display_screen_box.height-y1-1-(y2-y1)/2);
  382.             fg_make_box(box,p->x,p->y,p->x+p->width-1,p->y+p->height-1);
  383.             fg_boxclip(fg.displaybox,box,box);
  384.             if (fg.nsimulcolor < 16)
  385.                 {
  386.                 fg_drawline(FG_BLACK,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
  387.                 line[FG_X1]--;
  388.                 line[FG_X2]--;
  389.                 line[FG_Y1]++;
  390.                 line[FG_Y2]++;
  391.                 fg_drawline(FG_WHITE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
  392.                 fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box);
  393.                 fg_puts(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,p->x,p->y,str,box);
  394.                 }
  395.             else
  396.                 {
  397.                 fg_drawline(FG_BLUE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
  398.                 line[FG_X1]--;
  399.                 line[FG_X2]--;
  400.                 line[FG_Y1]++;
  401.                 line[FG_Y2]++;
  402.                 fg_drawline(FG_LIGHT_WHITE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
  403.                 fg_fillbox(FG_RED,FG_MODE_SET,~0,box);
  404.                 fg_puts(FG_YELLOW,FG_MODE_SET,~0,FG_ROT0,p->x,p->y,str,box);
  405.                 }
  406.             }
  407.         }
  408.     fg_msm_showcursor();
  409.     fg_flush();
  410.     }
  411.  
  412.  
  413. /************************************************
  414.  * function: int display_redraw(void)
  415.  *      redraws image
  416.  * parameters: none
  417.  * returns: 1 if redrawn, 0 if nothing to draw
  418.  ************************************************/
  419. int display_redraw(void)
  420.     {
  421.     fg_box_t box;
  422.     int top,i,j,lines;
  423.  
  424.     if (display_buffer_count == 0)
  425.         return 0;
  426.     top = gui_screen_height - 2 * gui_char_height;
  427.     fg_msm_hidecursor();
  428.     if (display_screen_box.x == 0)
  429.         {   /* clear above and below */
  430.         fg_make_box(box,0,0,gui_screen_width-1,display_screen_box.y-1);
  431.         fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  432.         fg_make_box(box,0,display_screen_box.y+display_screen_box.height-1,
  433.                     gui_screen_width-1,top);
  434.         fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  435.         }
  436.     else
  437.         {
  438.         fg_make_box(box,0,0,display_screen_box.x-1,top);
  439.         fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  440.         fg_make_box(box,display_screen_box.x+display_screen_box.width,0,
  441.                     gui_screen_width-1,top);
  442.         fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
  443.         }
  444.     fg_make_box(box,display_screen_box.x,display_screen_box.y,
  445.             display_screen_box.x+display_screen_box.width-1,
  446.             display_screen_box.y+display_screen_box.height-1);
  447.     fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box);
  448.     for (i=j=0 ; i < display_buffer_count ; i++, j+=display_lines_per_buffer)
  449.         {
  450.         if (j+display_lines_per_buffer > display_screen_box.height)
  451.             lines = display_screen_box.height - j;
  452.         else
  453.             lines = display_lines_per_buffer;
  454.         fg_make_box(box,0,0,display_screen_box.width-1,lines-1);
  455.         fg_drawmatrix(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x,
  456.             display_screen_box.y+display_screen_box.height-j-lines,
  457.             (char *)display_buffers[i],box,fg.displaybox);
  458.         }
  459.     fg_msm_showcursor();
  460.     fg_flush();
  461.     return 1;
  462.     }
  463.  
  464.  
  465. /**************** LOCAL FUNCTIONS ****************/
  466.  
  467. /************************************************
  468.  * function: static unsigned int read_source_buffer(void)
  469.  * parameters: none
  470.  * returns: (unsigned int) -1 if EOF or failure, else returns amount read
  471.  ************************************************/
  472. static unsigned int read_source_buffer(void)
  473.     {
  474.     src_size = read(src_fh,src_buffer,PCX_READ_BUFFER);
  475.     src_bytes = 0;
  476.     if (src_size <= 0)
  477.         src_size = (unsigned int) -1;
  478.     return src_size;
  479.     }
  480.  
  481.  
  482. /* pcx structure and defines */
  483.  
  484. #define PCX_HEADER_SIZE 128
  485. #define PCX_HEADER_USED 72
  486. #pragma ZTC align 1
  487. typedef struct
  488.     {
  489.             /* constants */
  490.     unsigned char   manuf;          /* always 10 decimal */
  491.     unsigned char   hardvers;       /* version */
  492.     unsigned char   pcxencodmode;   /* 1 if run length encoding */
  493.             /* calculated */
  494.     unsigned char   bitsppix;
  495.     unsigned short  x1;
  496.     unsigned short  y1;
  497.     unsigned short  x2;
  498.     unsigned short  y2;
  499.     unsigned short  hres;           /* card horizontal res. */
  500.     unsigned short  vres;           /* card vertical res. */
  501.     unsigned char   clrpa[16][3];   /* palette info */
  502.     unsigned char   vmode;          /* ignored, should be 0 */
  503.     unsigned char   nplanes;        /* number or planes */
  504.     unsigned short  bplin;          /* bytes per line */
  505.     unsigned short  page_start;
  506.     unsigned short  page_length;    /* page length in pixels */
  507.     unsigned char   reserved[PCX_HEADER_SIZE-PCX_HEADER_USED];
  508.     } PCX_HEADER;
  509. #pragma ZTC align
  510.  
  511. #define MAX_PCX_ENC_LEN (63)        /* maximum pcx run length */
  512. #define PCX_MANUFACTURER 10         /* manufacturer's code */
  513. #define PCX_RUN_LENGTH 1            /* encoding type */
  514. #define PCX_8_BITS_PER_PIX 1        /* code for 8 bits per pixel */
  515. #define DCX_ID 987654321L           /* dcx id code */
  516.  
  517. /************************************************
  518.  * function: int get_pcx_header(int fh)
  519.  *  read pcx header
  520.  * parameters: fh = file handle
  521.  * returns: 1 if success or 0 if error
  522.  ************************************************/
  523. static int get_pcx_header(int fh)
  524.     {
  525.     PCX_HEADER header;
  526.     long *l,src_offset;
  527.  
  528.     if ((src_offset = lseek(fh,0L,SEEK_CUR)) == -1)
  529.         return 0;
  530.     if (read(fh,(void *) &header,sizeof(header)) != sizeof(header))
  531.         return 0;
  532.     l = (long *) &header;
  533.     if (*l == DCX_ID)
  534.         {
  535.         if (lseek(fh,*(++l)+src_offset,SEEK_SET) == -1)
  536.             return 0;
  537.         if (read(fh,(void *) &header,sizeof(header)) != sizeof(header))
  538.             return 0;
  539.         }
  540.     if (header.manuf!=PCX_MANUFACTURER || header.pcxencodmode!=PCX_RUN_LENGTH ||
  541.         header.bitsppix!=PCX_8_BITS_PER_PIX || header.nplanes != 1 ||
  542.         header.x1>header.x2 || header.y1>header.y2)
  543.         {
  544.         return 0;
  545.         }
  546.     bytes_per_line = header.bplin;
  547.     lines_per_page = header.page_length;
  548.     return 1;
  549.     }
  550.  
  551.  
  552. /* macro for accessing buffer */
  553. #define bget() \
  554.     ((src_bytes < src_size) ? *(src_buffer+(src_bytes++)) : \
  555.         ((read_source_buffer() == (unsigned int) -1) ? ((unsigned int) -1) : \
  556.         (*(src_buffer+(src_bytes++)))))
  557. /************************************************
  558.  * function: unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
  559.  * parameters: buffer to read lines into and the number of bytes to read.
  560.  * returns: size put into buffer if OK or -1 if failed or EOF
  561.  ************************************************/
  562. static unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
  563.     {
  564.     unsigned int count,byt,cnt;
  565.  
  566.     count = 0;
  567.     while (count < number_of_bytes)
  568.         {
  569.         if((byt=bget()) == (unsigned int) -1)
  570.             return count;
  571.         if((byt&0xc0) == 0xc0)
  572.             {
  573.             cnt = 0x3f & byt;
  574.             if((byt=bget()) == (unsigned int) -1)
  575.                 return (unsigned int) -1;
  576.             memset(buffer+count,(~byt)&0xff,cnt);
  577.             }
  578.         else
  579.             {
  580.             cnt = 1;
  581.             *(buffer+count) = (~byt)&0xff;
  582.             }
  583.         count += cnt;
  584.         }
  585.     return count;
  586.     }
  587.  
  588.  
  589. /************************************************
  590.  * function: static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file)
  591.  *  allocate scaler resources and preset scale values
  592.  * parameters: scale factors in x & y, fixed point .00, screen and file sizes
  593.  * returns: 1 if OK or 0 if failed cuz no memory
  594.  ************************************************/
  595. static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file)
  596.     {
  597.     unsigned int buffer_size,i;
  598.     short pixel;
  599.     unsigned short bit_pattern;
  600.  
  601.     if (!open_sampler(file))            /* set up sampler */
  602.         return 0;
  603.     scaler_lines = yscale/100;          /* set up scale values */
  604.     scaler_delta = yscale % 100;
  605.     scaler_error = scaler_delta;
  606.     scaler_in_bytes_per_line = (file->width + 7) / 8;
  607.     scaler_out_bytes_per_line = (screen->width + 7) / 8;
  608.     scaler_buffer_size = scaler_in_bytes_per_line * scaler_lines;
  609.     buffer_size = scaler_buffer_size + scaler_in_bytes_per_line;
  610.     if ((scaler_buffer = (unsigned char *) malloc(buffer_size)) == NULL)
  611.         return 0;                       /* allocate line buffer */
  612.     buffer_size = scaler_out_bytes_per_line * 8 * sizeof(short *);
  613.     if ((scaler_offset = (short *) malloc(buffer_size)) == NULL)
  614.         {                               /* allocate offset buffer */
  615.         free(scaler_buffer);
  616.         return 0;
  617.         }
  618.     buffer_size = scaler_out_bytes_per_line * 8 * sizeof(short);
  619.     if ((scaler_mask = (unsigned short *) malloc(buffer_size)) == NULL)
  620.         {                               /* allocate mask buffer */
  621.         free(scaler_buffer);
  622.         free(scaler_offset);
  623.         return 0;
  624.         }
  625.     scaler_xscale = xscale;
  626.     scaler_yscale = yscale;
  627.     if (xscale < 1650)                  /* pattern of n bits in a word */
  628.         bit_pattern = 0xffff << (16 - (xscale+50)/100);
  629.     else
  630.         bit_pattern = 0xffff;
  631.     if (bit_pattern == 0)
  632.         bit_pattern = 0x8000;
  633.     for (i = 0 ; i < scaler_out_bytes_per_line * 8 ; i++)
  634.         {                               /* set up offsets and masks */
  635.         pixel = (short)(((long)i*(long)xscale)/100L);
  636.         scaler_offset[i] = pixel/8;
  637.         scaler_mask[i] = bit_pattern >> (pixel-(scaler_offset[i])*8);
  638.         scaler_mask[i] = (scaler_mask[i]>>8) | (scaler_mask[i]<<8); /* intel byte order */
  639.         }
  640.     return 1;
  641.     }
  642.  
  643.  
  644. /************************************************
  645.  * function: static int scaler(unsigned char *buffer)
  646.  *  scales scan lines using ratios from open_scaler()
  647.  * parameters: pointer to buffer for scaled line
  648.  * returns: 1 if OK or 0 if all done scaling
  649.  ************************************************/
  650. static int scaler(unsigned char *buffer)
  651.     {
  652.     unsigned int buffer_size,read_size,x,y,cutoff,accum,ylines;
  653.     int retval;
  654.     unsigned short bit_pattern;
  655.     unsigned char *p;
  656.     static unsigned char bit_mask[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
  657.     static unsigned char bit_count[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
  658.                                         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  659.                                         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  660.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  661.                                         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  662.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  663.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  664.                                         3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  665.                                         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  666.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  667.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  668.                                         3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  669.                                         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  670.                                         3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  671.                                         3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  672.                                         4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
  673.  
  674.     retval = 1;
  675.     if (scaler_error >= 50)                         /* (n+1) y lines */
  676.         {
  677.         buffer_size = scaler_buffer_size + scaler_in_bytes_per_line;
  678.         ylines = scaler_lines + 1;
  679.         scaler_error -= (100-scaler_delta);
  680.         }
  681.     else                                            /* (n) y lines */
  682.         {
  683.         buffer_size = scaler_buffer_size;
  684.         ylines = scaler_lines;
  685.         scaler_error += scaler_delta;
  686.         }
  687.     memset(buffer,0,scaler_out_bytes_per_line);     /* white out line */
  688.     if ((read_size = read_pcx(scaler_buffer,buffer_size)) != buffer_size)
  689.         {                                           /* partial read */
  690.         memset(scaler_buffer+read_size,0,buffer_size-read_size);    /* white out remaining */
  691.         retval = 0;
  692.         }
  693.     get_sample(scaler_buffer,ylines);               /* get a sample */
  694. #if I_LOVE_BLACK
  695.     if (scaler_xscale >= 1650)  /* how many bits in accum are significant? */
  696.         cutoff = (ylines * 16) / 3;
  697.     else
  698.         cutoff = (((scaler_xscale+50)*ylines)/3)/100;
  699. #else
  700.     if (scaler_xscale >= 1650)  /* how many bits in accum are significant? */
  701.         cutoff = (ylines * 16) / 2;
  702.     else
  703.         cutoff = (((scaler_xscale+50)*ylines)/2)/100;
  704. #endif
  705.     if (cutoff == 0)
  706.         cutoff = 1;
  707.     for (x = 0 ; x < (scaler_out_bytes_per_line << 3) ; x++)
  708.         {                                           /* for each output bit */
  709.         for (y = accum = 0, p = scaler_buffer ; y < ylines ; y++, p+=scaler_in_bytes_per_line)
  710.             {                                       /* for each y line in the set */
  711.             bit_pattern = *((unsigned short *)(p + scaler_offset[x])) & scaler_mask[x];
  712.             accum += (bit_count[bit_pattern>>8] + bit_count[bit_pattern&0x00ff]);
  713.             }
  714.         if (accum >= cutoff)                        /* if significant, mask it in */
  715.             buffer[x>>3] |= bit_mask[x&7];
  716.         }
  717.     return retval;
  718.     }
  719.  
  720.  
  721. /************************************************
  722.  * function: static void close_scaler(void)
  723.  *  clean up scaler resources
  724.  * parameters: none
  725.  * returns: none
  726.  ************************************************/
  727. static void close_scaler(void)
  728.     {
  729.     free(scaler_buffer);
  730.     free(scaler_offset);
  731.     free(scaler_mask);
  732.     }
  733.  
  734.  
  735. /************************************************
  736.  * function: static int open_sampler(DISPLAY_BOX *file)
  737.  * parameters: pointer to file extent struct
  738.  * returns: 1 if OK or 0 if failed, non memory
  739.  ************************************************/
  740. static int open_sampler(DISPLAY_BOX *file)
  741.     {
  742.     xsample = SAMPLE_200_X;         /* set sample sizes */
  743.     ysample = SAMPLE_200_Y;
  744.     xdelta = file->width / xsample; /* extent of sample */
  745.     ydelta = file->height / ysample;
  746.     while (((long)xdelta * (long)ydelta) > MAX_MALLOC)
  747.         {           /* adjust sampling to fit memory restrictions */
  748.         xsample++;
  749.         ysample++;
  750.         xdelta = file->width / xsample;
  751.         ydelta = file->height / ysample;
  752.         }
  753.                     /* allocate sample buffer */
  754.     if ((display_sample_ptr = malloc(xdelta * ydelta)) == NULL)
  755.         return 0;
  756.     memset(display_sample_ptr,WHITE,xdelta * ydelta);   /* set to white */
  757.     sample_line = 0;
  758.     return 1;
  759.     }
  760.  
  761.  
  762. /************************************************
  763.  * function: static void get_sample(unsigned char *scaler_buffer,int ylines)
  764.  *  sample the buffer
  765.  * parameters: pointer to buffer full of raw image, number of scanlines in image
  766.  * returns: nothing
  767.  ************************************************/
  768. static void get_sample(unsigned char *buffer,int ylines)
  769.     {
  770.     static unsigned char bit_mask[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
  771.     unsigned char *line_ptr,*sample_ptr;
  772.     unsigned int x,y;
  773.  
  774.     for (y=0, line_ptr=buffer ; y < ylines ; y++, sample_line++, line_ptr+=scaler_in_bytes_per_line)
  775.         {
  776.         if ((sample_line % (ysample/2)) == 0)       /* right line for scaling? */
  777.             {
  778.             sample_ptr = display_sample_ptr + ((sample_line/ysample) * xdelta);
  779.             if (xsample >= 8)
  780.                 {                                   /* byte sampling */
  781.                 for (x = 0 ; x < xdelta*xsample ; x += xsample, sample_ptr++)
  782.                     if (*(line_ptr+(x>>3)))
  783.                         *sample_ptr = BLACK;    /* if byte has black, set sample */
  784.                 }
  785.             else
  786.                 {                                   /* bit sampling */
  787.                 for (x = 0 ; x < xdelta*xsample ; x += xsample, sample_ptr++)
  788.                     if (*(line_ptr+(x>>3)) & bit_mask[x&7])
  789.                         *sample_ptr = BLACK;        /* if bit is black, set sample */
  790.                 }
  791.             }
  792.         }
  793.     }
  794.