Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://hpscanpbm_0.3a-11_s390.deb:20264/usr/share/doc/hpscanpbm/hpscanpbm.c.gz  info  downloads

/*
        hpscanpbm
        User-level SCSI HP Scanjet driver
        Written by David Etherton, etherton@netcom.com
        HPUX Port by John Fehr, fehr@ninja.aes.mb.doe.ca
	Little hacks by Steve Enns  ennss@nhrisv.nhrc.sk.doe.ca
	Copyright 1995, David Etherton
        Released under the terms of the GPL.
        *NO WARRANTY*

        Thanks to Les Johnson (les@ulysses.homer.att.com) for
        suggesting some Linux documentation clarifications.

        THIS IS ALPHA SOFTWARE.  IT WORKS FINE FOR ME.
        IT MIGHT NOT WORK FOR YOU.  You'll need to be
        familiar with rebuilding kernels to take
        advantage of this program (under older versions
	of Linux at least)

	Version 0.3alpha: dpi, save/restore tweaks, documentation
		update for newer linux kernels.

        Version 0.2alpha: HPUX port, better documentation, more
                scanner adjustments.

        Version 0.1alpha: initial release
*/

/*
        Build with cc hpscanpbm.c -o hpscanpbm

        Use "hpscanpbm -help" for instructions.  Creates portable pitmap
        file as output.  Can easily be used in a pipeline or with a
        "real" scanning application.  To use from an application,
        fork, redirect stdout and stderr, then exec this program with the
        -quiet switch.  On termination, if you got anything from
        stderr, issue it as a diagnostic; otherwise, interpret
        stdout as a PBM file.

*** Linux Notes ***

        THIS IS NOT A DEVICE DRIVER.  Your Scanjet must be connected
        to a SCSI adapter that is supported by Linux.  While the chipsets
        used on the boards supplied with the IIc and IIcx (NCR 53C400 and
        53C800) do seem to have some support under Linux, these exact
        board configurations are not supported yet.  I've had good luck
        with a Future Domain TMC-850.  Performance of this 8bit card
        isn't amazing but it definitely works.

        This program uses the generic SCSI interface.  Therefore, you 
        must have generic scsi enabled in your kernel, and you should
        have a series of generic SCSI devices set up:
        
                /dev/sga        major 21, minor 0 (mknod /dev/sga c 21 0)
                /dev/sgb        major 21, minor 1 (mknod /dev/sgb c 21 1)
                :               :

        SCSI generic devices should be character devices, not block
        devices.  Furthermore, even devices that are already assigned
        to other names (like /dev/sda, /dev/sr0) also get a generic
        entry point.  This means that you need at least as many scsi
        generic device entries as you have scsi devices.

       	If you're paranoid, clear all permissions on all generic devices 
       	except the scanner.  Figuring out in advance which generic device 
       	ends up being your scanner can get a little tricky.  If you only
        have one SCSI bus, they're allocated in order of SCSI id.
        In my case, I've got two SCSI controllers, one for my
        internal stuff and one for my scanner; I've got three devices
        on the first bus so my scanner ends up being on /dev/sgd.
        (I've got the wrong kind of cable to hook everything onto
        a single bus).  Unless the program is given the "-quiet" or
        "-dev" options, it will tell you where it found the scanner.
        The scanner's device must have both read and write permission.

        If you're running anthing older than about 1.1.74, you'll probably 
	also need to patch /usr/src/linux/drivers/scsi/scsi.c
        near line 370.  In a switch statement containing the lines:
        (the first line is a bit different as of kernel 1.1.73)

                switch (type = scsi_result[0])
                {
                      case TYPE_TAPE :
                      case TYPE_DISK :
                      case TYPE_MOD :
                        ** add this: **
                      case 3 :
                        SDpnt->writeable = 1;
                        break;

        you'll need to add "case 3:" as indicated above; you'll also need
        to add the HP scanner to the scsi blacklist near the top of
        the file:

        static struct blist blacklist[] =
        {
                :       :         :
                : lots of entries :
                {"HP", "C1750A", "3226"},
                {"HP", "C2500A", "????"},
		{"HP", "C2570A", "3406"},
                {NULL, NULL, NULL}};
        }

        I've tested this under 1.1.49, 1.1.72, 1.1.73, and 1.1.94.
	That shouldn't matter too much, I hope.  

        The program is smart enough to autoprobe for your Scanjet
        and won't try, for example, to read your disk drive.

	Generic SCSI got broken in the late 1.1.70's and didn't
	get fixed again until the late .80's.  All of the patches
	listed above are in the current kernel (1.1.94) *except*
	for the "C2570A" blacklist entry which is for the Scanjet 3p.

*** HPUX Notes ***

        On the 700 series, use the following command:
        mknod /dev/scanner c 105 0x201<N>00 (where N is the scsi #)
        You might also want to do a 'chmod 666 /dev/scanner' to allow 
        everyone to access the scanner.

	Compile:   cc +O3 -Aa -D_HPUX_SOURCE hpscanpbm.c

        (Please direct HPUX questions to John)

*** Steve Enns/Synergrafix Consulting notes ***

	Code changes marked with **ENNS**

	I have added the following options:

	-xres, -yres   to specify the desired width,height of the
		scanned image in pixels.  xdpi,ydpi  will be adjusted
		to get the desired number of pixels for a given scan
		size.
	-s filename, -l filename   to save/load a file containing
		the other optional parameters.  These options are
		sensitive to option order on the command line - 
		i.e. specify -l first if you want to override some 
		settings from the file, and specify -s last if you
		want to save all the options from the current command
		line to the parameter file.  

	e.g.
	
	hpscanpbm -xres 1280 -yres 1280 -cm -width 12 -height 12 -format color -s cdcover.hps > sample.ppm

	will scan an image and save the parameters to  cdcover.hps  which can
	be used later as:

	hpscanpbm -l cdcover.hps > sample2.ppm

	suitable for scanning audio CD covers ;-)

*/


