/*****************************************************************

	scan.c
	routines for scanning and saving a picture

******************************************************************/

#include "Xscan.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <scanner.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>

#ifdef _HAS_XPM
#include <X11/xpm.h>
#endif

int lines_scanned=0;			/* number of currently scanned lines */
char **linebuf;				/* buffer for scanned lines	     */
int bytes_per_line;			/* bytes per scannline		     */	
int canvas_line;
int fd;					/* filedescriptor for scann-device   */
XtInputId AppId;
 
void RedrawCanvas(Widget w, XEvent *unused,String *unused1, Cardinal *unused2)
{
	if (scaninprog) return;
	Redraw(NULL,NULL,NULL);
};

/*	save scanned image as X-bitmap		*/
	
void Save(char *filen) 
{	
#ifndef _HAS_XPM	
	FILE *fp;
	char ch;
	int j;
	int k,l,m;
	int mask;
	int cnt;
	int div = 0;
	char *ptr;
	char *p[8];
	
#else
	 XpmAttributes   attr;
#endif	
	char errtxt[80];
	int i;

	if (lines_scanned <= 0) {
		Message("nothing to save");
		for(i = 0; i < 5; i++) {	
			sleep(1);
			FlushEvents();
		}
		MessageOff();
		return;
	}
	if (cellsize == 1) {
		FlushEvents();
		if (XWriteBitmapFile(XtDisplay(DrawArea), filen, DrawPix,
				 pixmap_width,lines_scanned, 2,2) != 
				 BitmapSuccess) {
			sprintf(errtxt,"Can not open %s",filen);
		 	Message(errtxt);
			for(i = 0; i < 5; i++) {
               			sleep(1);
				FlushEvents();
			}
			MessageOff();
		}	
		return;
	}
#ifdef _HAS_XPM	
	attr.valuemask = XpmColormap;
      	attr.colormap  = default_cmap;
	if (XpmWriteFileFromPixmap(XtDisplay(DrawArea), filen, DrawPix, 
		(Pixmap) NULL, &attr) != XpmSuccess) {
		sprintf(errtxt,"Can not open %s",filen);
               	Message(errtxt);
		for(i = 0; i < 5; i++) {
               		sleep(1);
			FlushEvents();
		}
		MessageOff();
	}
#else
	switch (cellsize) {
		case 2: div = 16;
			break;
		case 4: div = 4;
			break;
		case 8: div = 1;
			break;
	}
	fp = fopen(filen,"w");
	if (fp == NULL) {
		MessageOff();
		sprintf(errtxt,"Can not open %s",filen);
		Message(errtxt);
		for(i = 0; i < 5; i++) {
			sleep(1);
			FlushEvents();
		}
		MessageOff();
		return;
	}
	fprintf(fp,"/* XPM */\nstatic char * pixm[] = {\n");
	fprintf(fp,"\"%d %d 65 1\",\n",(pixmap_width / cellsize), 
					(lines_scanned / cellsize));
	for(i = 0; i < 64; i++) {
		ch = i + '0';
		if (ch > 'Z') ch+=6;
		if (ch == ';') ch = ' ';
		j = i << 10;
		fprintf(fp,"\"%c\tc #%04X%04X%04X\",\n",ch,j,j,j);
	}
	fprintf(fp,"\"%c\tc #FFFFFFFFFFFF\",\n",ch+1);

	for( i = 0; i < lines_scanned; i += cellsize) {	
		FlushEvents();
		for(j = 0; j < cellsize;j++) p[j] = linebuf[i+j];
		fputc('\"',fp);
		for(j = 0; j < bytes_per_line;j++) {
			for(k = 0; k < 8; k += cellsize) {
				cnt = 0;
				for(l = 0; l < cellsize; l++) {
					mask = 0x80 >> k;
					ptr = p[l];
					for(m = 0; m < cellsize; m++) {
						if (*ptr & mask) cnt++;
						mask = mask >> 1;
					}
				}
				cnt *= div;
				if (cnt > 65) cnt = 65;
				cnt += '0';
				if (cnt > 'Z') cnt+=6;
				if (cnt == ';') cnt = ' ';
				fputc(cnt,fp);
			}
			for(m = 0; m < cellsize; m++) p[m]++;	
		}
		fputc('"',fp);
		if (i < (lines_scanned - cellsize)) {
			fputc(',',fp);
			fputc('\n',fp);
		}	
	}	
	fprintf(fp,"};\n");
	fclose(fp);
#endif
	
}

