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 >
Wrap
Text File
|
1993-03-13
|
32KB
|
794 lines
/***************************************************************
* file: DISPLAY.C
* purpose: display a PCX file
* contains:
* display_file() - displays a file.
* display_sample() - gets a pointer to a sample of the displayed file.
* copyright: 1993 by David Weber. All rights reserved.
* This software can be used for any purpose as object, library or executable.
* It cannot be sold for profit as source code.
* history:
* 02-26-93 - initial code, cobbled from various stuff
**************************************************************/
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "gui.h"
#include "display.h"
#include "zone.h"
/* local prototypes */
static int get_pcx_header(int fh);
static unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes);
static unsigned int read_source_buffer(void);
static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file);
static int scaler(unsigned char *buffer);
static void close_scaler(void);
static int open_sampler(DISPLAY_BOX *file);
static void get_sample(unsigned char *scaler_buffer,int ylines);
/* local data */
/* PCX */
static int src_fh; /* file handle of source */
static unsigned int bytes_per_line; /* byte width of image */
static unsigned int lines_per_page; /* pixel length of image */
static unsigned int src_bytes; /* byte count in buffer */
static unsigned int src_size; /* size of buffer */
static unsigned char *src_buffer; /* buffer pointer */
/* SCALER */
static unsigned char *scaler_buffer; /* buffer for scaler operations */
static int scaler_in_bytes_per_line; /* input bytes per line */
static int scaler_out_bytes_per_line; /* output bytes per line */
static int scaler_error; /* scaler y error */
static int scaler_delta; /* scale ratio delat error */
static unsigned int scaler_buffer_size; /* minimum buffer size */
static int scaler_lines; /* minimum lines in buffer */
static short *scaler_offset; /* offset from line start for scaler_mask */
static unsigned short *scaler_mask; /* bit mask of input line */
static int scaler_xscale; /* x scale value in fixed point .00 */
static int scaler_yscale; /* y scale value in fixed point .00 */
/* DISPLAY */
static unsigned char *display_buffers[MAX_DISPLAY_BUFFERS]; /* array of buffers for display */
static int display_buffer_count = 0; /* number of allocated buffers */
static int display_lines_per_buffer; /* number of lines in a buffer */
static int display_bytes_per_line; /* number of bytes in a display_buffer line */
static DISPLAY_BOX display_screen_box; /* screen info */
static NUMBERED_BOX *numbered_boxes = NULL; /* numbered boxes outside of image */
/* IMAGE SAMPLING */
static int xsample,ysample,xdelta,ydelta; /* scaled image dimensions */
static int sample_line; /* current sample line */
static unsigned char *display_sample_ptr = NULL; /* pointer to sampled image */
/************************************************
* function: int display_file(char *filename)
* Opens PCX file and displays same, displays error box
* if it fails
* parameters: pointer to file name
* returns: 1 if done or 0 if failed
************************************************/
int display_file(char *filename)
{
fg_box_t box;
DISPLAY_BOX screen;
int screen_aspect_ratio;
DISPLAY_BOX file;
int file_aspect_ratio;
int xscale,yscale,i,skip_it;
unsigned char *p;
if (display_buffer_count > 0)
{ /* clear out previous buffers */
for (i = 0 ; i < display_buffer_count ; i++)
free(display_buffers[i]);
display_buffer_count = 0;
}
if (display_sample_ptr != NULL)
free(display_sample_ptr);
screen.x = 0; /* size the display area on screen */
screen.y = 0;
screen.width = gui_screen_width;
screen.height = gui_screen_height - 2 * gui_char_height;
fg_make_box(box,0,0,screen.width-1,screen.height-1); /* clear screen */
fg_msm_hidecursor();
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
fg_msm_showcursor();
if ((src_buffer = (unsigned char *) malloc(PCX_READ_BUFFER)) == NULL)
{ /* file read buffer */
message_box("Out of memory.");
return 0;
}
if ((src_fh = open(filename,O_RDONLY | O_BINARY)) == -1) /* open file */
{
message_box("Cannot open file.");
free(src_buffer);
return 0;
}
if (!get_pcx_header(src_fh)) /* decode header */
{
message_box("Not a valid monochrome PCX file.");
free(src_buffer);
close(src_fh);
return 0;
} /* the following calculations are fixed point .00 */
screen_aspect_ratio = (int) (((long)gui_screen_width * 100L) / (long)gui_screen_height);
file.x = file.y = 0; /* display area of file */
file.width = bytes_per_line * 8;
file.height = lines_per_page;
file_aspect_ratio = (int) (((long)file.width * 100L) / (long)file.height);
if (file.width < screen.width || file.height < screen.height)
{ /* if it has to be scaled up, it has too little info for region finding */
message_box("PCX file too small for region finding.");
free(src_buffer);
close(src_fh);
return 0;
}
if (IDEAL_SCREEN_ASPECT > file_aspect_ratio)
{ /* y major scaling */
yscale = (int) (((long)file.height * 100L) / (long)screen.height);
xscale = (int) (((long)yscale * (long)IDEAL_SCREEN_ASPECT) / (long)screen_aspect_ratio);
screen.width = (int) (((long)file.width * 100L) / (long)xscale);
screen.x = (gui_screen_width - screen.width) / 2;
}
else
{ /* x major scaling */
xscale = (int) (((long)file.width * 100L) / (long)screen.width);
yscale = (int) (((long)xscale * (long)screen_aspect_ratio) / (long)IDEAL_SCREEN_ASPECT);
screen.height = (int) (((long)file.height * 100L) / (long)yscale);
screen.y = (gui_screen_height - 2 * gui_char_height - screen.height) / 2;
}
src_bytes = src_size = 0;
if (!open_scaler(xscale,yscale,&screen,&file)) /* set up scaler */
{
free(src_buffer);
close(src_fh);
message_box("Out of memory.");
return 0;
}
display_screen_box = screen; /* set up display parameters */
display_bytes_per_line = scaler_out_bytes_per_line;
display_screen_box.width = display_bytes_per_line * 8;
display_lines_per_buffer = DISPLAY_BUFFER_SIZE / display_bytes_per_line;
fg_make_box(box,screen.x,screen.y,screen.x+screen.width-1,screen.y+screen.height-1);
fg_msm_hidecursor();
fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box); /* draw blank page */
fg_make_box(box,0,0,screen.width-1,0);
for (i = skip_it = 0 ; i < screen.height ; i++) /* scale file to screen */
{
if ((i % display_lines_per_buffer) == 0)
{ /* need another array */
if ((display_buffers[display_buffer_count] = (unsigned char *) malloc(DISPLAY_BUFFER_SIZE)) == NULL)
{
display_free();
close_scaler();
free(src_buffer);
close(src_fh);
fg_msm_showcursor();
message_box("Out of memory.");
return 0;
}
p = display_buffers[display_buffer_count];
display_buffer_count++;
}
if (skip_it)
memset(p,0,scaler_out_bytes_per_line);
else if (!scaler(p))
skip_it = 1;
fg_drawmatrix(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,screen.x,screen.y+screen.height-i-1,(char *)p,box,fg.displaybox);
p += scaler_out_bytes_per_line;
}
fg_msm_showcursor();
fg_flush();
close_scaler();
free(src_buffer);
close(src_fh);
return 1;
}
/************************************************
* function: void display_free(void)
* free display resources
* parameters: none
* returns: nothing
************************************************/
void display_free(void)
{
int i;
if (display_buffer_count > 0)
{ /* clear out previous buffers */
for (i = 0 ; i < display_buffer_count ; i++)
free(display_buffers[i]);
display_buffer_count = 0;
}
if (display_sample_ptr != NULL) /* clear sample buffer */
free(display_sample_ptr);
}
/************************************************
* function: unsigned char *display_sample(int *samplex,int *sampley,int *dx,int *dy)
* gets info on image sampled while scaling
* parameters: pointers to x/y samples and x/y extents
* returns: pointer to image base or NULL if none
************************************************/
unsigned char *display_sample(int *samplex,int *sampley,int *dx,int *dy)
{
*samplex = xsample;
*sampley = ysample;
*dx = xdelta;
*dy = ydelta;
return display_sample_ptr;
}
/************************************************
* function: void display_numbered_box_close(void)
* clean up resources for numbered boxes
* parameters: none
* returns: nothing
************************************************/
void display_numbered_box_close(void)
{
NUMBERED_BOX *p,*q;
for (p = numbered_boxes ; p != NULL ; p = q)
{
q = p->next;
free(p);
}
numbered_boxes = NULL;
}
/************************************************
* function: void display_numbered_box(int x1,int y1,int x2,int y2,int num)
* draws a numbered box around a region, coordinates are relative to file
* parameters: x/y corners of the box and number of box
* returns: nothing
************************************************/
void display_numbered_box(int x1,int y1,int x2,int y2,int num)
{
fg_box_t box;
fg_line_t line;
char str[16];
int len,x,y,wide_screen,num_width,num_height,retry,pass;
NUMBERED_BOX *p,*q;
/* scale to screen */
x1 = (int) (((long)x1 * 100L + 50L) / (long) scaler_xscale);
y1 = (int) (((long)y1 * 100L + 50L) / (long) scaler_yscale);
x2 = (int) (((long)x2 * 100L + 50L) / (long) scaler_xscale);
y2 = (int) (((long)y2 * 100L + 50L) / (long) scaler_yscale);
/* outline box */
fg_msm_hidecursor();
fg_make_box(box,display_screen_box.x+x1,
display_screen_box.y+display_screen_box.height-y2-1,
display_screen_box.x+x2,
display_screen_box.y+display_screen_box.height-y1-1);
if (fg.nsimulcolor < 16)
fg_drawbox(FG_BLACK,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,box,fg.displaybox);
else
fg_drawbox(FG_LIGHT_RED,FG_MODE_SET,~0,FG_LINE_SOLID,box,fg.displaybox);
sprintf(str,"%d",num);
len = strlen(str);
num_width = len * gui_char_width;
num_height = gui_char_height;
if (x2-x1+1 >= num_width && y2-y1+1 >= (2*num_height)/3)
{ /* put number in upper left of box */
fg_make_box(box,display_screen_box.x+x1,
display_screen_box.y+display_screen_box.height-y1-num_height,
display_screen_box.x+x1+num_width-1,
display_screen_box.y+display_screen_box.height-y1-1);
fg_boxclip(fg.displaybox,box,box);
if (fg.nsimulcolor < 16)
{
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
fg_puts(FG_WHITE,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x+x1,
display_screen_box.y+display_screen_box.height-y1-num_height,str,box);
}
else
{
fg_fillbox(FG_RED,FG_MODE_SET,~0,box);
fg_puts(FG_YELLOW,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x+x1,
display_screen_box.y+display_screen_box.height-y1-num_height,str,box);
}
}
else
{ /* draw line between number and box */
if (display_screen_box.x == 0)
{ /* wide screen */
wide_screen = 1;
x = x1;
if (y1 < display_screen_box.height/2) /* above */
y = display_screen_box.y + display_screen_box.height + gui_char_height;
else /* underneath */
y = display_screen_box.y - 2 * gui_char_height;
}
else
{ /* tall screen */
wide_screen = 0;
y = display_screen_box.height-y1-1-gui_char_height;
if (x1 < display_screen_box.width/2) /* left */
x = display_screen_box.x - 4 * gui_char_width;
else /* right */
x = display_screen_box.x + display_screen_box.width + 2 * gui_char_width;
}
if (x < 0) /* size to screen */
x = 0;
if (x > gui_screen_width-2*gui_char_width)
x = gui_screen_width-2*gui_char_width;
if (y < 0)
y = 0;
if (y > gui_screen_height-3*gui_char_height)
y = gui_screen_height-3*gui_char_height;
for (p=numbered_boxes, pass=retry=0 ; pass < 64 ; p = p->next)
{ /* resolve overlaps */
if (p->next == NULL)
q = p;
if (p == NULL)
{
if (retry == 0)
break;
retry = 0;
p = numbered_boxes;
}
if (abs(p->x - x) < num_width && abs(p->y - y) < num_height)
{ /* have an overlap */
if (wide_screen == 1)
{
x = p->x + p->width + gui_char_width; /* move right */
if (x > gui_screen_width-num_width)
{ /* no more room */
if (pass == 0)
y = p->x - num_width - gui_char_width;
else
x = display_screen_box.width/2;
}
}
else
{
y = p->y - num_height - 1; /* move down */
if (y < 0)
{ /* no more room */
if (pass == 0)
y = p->y + num_height + 1;
else
y = display_screen_box.height/2;
}
}
retry = 1;
pass++;
}
}
p = (NUMBERED_BOX *) malloc(sizeof(NUMBERED_BOX));
if (p != NULL)
{
if (numbered_boxes == NULL)
numbered_boxes = p;
else
q->next = p;
p->next = NULL;
p->x = x;
p->y = y;
p->width = num_width;
p->height = num_height;
fg_make_line(line,p->x+p->width/2,p->y+p->height/2,
display_screen_box.x+x1+(x2-x1)/2,
display_screen_box.y+display_screen_box.height-y1-1-(y2-y1)/2);
fg_make_box(box,p->x,p->y,p->x+p->width-1,p->y+p->height-1);
fg_boxclip(fg.displaybox,box,box);
if (fg.nsimulcolor < 16)
{
fg_drawline(FG_BLACK,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
line[FG_X1]--;
line[FG_X2]--;
line[FG_Y1]++;
line[FG_Y2]++;
fg_drawline(FG_WHITE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box);
fg_puts(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,p->x,p->y,str,box);
}
else
{
fg_drawline(FG_BLUE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
line[FG_X1]--;
line[FG_X2]--;
line[FG_Y1]++;
line[FG_Y2]++;
fg_drawline(FG_LIGHT_WHITE,FG_MODE_SET,~0,FG_LINE_DENSE_DOTTED,line);
fg_fillbox(FG_RED,FG_MODE_SET,~0,box);
fg_puts(FG_YELLOW,FG_MODE_SET,~0,FG_ROT0,p->x,p->y,str,box);
}
}
}
fg_msm_showcursor();
fg_flush();
}
/************************************************
* function: int display_redraw(void)
* redraws image
* parameters: none
* returns: 1 if redrawn, 0 if nothing to draw
************************************************/
int display_redraw(void)
{
fg_box_t box;
int top,i,j,lines;
if (display_buffer_count == 0)
return 0;
top = gui_screen_height - 2 * gui_char_height;
fg_msm_hidecursor();
if (display_screen_box.x == 0)
{ /* clear above and below */
fg_make_box(box,0,0,gui_screen_width-1,display_screen_box.y-1);
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
fg_make_box(box,0,display_screen_box.y+display_screen_box.height-1,
gui_screen_width-1,top);
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
}
else
{
fg_make_box(box,0,0,display_screen_box.x-1,top);
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
fg_make_box(box,display_screen_box.x+display_screen_box.width,0,
gui_screen_width-1,top);
fg_fillbox(FG_BLACK,FG_MODE_SET,~0,box);
}
fg_make_box(box,display_screen_box.x,display_screen_box.y,
display_screen_box.x+display_screen_box.width-1,
display_screen_box.y+display_screen_box.height-1);
fg_fillbox(FG_WHITE,FG_MODE_SET,~0,box);
for (i=j=0 ; i < display_buffer_count ; i++, j+=display_lines_per_buffer)
{
if (j+display_lines_per_buffer > display_screen_box.height)
lines = display_screen_box.height - j;
else
lines = display_lines_per_buffer;
fg_make_box(box,0,0,display_screen_box.width-1,lines-1);
fg_drawmatrix(FG_BLACK,FG_MODE_SET,~0,FG_ROT0,display_screen_box.x,
display_screen_box.y+display_screen_box.height-j-lines,
(char *)display_buffers[i],box,fg.displaybox);
}
fg_msm_showcursor();
fg_flush();
return 1;
}
/**************** LOCAL FUNCTIONS ****************/
/************************************************
* function: static unsigned int read_source_buffer(void)
* parameters: none
* returns: (unsigned int) -1 if EOF or failure, else returns amount read
************************************************/
static unsigned int read_source_buffer(void)
{
src_size = read(src_fh,src_buffer,PCX_READ_BUFFER);
src_bytes = 0;
if (src_size <= 0)
src_size = (unsigned int) -1;
return src_size;
}
/* pcx structure and defines */
#define PCX_HEADER_SIZE 128
#define PCX_HEADER_USED 72
#pragma ZTC align 1
typedef struct
{
/* constants */
unsigned char manuf; /* always 10 decimal */
unsigned char hardvers; /* version */
unsigned char pcxencodmode; /* 1 if run length encoding */
/* calculated */
unsigned char bitsppix;
unsigned short x1;
unsigned short y1;
unsigned short x2;
unsigned short y2;
unsigned short hres; /* card horizontal res. */
unsigned short vres; /* card vertical res. */
unsigned char clrpa[16][3]; /* palette info */
unsigned char vmode; /* ignored, should be 0 */
unsigned char nplanes; /* number or planes */
unsigned short bplin; /* bytes per line */
unsigned short page_start;
unsigned short page_length; /* page length in pixels */
unsigned char reserved[PCX_HEADER_SIZE-PCX_HEADER_USED];
} PCX_HEADER;
#pragma ZTC align
#define MAX_PCX_ENC_LEN (63) /* maximum pcx run length */
#define PCX_MANUFACTURER 10 /* manufacturer's code */
#define PCX_RUN_LENGTH 1 /* encoding type */
#define PCX_8_BITS_PER_PIX 1 /* code for 8 bits per pixel */
#define DCX_ID 987654321L /* dcx id code */
/************************************************
* function: int get_pcx_header(int fh)
* read pcx header
* parameters: fh = file handle
* returns: 1 if success or 0 if error
************************************************/
static int get_pcx_header(int fh)
{
PCX_HEADER header;
long *l,src_offset;
if ((src_offset = lseek(fh,0L,SEEK_CUR)) == -1)
return 0;
if (read(fh,(void *) &header,sizeof(header)) != sizeof(header))
return 0;
l = (long *) &header;
if (*l == DCX_ID)
{
if (lseek(fh,*(++l)+src_offset,SEEK_SET) == -1)
return 0;
if (read(fh,(void *) &header,sizeof(header)) != sizeof(header))
return 0;
}
if (header.manuf!=PCX_MANUFACTURER || header.pcxencodmode!=PCX_RUN_LENGTH ||
header.bitsppix!=PCX_8_BITS_PER_PIX || header.nplanes != 1 ||
header.x1>header.x2 || header.y1>header.y2)
{
return 0;
}
bytes_per_line = header.bplin;
lines_per_page = header.page_length;
return 1;
}
/* macro for accessing buffer */
#define bget() \
((src_bytes < src_size) ? *(src_buffer+(src_bytes++)) : \
((read_source_buffer() == (unsigned int) -1) ? ((unsigned int) -1) : \
(*(src_buffer+(src_bytes++)))))
/************************************************
* function: unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
* parameters: buffer to read lines into and the number of bytes to read.
* returns: size put into buffer if OK or -1 if failed or EOF
************************************************/
static unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
{
unsigned int count,byt,cnt;
count = 0;
while (count < number_of_bytes)
{
if((byt=bget()) == (unsigned int) -1)
return count;
if((byt&0xc0) == 0xc0)
{
cnt = 0x3f & byt;
if((byt=bget()) == (unsigned int) -1)
return (unsigned int) -1;
memset(buffer+count,(~byt)&0xff,cnt);
}
else
{
cnt = 1;
*(buffer+count) = (~byt)&0xff;
}
count += cnt;
}
return count;
}
/************************************************
* function: static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file)
* allocate scaler resources and preset scale values
* parameters: scale factors in x & y, fixed point .00, screen and file sizes
* returns: 1 if OK or 0 if failed cuz no memory
************************************************/
static int open_scaler(int xscale,int yscale,DISPLAY_BOX *screen,DISPLAY_BOX *file)
{
unsigned int buffer_size,i;
short pixel;
unsigned short bit_pattern;
if (!open_sampler(file)) /* set up sampler */
return 0;
scaler_lines = yscale/100; /* set up scale values */
scaler_delta = yscale % 100;
scaler_error = scaler_delta;
scaler_in_bytes_per_line = (file->width + 7) / 8;
scaler_out_bytes_per_line = (screen->width + 7) / 8;
scaler_buffer_size = scaler_in_bytes_per_line * scaler_lines;
buffer_size = scaler_buffer_size + scaler_in_bytes_per_line;
if ((scaler_buffer = (unsigned char *) malloc(buffer_size)) == NULL)
return 0; /* allocate line buffer */
buffer_size = scaler_out_bytes_per_line * 8 * sizeof(short *);
if ((scaler_offset = (short *) malloc(buffer_size)) == NULL)
{ /* allocate offset buffer */
free(scaler_buffer);
return 0;
}
buffer_size = scaler_out_bytes_per_line * 8 * sizeof(short);
if ((scaler_mask = (unsigned short *) malloc(buffer_size)) == NULL)
{ /* allocate mask buffer */
free(scaler_buffer);
free(scaler_offset);
return 0;
}
scaler_xscale = xscale;
scaler_yscale = yscale;
if (xscale < 1650) /* pattern of n bits in a word */
bit_pattern = 0xffff << (16 - (xscale+50)/100);
else
bit_pattern = 0xffff;
if (bit_pattern == 0)
bit_pattern = 0x8000;
for (i = 0 ; i < scaler_out_bytes_per_line * 8 ; i++)
{ /* set up offsets and masks */
pixel = (short)(((long)i*(long)xscale)/100L);
scaler_offset[i] = pixel/8;
scaler_mask[i] = bit_pattern >> (pixel-(scaler_offset[i])*8);
scaler_mask[i] = (scaler_mask[i]>>8) | (scaler_mask[i]<<8); /* intel byte order */
}
return 1;
}
/************************************************
* function: static int scaler(unsigned char *buffer)
* scales scan lines using ratios from open_scaler()
* parameters: pointer to buffer for scaled line
* returns: 1 if OK or 0 if all done scaling
************************************************/
static int scaler(unsigned char *buffer)
{
unsigned int buffer_size,read_size,x,y,cutoff,accum,ylines;
int retval;
unsigned short bit_pattern;
unsigned char *p;
static unsigned char bit_mask[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
static unsigned char bit_count[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
retval = 1;
if (scaler_error >= 50) /* (n+1) y lines */
{
buffer_size = scaler_buffer_size + scaler_in_bytes_per_line;
ylines = scaler_lines + 1;
scaler_error -= (100-scaler_delta);
}
else /* (n) y lines */
{
buffer_size = scaler_buffer_size;
ylines = scaler_lines;
scaler_error += scaler_delta;
}
memset(buffer,0,scaler_out_bytes_per_line); /* white out line */
if ((read_size = read_pcx(scaler_buffer,buffer_size)) != buffer_size)
{ /* partial read */
memset(scaler_buffer+read_size,0,buffer_size-read_size); /* white out remaining */
retval = 0;
}
get_sample(scaler_buffer,ylines); /* get a sample */
#if I_LOVE_BLACK
if (scaler_xscale >= 1650) /* how many bits in accum are significant? */
cutoff = (ylines * 16) / 3;
else
cutoff = (((scaler_xscale+50)*ylines)/3)/100;
#else
if (scaler_xscale >= 1650) /* how many bits in accum are significant? */
cutoff = (ylines * 16) / 2;
else
cutoff = (((scaler_xscale+50)*ylines)/2)/100;
#endif
if (cutoff == 0)
cutoff = 1;
for (x = 0 ; x < (scaler_out_bytes_per_line << 3) ; x++)
{ /* for each output bit */
for (y = accum = 0, p = scaler_buffer ; y < ylines ; y++, p+=scaler_in_bytes_per_line)
{ /* for each y line in the set */
bit_pattern = *((unsigned short *)(p + scaler_offset[x])) & scaler_mask[x];
accum += (bit_count[bit_pattern>>8] + bit_count[bit_pattern&0x00ff]);
}
if (accum >= cutoff) /* if significant, mask it in */
buffer[x>>3] |= bit_mask[x&7];
}
return retval;
}
/************************************************
* function: static void close_scaler(void)
* clean up scaler resources
* parameters: none
* returns: none
************************************************/
static void close_scaler(void)
{
free(scaler_buffer);
free(scaler_offset);
free(scaler_mask);
}
/************************************************
* function: static int open_sampler(DISPLAY_BOX *file)
* parameters: pointer to file extent struct
* returns: 1 if OK or 0 if failed, non memory
************************************************/
static int open_sampler(DISPLAY_BOX *file)
{
xsample = SAMPLE_200_X; /* set sample sizes */
ysample = SAMPLE_200_Y;
xdelta = file->width / xsample; /* extent of sample */
ydelta = file->height / ysample;
while (((long)xdelta * (long)ydelta) > MAX_MALLOC)
{ /* adjust sampling to fit memory restrictions */
xsample++;
ysample++;
xdelta = file->width / xsample;
ydelta = file->height / ysample;
}
/* allocate sample buffer */
if ((display_sample_ptr = malloc(xdelta * ydelta)) == NULL)
return 0;
memset(display_sample_ptr,WHITE,xdelta * ydelta); /* set to white */
sample_line = 0;
return 1;
}
/************************************************
* function: static void get_sample(unsigned char *scaler_buffer,int ylines)
* sample the buffer
* parameters: pointer to buffer full of raw image, number of scanlines in image
* returns: nothing
************************************************/
static void get_sample(unsigned char *buffer,int ylines)
{
static unsigned char bit_mask[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
unsigned char *line_ptr,*sample_ptr;
unsigned int x,y;
for (y=0, line_ptr=buffer ; y < ylines ; y++, sample_line++, line_ptr+=scaler_in_bytes_per_line)
{
if ((sample_line % (ysample/2)) == 0) /* right line for scaling? */
{
sample_ptr = display_sample_ptr + ((sample_line/ysample) * xdelta);
if (xsample >= 8)
{ /* byte sampling */
for (x = 0 ; x < xdelta*xsample ; x += xsample, sample_ptr++)
if (*(line_ptr+(x>>3)))
*sample_ptr = BLACK; /* if byte has black, set sample */
}
else
{ /* bit sampling */
for (x = 0 ; x < xdelta*xsample ; x += xsample, sample_ptr++)
if (*(line_ptr+(x>>3)) & bit_mask[x&7])
*sample_ptr = BLACK; /* if bit is black, set sample */
}
}
}
}