#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#ifndef _HPUX_SOURCE
#include "scsi/sg.h"
#else
#include <sys/scsi.h>
#include <fcntl.h>
#endif

/* this might eventually go into a header file */
#define THRESHOLDED     0
#define DITHERED        1
#define GREYSCALE       2
#define TRUECOLOR       3

/**ENNS  added xres,yres **/

typedef struct {
        int xdpi, ydpi;
	int xres, yres; /* in pixels */
        int x, y, width,height; /* in decipoints, 1/720in */
        int format;
        double brightness, contrast;
}       ScanSettings;

/* default is 100dpi binarized 8.5x11 image */
ScanSettings settings = { 100, 100, 0, 0, 0, 0, 6120, 7920, THRESHOLDED, 0.0, 0.0 };

int min(int a,int b) { return a<b? a : b; }

static int quiet;

static void dump(void *buffer,int count)
{
        unsigned char *c = buffer;
        int i,j;
        for (i=0; i<count; i+=16) {
                printf("%04x: ",i);
                for (j=i; j<i+16; j++)
                        if (j < count)
                                printf("%02x ",c[j]);
                        else
                                printf("   ");
                for (j=i; j<i+16; j++)
                        if (j < count)
                                putchar(isprint(c[j])?c[j]:'.');
                        else
                                putchar(' ');
                putchar('\n');
        }
}


#ifndef _HPUX_SOURCE    /* Linux version */
        
int sg_xfer(int fid,unsigned char *src,int len,unsigned char *dest,
                int reply_len)
{
        int count, result;
        static struct sg_header hdr;
        static char buf[4096 + sizeof(struct sg_header)];
        hdr.pack_len = sizeof(hdr) + len;
        hdr.reply_len = sizeof(hdr) + reply_len;
        memcpy(buf, &hdr, sizeof(hdr));
        memcpy(buf + sizeof(hdr), src, len);
        if (write(fid, buf, hdr.pack_len) == -1) {
                perror("sg_xfer(write)");
                return -1;
        }
        if ((count = read(fid,buf,hdr.reply_len)) == -1) {
                perror("sg_xfer(read)");
                return -1;
        }
        result = ((struct sg_header*)buf)->result;
        if (result) {
                fprintf(stderr,"sg_xfer: result is %d\n",result);
        }
        if (count > sizeof(struct sg_header)) {
                count -= sizeof(struct sg_header);
                memcpy(dest,buf + sizeof(hdr),count);
        }
        else
                count = 0;
        return count;
}

#else   /* HPUX version */