/*	Redraw only visible part of viewportwidget.	*/

void QRedraw(int line)
{
	if (DefaultDepthOfScreen(XtScreen(DrawArea)) == 1) 
		XCopyArea(XtDisplay(DrawArea), DrawPix, XtWindow(DrawArea),
			DefaultGCOfScreen(XtScreen(DrawArea)), slider_x, line,
			slider_width, 1, 0, line);
	else 
		XCopyPlane(XtDisplay(DrawArea), DrawPix, XtWindow(DrawArea),
			DefaultGCOfScreen(XtScreen(DrawArea)), slider_x, line,
			slider_width, 1, 0, line,1);
}

/*	Make complete viewportwidget with given number of colors 	*/

void Make(void)
{
	int i, j, k,l,m;
	int x,y;
	int mask;
	int div = 0;
	int cnt;
	char *ptr;
	char *p[8];
	XGCValues val;

	if (lines_scanned <= 0) {
		pixmap_heigh = XscanAppData.MaxScanLines;
		FreePixMap();
		MakePixMap();
		ClrDraw();
		return;
	}
	FreePixMap();
	MakePixMap();
	ClrDraw();

	Message("processing");
	if (cellsize == 1) {		/* only black and white */
		for( i = 0; i < lines_scanned; i++) {
			if (i & 4) FlushEvents();
			ptr = linebuf[i];
			for(j = 0; j < bytes_per_line;j++) {
				mask = 0x80;
				for(k = 0; k < 8;k++) {
					if (!(*ptr & mask)) 			
					     XDrawPoint(XtDisplay(DrawArea),DrawPix,DrawGC,
							(j<<3)+k,i);
					mask = mask >> 1;
				}
				ptr++;
			}	
		}
	}
	else {		/* greyscale */
		switch (cellsize) {	
			case 2: div = 16;
				break;
			case 4: div = 4;
				break;
			case 8: div = 1;
				break;
		}
		y = 0;
		for( i = 0; i < lines_scanned; i+=cellsize) {
			if (i & 4) FlushEvents();
			x = 0;
			for(j = 0; j < cellsize;j++)
				p[j] = linebuf[i+j];
			for(j = 0; j < bytes_per_line;j++) {
				for(k = 0; k < 8;k+=cellsize) {
					cnt = 0;
					for(l = 0; l < cellsize; l++) {
						mask = 0x80 >> k;
						ptr = p[l];
						for(m = 0; m < cellsize; m++) {
							if (*ptr & mask) cnt++;
							mask = mask >> 1;
						}
					}
					cnt *= div;
					val.foreground = colors[cnt];
					XChangeGC(disp, DrawGC,GCForeground, &val);			 
					XDrawPoint(XtDisplay(DrawArea),DrawPix,DrawGC,
							x,y);
					x++;
				}
				for(k = 0; k < cellsize; k++) p[k]++;
			}
			y++;	
		}
	}	
	Redraw(NULL,NULL,NULL);
	MessageOff();
}

void Scan(Widget w, XtPointer client_data, XtPointer call_data)
{

	int i,dpi;
	oldcell = cellsize;
 
	XawViewportSetCoordinates(Canvas,slider_x,0);
	if (scaninprog) return;
	
	/*	release old buffers	*/
	lines_scanned += 7;
	lines_scanned &= 0xfffff8;
	for(i = 0; i < lines_scanned; i++) {
		XtFree(linebuf[i]);	
		linebuf[i] = NULL;
	}
	scaninprog = TRUE;
	bufcnt = 0;  
	PopupScanDialog();
	FreePixMap(); 
	ScanInfo(&bytes_per_line,&dpi);
	sprintf(ScanLabel,"Resolution : %d dpi",dpi);
	XtVaSetValues(ShowLabel,XtNlabel,ScanLabel, NULL);
	pixmap_width = bytes_per_line * 8;
	pixmap_heigh = MAXSCANLINES;
	cellsize = 1;
	lines_scanned = 0;
	MakePixMap();
	ClrDraw();

	fd = open("/dev/scan",O_RDONLY);
	if (fd == 0) {
		perror("Can not open /dev/scan");
		exit (1);
	}
	canvas_line = 0;	
	AppId = XtAppAddInput(app_context, fd, (XtPointer)XtInputReadMask,
			      (XtInputCallbackProc)get_line,NULL);
}
