home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
08
/
fax.asc
< prev
next >
Wrap
Text File
|
1991-07-23
|
19KB
|
499 lines
_SCALING AND PRINTING FAXES FASTER_
by Greg Pickles
[LISTING ONE]
;-----------------------------------------------------------------------------
; Scale2To3 -- by Greg Pickles -- C callable assembly language routine to
; expand 2 lines of 200 DPI bitmap to 3 lines of 300 DPI bitmap. Assumes that
; all memory for storing the lines is allocated outside this routine.
;-----------------------------------------------------------------------------
.model large,c
.286
.data
;----------------------------------------------------------------
; MapTbl contains the output bit map for each 2x2 input section
; Entries are groups of 4 bytes, with the 4th byte a placeholder.
;----------------------------------------------------------------
MapTbl dw 0000000000000000b ;0
dw 0000000000000000b
dw 0000000000000000b
dw 0
dw 0000001100000000b ;1
dw 0000001100000000b
dw 0000000000000000b
dw 0
dw 0000011000000000b ;2
dw 0000011000000000b
dw 0000000000000000b
dw 0
dw 0000011100000000b ;3
dw 0000011100000000b
dw 0000000000000000b
dw 0
dw 0000000000000000b ;4
dw 0000001100000000b
dw 0000001100000000b
dw 0
dw 0000001100000000b ;5
dw 0000001100000000b
dw 0000001100000000b
dw 0
dw 0000011000000000b ;6
dw 0000011100000000b
dw 0000001100000000b
dw 0
dw 0000011100000000b ;7
dw 0000011100000000b
dw 0000001100000000b
dw 0
dw 0000000000000000b ;8
dw 0000011000000000b
dw 0000011000000000b
dw 0
dw 0000001100000000b ;9
dw 0000011100000000b
dw 0000011000000000b
dw 0
dw 0000011000000000b ;a
dw 0000011000000000b
dw 0000011000000000b
dw 0
dw 0000011100000000b ;b
dw 0000011100000000b
dw 0000011000000000b
dw 0
dw 0000000000000000b ;c
dw 0000011100000000b
dw 0000011100000000b
dw 0
dw 0000001100000000b ;d
dw 0000011100000000b
dw 0000011100000000b
dw 0
dw 0000011000000000b ;e
dw 0000011100000000b
dw 0000011100000000b
dw 0
dw 0000011100000000b ;f
dw 0000011100000000b
dw 0000011100000000b
dw 0
.code
;--------------------------------------------------------------------
; void Scale2to3(char far*,char far*,short,short);
;--------------------------------------------------------------------
public Scale2to3
Scale2to3 proc uses si di ds,pIn:PTR,pOut:PTR,nBytes:WORD,InvFlg:Word
LOCAL OuterCnt:WORD
S23_0:
mov ax,nBytes ;get number of bytes in input line
mov OuterCnt,ax ;set outer loop count
mov dx,ax ;mult AX by 3/2 and put result in DX
shr ax,1 ;div AX by 2
jnc S23_10 ;if carry, then there is a fractional
inc ax ; bytein the result, so inc for it
S23_10: add dx,ax ;save # of bytes in output line in dx
;fill the output buffer with 0
mov cx,dx ;multiply output line size by 3
shl cx,1
add cx,dx
mov bx,cx ;save CX to test for odd value later
shr cx,1 ;divide CX by 2 to get word count
les di,pOut ;get pointer to output buffer
sub ax,ax ;get fill value
rep stosw
test bl,1 ;see if extra byte to fill
jz S23_15
stosb
S23_15: mov ax,@data
mov ds,ax
mov si,offset MapTbl
mov cl,13 ;amount to shift initial output value
;top of loop that processes a byte of input
; register usage:
; AX = input data and output data
; BX = ofset into map table
; CH = inner loop counter
; CL = shift count for this output group
; DX = size of output line
; DS:SI pointer to map table
; ES:DI pointer to output word
S23_30: les di,pIn ;get pointer to 1st input line
mov ah,byte ptr es:[di] ;get data from line 1
add di,nBytes
mov al,byte ptr es:[di] ;get data from line 2
test InvFlg,0ffffh ;see if we need to invert
jz S23_35
not ax
S23_35: mov ch,4 ;do 4 2-bit segments in next loop
mov es,word ptr pOut+2 ;get segment address of output
S23_40: rol ax,2 ;bits we want are in 0,1,8,9
push ax
and ax,303h ;mask out other bits
shl ah,2 ;move bits from 8,9 to 10,11
or al,ah ;or them into al
sub ah,ah ;clear ah
shl ax,3 ;ax now has offset into enlarge table
mov bx,ax
mov ax,[si+bx] ;get output value
rol ax,cl ;shift it
mov di,word ptr pOut
or es:[di],ax ;or into output
add di,dx ;get pointer to line 2 of output
mov ax,[si+bx+2] ;get output value
rol ax,cl ;shift it
or es:[di],ax ;or into output
add di,dx ;get pointer to line 3 of output
mov ax,[si+bx+4] ;get output value
rol ax,cl ;shift it
or es:[di],ax ;or into output
pop ax
;adjust the shift count for the output data
;and the output pointer, if necessary
cmp cl,1 ;see if we need to bump output pointer
ja S23_60 ;jump if just need to adjust count
;CL is either 0 or 1 so it must become
; either 13 or 6, respectively
; NOTE: we are later going to sub 3
; so set CL what we want + 3
mov cl,9 ;assume CL was 1
je S23_50 ;jump if CL=1
mov cl,16 ;opps! guessed wrong so make it 13
inc word ptr pOut ;when CL goes from 0 to 13, need to
; bump the output pointer by 2
S23_50: inc word ptr pOut ;increment output pointer
S23_60: sub cl,3
dec ch ;decrement inner loop counter
jnz S23_40 ;jump to inner loop if not 0
inc word ptr pIn ;increment input pointer
dec OuterCnt ;decrement outer loop counter
jnz S23_30
ret
Scale2to3 endp
end
[LISTING TWO]
/*******************************************************************
* PCXHP.H by Greg Pickles -- Header file for FAX image print program.
*******************************************************************/
typedef struct { // This struct passes control information.
SHORT sXpos; // x pos for image on page in pixels
SHORT sYpos; // y pos for image on page in pixels
SHORT sInv; // TRUE to invert image
SHORT sEndAdjust; // number of bytes at end of a raster line to adjust
// because they are beyond the end of the actual image
SHORT sAdjOffset; // offset in line of first byte to adjust
UCHAR ucMask; // mask to OR in to the first byte that is
// adjusted (image may end in middle of byte)
} OPTIONS;
typedef struct { // This struct is the PCX file header.
UCHAR ucPcxId; // PCX ID, always 0x0a
UCHAR ucVer; // PCX version
UCHAR ucEncMeth; // 1 = run length
UCHAR ucBPP; // bits per pixel
USHORT usUpLeftX, usUpLeftY; // position of upper left corner
USHORT usLoRightX, usLoRightY; // position of lower right corner
USHORT usDispXRes, usDispYRes; // resolution of display
UCHAR aucPalette[48]; // palette data
UCHAR ucRes;
UCHAR ucNumPlanes; // number of bit planes of data
USHORT usBytePerLine; // # bytes in an raster line
UCHAR ucRes2[60];
} PCX_HDR;
/*-------------- Function prototypes-------------------------------------*/
int PCXToHP(char*, FILEBUFFER*, OPTIONS*);
void usage(void);
PCX_HDR *PcxReadHeader(PCX_HDR*, FILEBUFFER*);
void pcx_print_header(PCX_HDR*);
UCHAR *pcx_alloc_line(PCX_HDR*, SHORT);
int PcxReadLines(PCX_HDR*, UCHAR*, FILEBUFFER*, SHORT, OPTIONS*);
UCHAR *pcx_test_line(PCX_HDR*, UCHAR*, SHORT, SHORT);
UCHAR *ScanNE(UCHAR*, UCHAR, int);
int IndexNE(UCHAR*, UCHAR, int);
int CntREQ(UCHAR*, UCHAR, int);
int main(int, char**);
void Scale2to3(char far*,char far*,short,short);
[LISTING THREE]
/*******************************************************************
* PCXHP.C by Greg Pickles --- FAX to LaserJetII image print program.
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <conio.h>
#include "bufio.h"
#include "pcxhp.h"
/*******************************************************************
* PCXToHP -- Process a PCX file. Returns 0 if successful, non-0 if error
* pszFileName : pointer to the input file name
* pstrcOutFile : pointer to output file buffer structure
* pstrcOpt : pointer to OPTIONS struc for processing this file
*******************************************************************/
int PCXToHP(char *pszFileName, FILEBUFFER *pstrcOutFile, OPTIONS *pstrcOpt)
{
FILEBUFFER *pstrcInFile;
PCX_HDR strcHdr;
SHORT i, k, sXsize, sYsize, sLineBytes, sExpLineSize;
UCHAR *pucLine, *pucExpBuf;
int iCurX = -1, iCurY = -1;
int iNewX, iNewY, iFront, iBack;
char szFileName[80];
char szHpLineLead[20];
char szHpPos[50];
// these strings are for building PCL4 commands
static char szPosFmtFXYO [] = "\x01b*p%dx%dY\x01b*r1A";
static char szPosFmtY [] = "\x01b*p%dY";
static char szGrDataFmt [] = "\x01b*b%dW";
static char szEndGr [] = "\x01b*rB";
static char szRes300 [] = "\x01b*t300R";
strcpy(szFileName, pszFileName); // make local copy of name
if (strchr(szFileName,'.') == NULL) // add .PCX if needed
strcat(szFileName,".pcx");
// allocate input file buffer and open file, using my buffered I/O routines
if ( (pstrcInFile=FileOpen(szFileName,0)) == NULL )
return 1;
if (PcxReadHeader(&strcHdr,pstrcInFile) == NULL) {
fprintf(stderr,"Error reading PCX header in file '%s'\n",
szFileName);
close(pstrcInFile->hFile);
return 3;
}
if (strcHdr.ucNumPlanes != 1) {
fprintf(stderr,"Error: Not a monochrome PCX file.\n");
close(pstrcInFile->hFile);
return 5;
}
// extract size of line, compute number of rows,
// allocate buffer for 2 input lines
sLineBytes = strcHdr.usBytePerLine;
sYsize = strcHdr.usLoRightY - strcHdr.usUpLeftY + 1;
pucLine = malloc(2*sLineBytes);
// determine whether any bits/bytes need to be masked
// at the end of a decompressed line
sXsize = (strcHdr.usLoRightX - strcHdr.usUpLeftX + 1);
if ( sXsize/8 < sLineBytes ) {
pstrcOpt->sEndAdjust = sLineBytes - sXsize/8;
pstrcOpt->sAdjOffset = sXsize/8;
pstrcOpt->ucMask = (UCHAR) (0xff >> sXsize%8);
}
// compute length of scaled line and allocate buffer
sExpLineSize = strcHdr.usBytePerLine + (strcHdr.usBytePerLine/2) +
((strcHdr.usBytePerLine & 1) ? 1 : 0);
pucExpBuf = malloc(sExpLineSize*3);
// set HP graphics resolution to 300 DPI
BufWrite(pstrcOutFile,szRes300, strlen(szRes300));
// init position on page
iNewX = pstrcOpt->sXpos;
iNewY = pstrcOpt->sYpos;
for (i=0; i<sYsize; i+=2) {
if ( !PcxReadLines(&strcHdr, pucLine, pstrcInFile, 2, pstrcOpt) )
break;
Scale2to3(pucLine,pucExpBuf,sLineBytes,pstrcOpt->sInv);
for (k=0; k<3; k++) {
if ((iFront=IndexNE(pucExpBuf+k*sExpLineSize,0,sExpLineSize)) >= 0) {
iNewX = pstrcOpt->sXpos + iFront*8;
iBack=CntREQ(pucExpBuf+(k+1)*sExpLineSize-1,0,sExpLineSize);
if (iNewX != iCurX) {
sprintf(szHpPos,szPosFmtFXYO,iNewX,iNewY);
BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
iCurX = iNewX;
iCurY = iNewY;
}
else if (iNewY != iCurY) {
sprintf(szHpPos,szPosFmtY,iNewY);
BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
iCurY = iNewY;
}
// note: a possible optimization is to remember the previous
// leadin string, value of iFront, and leadin string length
// and only create them when they change
sprintf(szHpLineLead,szGrDataFmt, sExpLineSize-iFront-iBack);
BufWrite(pstrcOutFile,szHpLineLead,strlen(szHpLineLead));
BufWrite(pstrcOutFile,pucExpBuf+k*sExpLineSize+iFront,
sExpLineSize-iFront-iBack);
iCurY++;
}
iNewY++;
}
}
BufWrite(pstrcOutFile,szEndGr,strlen(szEndGr));
BufWrite(pstrcOutFile,"\f",1);
free(pucLine);
free(pucExpBuf);
FileClose(pstrcInFile);
return 0;
}
/*******************************************************************/
void usage(void) // displays help info about usage, return to system
{
printf("PCXHP\n");
printf(" Given a .PCX file, this program creates a file which can be\n");
printf(" sent to an HP LaserJet printer to print the image.\n");
printf(" PCXHP [-xX] [-yY][-d] [-i] [-ofilename] filename\n");
printf(" Options include: (units) [default]\n");
printf(" -xPOS set horizontal position (pixels from left) [0]\n");
printf(" -yPOS set vertical position (pixels from bottom) [0]\n");
printf(" -d dump PCX file info to stdout [off]\n");
printf(" -i sInv image [off]\n");
printf(" -oFIL set output filename, or use SET PCXHP=filename\n");
exit(1);
}
/*******************************************************************
* PcxReadHeader -- Reads the header of a PCX file. Returns NULL if can't.
*******************************************************************/
PCX_HDR *PcxReadHeader(PCX_HDR *pstrcHdr, FILEBUFFER *pstrcF)
{ lseek(pstrcF->hFile,0L,SEEK_SET);
if (read(pstrcF->hFile,(char*)pstrcHdr,sizeof(PCX_HDR))
!= sizeof(*pstrcHdr))
return NULL;
else return pstrcHdr;
}
/*******************************************************************
* PcxReadLines --- returns TRUE if success, FALSE if out of data
* Reads and expands the next N line from the PCX file. Assumes
* that the file pointer is positioned at the point in the file at
* which to begin reading. Performs data expansion as necessary.
* pstrcHdr : pointer to PCX header struct for the file
* pbLine : pointer to the buffer in which to put lines
* pstrcF : pointer to the opened FILEBUFFER for the file
* sLines : number of lines to read and expand
*******************************************************************/
int PcxReadLines(PCX_HDR *pstrcHdr, UCHAR *pucLine, FILEBUFFER *pstrcF,
SHORT sLines, OPTIONS *pstrcOpt)
{
int iData, iData2;
UCHAR *pucDst, *pucLineStart;
USHORT usLSize = pstrcHdr->usBytePerLine;
int i, j;
for (j=0, pucDst=pucLine; j<sLines; j++) {
for (i=0, pucLineStart=pucDst; i<usLSize; ) {
// if we get EOF on the first line, return FALSE
// to indicate we're done, otherwise fill the
// rest of the lines with 0xff (i.e. blank)
if ((iData=GetBufCh(pstrcF)) == EOF) {
if ( (j > 0) || (i > 0) ) {
memset(pucDst,0xff,usLSize-i);
i = usLSize;
pucDst += (usLSize-i);
}
else
return FALSE;
}
else {
if ((iData & 0xc0) == 0xc0) { // check for run length
// read data to be repeated; if EOF, return FALSE
if ((iData2=GetBufCh(pstrcF)) == EOF)
return FALSE;
memset(pucDst, (UCHAR)iData2, iData & 0x3f);
pucDst += iData & 0x3f;
i += iData & 0x3f;
}
else {
*pucDst++ = (UCHAR)iData;
i++;
}
}
}
if (i=pstrcOpt->sEndAdjust) {
pucLineStart += pstrcOpt->sAdjOffset;
*pucLineStart |= pstrcOpt->ucMask;
while (--i)
*(++pucLineStart) = 0xff;
}
}
return TRUE;
}
/*******************************************************************
* IndexNE -- Scans a buffer for the first byte not equal to a specified byte.
* pbBuf pointer to the buffer to test
* bVal value to test for
* iCount number of bytes to test
* Returns: -1 if the buffer contains only the specified byte
* otherwise offset of the first byte that is not the specified byte
*******************************************************************/
int IndexNE(UCHAR *bBuf, UCHAR bVal, int iCount)
{ int iOrig = iCount;
while (iCount && (*bBuf == bVal)) { iCount--; bBuf++; }
if (iCount) return iOrig-iCount;
return -1;
}
/*******************************************************************
* CntREQ -- Counts the number of bytes equal to a specified byte from a
* starting point in memory backwards.
* pbBuf : pointer to the (end of the) buffer to test
* bVal : value to test for
* iCount : number of bytes to test
* Returns number of bytes found that are equal to the specified byte
*******************************************************************/
int CntREQ(UCHAR *bBuf, UCHAR bVal, int iCount)
{ int iOrig = iCount;
while (iCount && (*bBuf == bVal)) { iCount--; bBuf--; }
return iOrig-iCount;
}
/*******************************************************************/
int main(int argc, char *argv[])
{
int i;
FILEBUFFER *OutFile;
char *outfname = NULL;
char *filename = NULL;
static OPTIONS Opt = {0,0,TRUE,0,0,0};
if (argc < 2) usage();
for (i=1; i<argc; i++) {
if (argv[i][0] == '-' || argv[i][0] == '/')
switch (toupper(argv[i][1]))
{
case 'X': Opt.sXpos = atoi(argv[i]+2); break;
case 'Y': Opt.sYpos = atoi(argv[i]+2); break;
case 'I': Opt.sInv = !Opt.sInv; break;
case 'O': outfname=argv[i]+2; break;
case '?': usage(); break;
default: fprintf(stderr, "Unknown option %s\n",argv[i]);
usage(); break;
}
else
filename = argv[i];
}
if ( (outfname == NULL) && ((outfname = getenv("PCXHP")) == NULL) )
outfname = "prn";
if ( (OutFile=FileOpen(outfname,1)) == NULL ) exit(1);
i = PCXToHP(filename, OutFile, &Opt);
FileClose(OutFile);
return i;
}