int sg_xfer(int fid,unsigned char *src,int len,unsigned char *dest,
                int reply_len,int flags)
{
        int count, result;
        struct sctl_io hdr;
        static char buf[2048];
        memset(&hdr,0,sizeof(struct sctl_io));
        memcpy(hdr.cdb,src,len);
        hdr.flags=flags;
        hdr.cdb_length=len;
        hdr.data=dest;
        hdr.data_length=reply_len;
        hdr.max_msecs=10000;    /* ten seconds for command */
        if (ioctl(fid,SIOC_IO,&hdr) == -1)
        {
                perror("sg_xfer(ioctl)");
                return -1;
        }
        result=hdr.cdb_status;
        count=hdr.data_xfer;

        if (result) {
                fprintf(stderr,"sg_xfer: result is %d\n",result);
        }
        return count;
}
#endif

int inquire_device(int fid,char *mfg,char *model)
{
        static unsigned char inquiry[] = { 0x12,0,0,0,255,0 };
        unsigned char reply[256];
#ifndef _HPUX_SOURCE
        if (sg_xfer(fid,inquiry,sizeof(inquiry),reply,sizeof(reply)) < 16)
                return -1;
#else
        if (sg_xfer(fid,inquiry,sizeof(inquiry),reply,sizeof(reply),SCTL_READ) < 16)
                return -1;
#endif
        memcpy(mfg,reply + 8, 8);
        memcpy(model,reply + 16, 16);
        return reply[0];
}

int write_data(int fid,char *data,int len)
{
        char write_6[4096];
        memset(write_6,0,6);
        write_6[0] = 0xa;
        write_6[2] = len >> 16;
        write_6[3] = len >> 8;
        write_6[4] = len;
        memcpy(write_6 + 6, data, len);
#ifndef _HPUX_SOURCE
        if (sg_xfer(fid,write_6,6 + len,0,0) < 0)
#else
        if (sg_xfer(fid,write_6,6,write_6 + 6,sizeof(write_6) - 6,0) < 0)
#endif
                return -1;
        return 0;
}

int read_data(int fid,char *dest,int len)
{
        static unsigned char read_6[6] = { 8,0,0,0,0,0 };
        read_6[2] = len >> 16;
        read_6[3] = len >> 8;
        read_6[4] = len;
#ifndef _HPUX_SOURCE
        if ((len=sg_xfer(fid,read_6,6,dest,len)) < 0)
#else
        if ((len=sg_xfer(fid,read_6,6,dest,len,SCTL_READ))<0)
#endif
                return -1;
        /* dump(dest,len); */
        return len;
}

int write_string(int fid,char *format,...)
{
        va_list args;
        char buf[1024];
        va_start(args, format);
        vsprintf(buf,format,args);
        write_data(fid,buf,strlen(buf));
}

int inquire(int fid,char *inq)
{
        char reply[128];
        write_string(fid,inq);
        if (read_data(fid,reply,sizeof(reply))) {
                /* dump(reply,128); */
                /* this should be less haphazard */
                return atoi(strchr(reply,'d') + 1);
        }
        else
                return -1;
}

int norm8(double value)
{
	if (value < -1.0)
		value = -1.0;
	else if (value > 1.0)
		value = 1.0;
	return (int)(value * 127.0);
}

