Category : Files from Magazines
Archive   : DDJ8_91.ZIP
Filename : FAX.ASC

 
Output of file : FAX.ASC contained in archive : DDJ8_91.ZIP
_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
#include
#include
#include
#include
#include
#include
#include
#include
#include

#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 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 for (i=0, pucLineStart=pucDst; i // 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 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;
}



  3 Responses to “Category : Files from Magazines
Archive   : DDJ8_91.ZIP
Filename : FAX.ASC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/