void do_scan(char *dest,int fid,ScanSettings* ss)
{
        char buf[4000];
        int len, blocks = 0, mode;
        FILE *f = dest? fopen(dest,"w") : stdout;
        int pixels_per_line, bytes_per_line, lines, pixels;

        /* reset scanner; returns all paramters to defaults */
        write_string(fid,"\033E");

        /* set resolution, in DPI */
        write_string(fid,"\033*a%dR",ss->xdpi);
        write_string(fid,"\033*a%dS",ss->ydpi);

        /* set scan extents, in 1/720'ths of an inch */
        write_string(fid,"\033*a%dX",ss->x);
        write_string(fid,"\033*a%dY",ss->y);
        write_string(fid,"\033*a%dP",ss->width);
        write_string(fid,"\033*a%dQ",ss->height);

        /* (the original scanjet only allows -1, 0, or 1) */
        write_string(fid,"\033*a%dL",norm8(ss->brightness));
        write_string(fid,"\033*a%dK",norm8(ss->contrast));

        /* greyscale and color modes seems to need to have their
                outputs inverted; thresholded and dithered modes
                do not (the default) */
        if (ss->format > DITHERED)
                write_string(fid,"\033*a1I");
        mode = 4;
        /* data format is thresholded by default; pixel format
                is 8 pixels/byte */
        if (ss->format == DITHERED) {
                /* data format: dithered */
                write_string(fid,"\033*a3T");
        }
        else if (ss->format == GREYSCALE) {
                /* data format is greyscale, pixel format is
                        one pixel/byte */
                write_string(fid,"\033*a4T");
                write_string(fid,"\033*a8G");
                mode = 5;
        }
        else if (ss->format == TRUECOLOR) {
                /* data format is 24bit color, pixel format
                        is one pixel/three bytes */
                write_string(fid,"\033*a5T");
                write_string(fid,"\033*a24G");
                mode = 6;
        }
        /* inquire resulting size of image after setting it up */
        pixels_per_line = inquire(fid,"\033*s1024E");
        bytes_per_line = inquire(fid,"\033*s1025E");
        lines = inquire(fid,"\033*s1026E");

        if (!quiet) {
                fprintf(stderr,"%d pixels per line, %d bytes, %d lines high\n",
                        pixels_per_line, bytes_per_line, lines);
		fprintf(stderr,"xdpi %d, ydpi %d\n",ss->xdpi,ss->ydpi);
		}
        fprintf(f,"P%d\n# created by hpscanpbm\n%d %d\n",
                        mode,pixels_per_line,lines);
        if (mode > 4)
                fprintf(f,"255\n");
        pixels = bytes_per_line * lines;

        write_string(fid,"\033*f0S");           /* begin scan! */

        /* consume all data */
        while (pixels && (len = read_data(fid,buf,min(sizeof(buf),pixels)))) {
                pixels -= len;
                fwrite(buf,len,1,f);
        }
        if (dest)
                fclose(f);
}

int is_hp_scanner(char *devname)
{
        int fd = open(devname, O_RDWR);
        if (fd != -1) {
                char mfr[8], model[16];
                int type = inquire_device(fd,mfr,model);
                if (type == 3 && !strncmp(mfr,"HP",2))
                        return fd;
                close(fd);
        }
        return -1;
}

int find_hp_scanner(void)
{
        char buf[16];
        int i, fd;
#ifndef _HPUX_SOURCE
        for (i='a'; i <= 'z'; i++) {
                sprintf(buf,"/dev/sg%c",i);
#else
                sprintf(buf,"/dev/scanner");
#endif
                if ((fd = is_hp_scanner(buf)) != -1) {
                        if (!quiet)
                                fprintf(stderr,
                                        "HP Scanjet found on '%s'\n",buf);
                        return fd;
                }
#ifndef _HPUX_SOURCE
        }
#endif
        return -1;
}

/** ENNS  Added loadsettings and savesettings **/

int loadsettings(char *filename) {
	FILE *fin;
	if ((fin=fopen(filename,"rb"))==NULL) {
		fprintf(stderr,"Can't open settings file %s for read.\n",filename);
		exit(1);
		}
	if (fread(&settings,sizeof(settings),1,fin)!=1) {
		fprintf(stderr,"Can't read settings file %s\n",filename);
		exit(1);
		}
	return 0;
	}


int savesettings(char *filename) {
	FILE *fin;
	if ((fin=fopen(filename,"wb"))==NULL) {
		fprintf(stderr,"Can't open settings file %s for write.\n",filename);
		exit(1);
		}
	if (fwrite(&settings,sizeof(settings),1,fin)!=1) {
		fprintf(stderr,"Can't write settings file %s\n",filename);
		exit(1);
		}
	return 0;
	}


#define nextargi (--argc,atoi(*++argv))
#define nextargf (--argc,atof(*++argv))
#define nextargs (--argc,*++argv)

/** ENNS  Added xres,yres,l,s options **/

void main(int argc,char **argv)
{
        double posfactor = 720.0;
        char *devname = (char*)0, *outname = (char*)0;
        int fd;

        while (--argc && **++argv=='-') {
		if (!strcmp(argv[0],"-l") || !strcmp(argv[0],"-load"))
			loadsettings(nextargs);
                else if (!strcmp(argv[0],"-dpi"))
                        settings.xdpi = settings.ydpi = nextargi;
                else if (!strcmp(argv[0],"-xdpi"))
                        settings.xdpi = nextargi;
                else if (!strcmp(argv[0],"-ydpi"))
                        settings.ydpi = nextargi;
                else if (!strcmp(argv[0],"-xres"))
			settings.xres = nextargi;
		else if (!strcmp(argv[0],"-yres"))
			settings.yres = nextargi;
		else if (!strcmp(argv[0],"-in")) 
                        posfactor = 720.0;
                else if (!strcmp(argv[0],"-cm")) 
                        posfactor = 720.0 / 2.54;
                else if (!strcmp(argv[0],"-mm")) 
                        posfactor = 720.0 / 25.4; 
                else if (!strcmp(argv[0],"-x"))
                        settings.x = posfactor * nextargf;
                else if (!strcmp(argv[0],"-y"))
                        settings.y = posfactor * nextargf;
                else if (!strcmp(argv[0],"-width"))
                        settings.width = posfactor * nextargf;
                else if (!strcmp(argv[0],"-height"))
                        settings.height = posfactor * nextargf;
		else if (!strcmp(argv[0],"-bright"))
			settings.brightness = nextargf;
		else if (!strcmp(argv[0],"-cont"))
			settings.contrast = nextargf;
                else if (!strcmp(argv[0],"-dev"))
                        devname = nextargs;
                else if (!strcmp(argv[0],"-o") || !strcmp(argv[0],"-out"))
                        outname = nextargs;
                else if (!strcmp(argv[0],"-q") || !strcmp(argv[0],"-quiet"))
                        quiet = 1;
                else if (!strcmp(argv[0],"-format")) {
                        char *mn = nextargs;
                        if (!strcmp(mn,"thresholded"))
                                settings.format = THRESHOLDED;
                        else if (!strcmp(mn,"dithered"))
                                settings.format = DITHERED;
                        else if (!strcmp(mn,"greyscale") || 
                                        !strcmp(mn,"grayscale"))
                                settings.format = GREYSCALE;
                        else if (!strcmp(mn,"color"))
                                settings.format = TRUECOLOR;
                        else {
                                fprintf(stderr,"invalid mode; ");
                                goto oops;
                        	}
			}
	 	else if (!strcmp(argv[0],"-s") || !strcmp(argv[0],"-save")) 
			savesettings(nextargs);
                else {
                        if (strcmp(argv[0],"-help"))
                                fprintf(stderr,"unknown option '%s'; ",argv[0]);	oops:
        fprintf(stderr,"valid options are:\n"
        "-dpi    sets x & y scan resolution in dots per inch\n"
        "-xdpi   sets x scan resolution only (default 100)\n"
        "-ydpi   sets y scan resolution only (default 100)\n"
	"-xres   sets desired number of x-pixels on output image\n"
	"-yres   sets desired number of y-pixels on output image\n"
        "-in     specify scan region in inches (default)\n"
        "-cm     specify scan region in centimeters\n"
        "-mm     specify scan region in millimeters\n"
        "-x      specify upper left x of scan region (default 0.0)\n"
        "-y      specify upper left y of scan region (default 0.0)\n"
        "-width  specify width of scan region (default 8.5in)\n"
        "-height specify height of scan region (default 11.0in)\n"
        "-bright specify brightness adjustment (-1.0 to 1.0, default 0.0)\n"
        "-cont   specify contrast adjustment (-1.0 to 1.0, default 0.0)\n"
        "-dev    scsi generic device of scanner (default autoprobe)\n"
        "-o,-out output file (default stdout)\n"
        "-quiet  turn off informational messages\n"
	"-load   read parameter settings from file\n"
	"-save   save current parameter settings to file\n"
        "-format pixel format: thresholded, dithered, greyscale, color\n"
                                );
                        exit(1);
                }
        }
        if (argc)
                goto oops;
        if (!devname) {
                fd = find_hp_scanner();
                if (fd == -1) {
                        fprintf(stderr,"No HP Scanjet found.\n");
                        exit(2);
                }
        }
        else if ((fd = is_hp_scanner(devname)) == -1) {
                fprintf(stderr,"'%s' is not an HP Scanjet.\n",devname);
                exit(2);
        }

	/** ENNS  hack dpi for desired xres,yres */

	if (settings.xres != 0) 
		settings.xdpi=(settings.xres/(settings.width/720.0)+0.5);
	if (settings.yres != 0)
		settings.ydpi=(settings.yres/(settings.height/720.0)+0.5);

        do_scan(outname,fd,&settings);
        close(fd);
}

Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions