home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 08 / fax.asc < prev    next >
Text File  |  1991-07-23  |  19KB  |  499 lines

  1. _SCALING AND PRINTING FAXES FASTER_
  2. by Greg Pickles
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. ;-----------------------------------------------------------------------------
  8. ;  Scale2To3 -- by Greg Pickles -- C callable assembly language routine to 
  9. ;  expand 2 lines of 200 DPI bitmap to 3 lines of 300 DPI bitmap. Assumes that
  10. ;  all memory for storing the lines is allocated outside this routine.
  11. ;-----------------------------------------------------------------------------
  12. .model  large,c
  13. .286
  14.     .data
  15.     ;----------------------------------------------------------------
  16.     ; MapTbl contains the output bit map for each 2x2 input section
  17.     ; Entries are groups of 4 bytes, with the 4th byte a placeholder.
  18.     ;----------------------------------------------------------------
  19. MapTbl  dw  0000000000000000b       ;0
  20.     dw  0000000000000000b
  21.     dw  0000000000000000b
  22.     dw  0
  23.     dw  0000001100000000b       ;1
  24.     dw  0000001100000000b
  25.     dw  0000000000000000b
  26.     dw  0
  27.     dw  0000011000000000b       ;2
  28.     dw  0000011000000000b
  29.     dw  0000000000000000b
  30.     dw  0
  31.     dw  0000011100000000b       ;3
  32.     dw  0000011100000000b
  33.     dw  0000000000000000b
  34.     dw  0
  35.     dw  0000000000000000b       ;4
  36.     dw  0000001100000000b
  37.     dw  0000001100000000b
  38.     dw  0
  39.     dw  0000001100000000b       ;5
  40.     dw  0000001100000000b
  41.     dw  0000001100000000b
  42.     dw  0
  43.     dw  0000011000000000b       ;6
  44.     dw  0000011100000000b
  45.     dw  0000001100000000b
  46.     dw  0
  47.     dw  0000011100000000b       ;7
  48.     dw  0000011100000000b
  49.     dw  0000001100000000b
  50.     dw  0
  51.     dw  0000000000000000b       ;8
  52.     dw  0000011000000000b
  53.     dw  0000011000000000b
  54.     dw  0
  55.     dw  0000001100000000b       ;9
  56.     dw  0000011100000000b
  57.     dw  0000011000000000b
  58.     dw  0
  59.     dw  0000011000000000b       ;a
  60.     dw  0000011000000000b
  61.     dw  0000011000000000b
  62.     dw  0
  63.     dw  0000011100000000b       ;b
  64.     dw  0000011100000000b
  65.     dw  0000011000000000b
  66.     dw  0
  67.     dw  0000000000000000b       ;c
  68.     dw  0000011100000000b
  69.     dw  0000011100000000b
  70.     dw  0
  71.     dw  0000001100000000b       ;d
  72.     dw  0000011100000000b
  73.     dw  0000011100000000b
  74.     dw  0
  75.     dw  0000011000000000b       ;e
  76.     dw  0000011100000000b
  77.     dw  0000011100000000b
  78.     dw  0
  79.     dw  0000011100000000b       ;f
  80.     dw  0000011100000000b
  81.     dw  0000011100000000b
  82.     dw  0
  83.  
  84.     .code
  85. ;--------------------------------------------------------------------
  86. ; void Scale2to3(char far*,char far*,short,short);
  87. ;--------------------------------------------------------------------
  88.     public  Scale2to3
  89. Scale2to3  proc uses si di ds,pIn:PTR,pOut:PTR,nBytes:WORD,InvFlg:Word
  90. LOCAL   OuterCnt:WORD
  91. S23_0:
  92.     mov ax,nBytes   ;get number of bytes in input line
  93.     mov OuterCnt,ax ;set outer loop count
  94.     mov dx,ax       ;mult AX by 3/2 and put result in DX
  95.     shr ax,1        ;div AX by 2
  96.     jnc S23_10      ;if carry, then there is a fractional
  97.     inc ax      ;  bytein the result, so inc for it
  98. S23_10: add dx,ax       ;save # of bytes in output line in dx
  99.                     ;fill the output buffer with 0
  100.     mov cx,dx       ;multiply output line size by 3
  101.     shl cx,1
  102.     add cx,dx
  103.     mov bx,cx       ;save CX to test for odd value later
  104.     shr cx,1        ;divide CX by 2 to get word count
  105.     les di,pOut     ;get pointer to output buffer
  106.     sub ax,ax       ;get fill value
  107.     rep stosw
  108.     test    bl,1        ;see if extra byte to fill
  109.     jz  S23_15
  110.     stosb
  111. S23_15: mov ax,@data
  112.     mov ds,ax
  113.     mov si,offset MapTbl
  114.     mov cl,13       ;amount to shift initial output value
  115.             ;top of loop that processes a byte of input
  116.             ; register usage:
  117.             ;  AX = input data and output data
  118.             ;  BX = ofset into map table
  119.             ;  CH = inner loop counter
  120.             ;  CL = shift count for this output group
  121.             ;  DX = size of output line
  122.             ;  DS:SI pointer to map table
  123.             ;  ES:DI pointer to output word
  124. S23_30: les di,pIn      ;get pointer to 1st input line
  125.     mov ah,byte ptr es:[di] ;get data from line 1
  126.     add di,nBytes
  127.     mov al,byte ptr es:[di] ;get data from line 2
  128.  
  129.     test    InvFlg,0ffffh   ;see if we need to invert
  130.     jz  S23_35
  131.     not ax
  132. S23_35: mov ch,4        ;do 4 2-bit segments in next loop
  133.     mov es,word ptr pOut+2  ;get segment address of output
  134. S23_40: rol ax,2        ;bits we want are in 0,1,8,9
  135.     push    ax
  136.     and ax,303h     ;mask out other bits
  137.     shl ah,2        ;move bits from 8,9 to 10,11
  138.     or  al,ah       ;or them into al
  139.     sub ah,ah       ;clear ah
  140.     shl ax,3        ;ax now has offset into enlarge table
  141.     mov bx,ax
  142.  
  143.     mov ax,[si+bx]  ;get output value
  144.     rol ax,cl       ;shift it
  145.     mov di,word ptr pOut
  146.     or  es:[di],ax  ;or into output
  147.     
  148.     add di,dx       ;get pointer to line 2 of output
  149.     mov ax,[si+bx+2]    ;get output value
  150.     rol ax,cl       ;shift it
  151.     or  es:[di],ax  ;or into output
  152.  
  153.     add di,dx       ;get pointer to line 3 of output
  154.     mov ax,[si+bx+4]    ;get output value
  155.     rol ax,cl       ;shift it
  156.     or  es:[di],ax  ;or into output
  157.  
  158.     pop ax
  159.             ;adjust the shift count for the output data
  160.             ;and the output pointer, if necessary
  161.     cmp cl,1        ;see if we need to bump output pointer
  162.     ja  S23_60      ;jump if just need to adjust count
  163.                 ;CL is either 0 or 1 so it must become
  164.                 ; either 13 or 6, respectively
  165.                 ; NOTE: we are later going to sub 3
  166.                 ;       so set CL what we want + 3
  167.     mov cl,9        ;assume CL was 1
  168.     je  S23_50      ;jump if CL=1
  169.     mov cl,16       ;opps! guessed wrong so make it 13
  170.     inc word ptr pOut   ;when CL goes from 0 to 13, need to
  171.                 ; bump the output pointer by 2
  172. S23_50: inc word ptr pOut   ;increment output pointer
  173. S23_60: sub cl,3
  174.     dec ch      ;decrement inner loop counter
  175.     jnz S23_40      ;jump to inner loop if not 0
  176.  
  177.     inc word ptr pIn    ;increment input pointer
  178.     dec OuterCnt    ;decrement outer loop counter
  179.     jnz S23_30
  180.  
  181.     ret
  182. Scale2to3   endp
  183.     end
  184.  
  185.  
  186.  
  187.  
  188. [LISTING TWO]
  189.  
  190. /*******************************************************************
  191.  * PCXHP.H  by Greg Pickles -- Header file for FAX image print program.
  192.  *******************************************************************/
  193.  
  194. typedef struct {        // This struct passes control information.
  195.     SHORT sXpos;        // x pos for image on page in pixels
  196.     SHORT sYpos;        // y pos for image on page in pixels
  197.     SHORT sInv;         // TRUE to invert image
  198.     SHORT sEndAdjust;   // number of bytes at end of a raster line to adjust 
  199.                         // because they are beyond the end of the actual image
  200.     SHORT sAdjOffset;   // offset in line of first byte to adjust
  201.     UCHAR ucMask;       // mask to OR in to the first byte that is
  202.                         //  adjusted (image may end in middle of byte)
  203. } OPTIONS;      
  204. typedef struct {          // This struct is the PCX file header.
  205.     UCHAR  ucPcxId;                // PCX ID, always 0x0a
  206.     UCHAR  ucVer;                  // PCX version
  207.     UCHAR  ucEncMeth;              // 1 = run length
  208.     UCHAR  ucBPP;                  // bits per pixel
  209.     USHORT usUpLeftX, usUpLeftY;   // position of upper left corner
  210.     USHORT usLoRightX, usLoRightY; // position of lower right corner
  211.     USHORT usDispXRes, usDispYRes; // resolution of display
  212.     UCHAR  aucPalette[48];         // palette data
  213.     UCHAR  ucRes;
  214.     UCHAR  ucNumPlanes;            // number of bit planes of data
  215.     USHORT usBytePerLine;          // # bytes in an raster line
  216.     UCHAR  ucRes2[60];
  217. } PCX_HDR;
  218.  
  219. /*-------------- Function prototypes-------------------------------------*/
  220. int PCXToHP(char*, FILEBUFFER*, OPTIONS*);
  221. void usage(void);
  222. PCX_HDR *PcxReadHeader(PCX_HDR*, FILEBUFFER*);
  223. void pcx_print_header(PCX_HDR*);
  224. UCHAR *pcx_alloc_line(PCX_HDR*, SHORT);
  225. int PcxReadLines(PCX_HDR*, UCHAR*, FILEBUFFER*, SHORT, OPTIONS*);
  226. UCHAR *pcx_test_line(PCX_HDR*, UCHAR*, SHORT, SHORT);
  227. UCHAR *ScanNE(UCHAR*, UCHAR, int);
  228. int IndexNE(UCHAR*, UCHAR, int);
  229. int CntREQ(UCHAR*, UCHAR, int);
  230. int main(int, char**);
  231.  
  232. void Scale2to3(char far*,char far*,short,short);
  233.  
  234.  
  235.  
  236.  
  237. [LISTING THREE]
  238.  
  239. /*******************************************************************
  240.  * PCXHP.C  by Greg Pickles --- FAX to LaserJetII image print program.
  241.  *******************************************************************/
  242. #include <stdio.h>
  243. #include <stdlib.h>
  244. #include <string.h>
  245. #include <memory.h>
  246. #include <malloc.h>
  247. #include <fcntl.h>
  248. #include <io.h>
  249. #include <sys\types.h>
  250. #include <sys\stat.h>
  251. #include <conio.h>
  252.  
  253. #include "bufio.h"
  254. #include "pcxhp.h"
  255.  
  256. /*******************************************************************
  257.  * PCXToHP -- Process a PCX file. Returns 0 if successful, non-0  if error
  258.  *  pszFileName   :  pointer to the input file name
  259.  *  pstrcOutFile  :  pointer to output file buffer structure
  260.  *  pstrcOpt      :  pointer to OPTIONS struc for processing this file
  261.  *******************************************************************/
  262. int PCXToHP(char *pszFileName, FILEBUFFER *pstrcOutFile, OPTIONS *pstrcOpt)
  263. FILEBUFFER  *pstrcInFile;
  264. PCX_HDR     strcHdr;
  265. SHORT       i, k, sXsize, sYsize, sLineBytes, sExpLineSize;
  266. UCHAR       *pucLine, *pucExpBuf;
  267. int         iCurX = -1, iCurY = -1;
  268. int         iNewX, iNewY, iFront, iBack;
  269. char        szFileName[80];
  270. char        szHpLineLead[20];
  271. char        szHpPos[50];
  272.                           // these strings are for building PCL4 commands
  273. static  char    szPosFmtFXYO [] = "\x01b*p%dx%dY\x01b*r1A";
  274. static  char    szPosFmtY    [] = "\x01b*p%dY";
  275. static  char    szGrDataFmt  [] = "\x01b*b%dW";
  276. static  char    szEndGr      [] = "\x01b*rB";
  277. static  char    szRes300     [] = "\x01b*t300R";
  278.     
  279.   strcpy(szFileName, pszFileName);       // make local copy of name
  280.   if (strchr(szFileName,'.') == NULL)    // add .PCX if needed
  281.     strcat(szFileName,".pcx");         
  282.   // allocate input file buffer and open file, using my buffered I/O routines
  283.   if ( (pstrcInFile=FileOpen(szFileName,0)) == NULL )
  284.     return 1;
  285.   if (PcxReadHeader(&strcHdr,pstrcInFile) == NULL)   {
  286.     fprintf(stderr,"Error reading PCX header in file '%s'\n",
  287.             szFileName);
  288.     close(pstrcInFile->hFile);
  289.     return 3;
  290.     }
  291.   if (strcHdr.ucNumPlanes != 1) {
  292.     fprintf(stderr,"Error: Not a monochrome PCX file.\n");
  293.     close(pstrcInFile->hFile);
  294.     return 5;
  295.     }
  296.            // extract size of line, compute number of rows,
  297.            // allocate buffer for 2 input lines
  298.   sLineBytes = strcHdr.usBytePerLine;
  299.   sYsize = strcHdr.usLoRightY - strcHdr.usUpLeftY + 1;
  300.   pucLine = malloc(2*sLineBytes);
  301.               // determine whether any bits/bytes need to be masked
  302.               // at the end of a decompressed line
  303.   sXsize = (strcHdr.usLoRightX - strcHdr.usUpLeftX + 1);
  304.   if ( sXsize/8 < sLineBytes ) {
  305.     pstrcOpt->sEndAdjust = sLineBytes - sXsize/8;
  306.     pstrcOpt->sAdjOffset = sXsize/8;
  307.     pstrcOpt->ucMask = (UCHAR) (0xff >> sXsize%8);
  308.   }
  309.               // compute length of scaled line and allocate buffer
  310.   sExpLineSize = strcHdr.usBytePerLine + (strcHdr.usBytePerLine/2) +
  311.                 ((strcHdr.usBytePerLine & 1) ? 1 : 0);
  312.   pucExpBuf = malloc(sExpLineSize*3);
  313.               // set HP graphics resolution to 300 DPI
  314.   BufWrite(pstrcOutFile,szRes300, strlen(szRes300));
  315.               // init position on page    
  316.   iNewX = pstrcOpt->sXpos;
  317.   iNewY = pstrcOpt->sYpos;
  318.  
  319.   for (i=0; i<sYsize; i+=2)  {
  320.     if ( !PcxReadLines(&strcHdr, pucLine, pstrcInFile, 2, pstrcOpt) )
  321.       break;
  322.     Scale2to3(pucLine,pucExpBuf,sLineBytes,pstrcOpt->sInv);
  323.  
  324.     for (k=0; k<3; k++)  {
  325.       if ((iFront=IndexNE(pucExpBuf+k*sExpLineSize,0,sExpLineSize)) >= 0) {
  326.         iNewX = pstrcOpt->sXpos + iFront*8;
  327.         iBack=CntREQ(pucExpBuf+(k+1)*sExpLineSize-1,0,sExpLineSize);
  328.         if (iNewX != iCurX) {
  329.           sprintf(szHpPos,szPosFmtFXYO,iNewX,iNewY);
  330.           BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
  331.           iCurX = iNewX;
  332.           iCurY = iNewY;
  333.           }
  334.         else if (iNewY != iCurY) {
  335.           sprintf(szHpPos,szPosFmtY,iNewY);
  336.           BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
  337.           iCurY = iNewY;
  338.           }
  339.                 // note: a possible optimization is to remember the previous 
  340.                 // leadin string, value of iFront, and leadin string length 
  341.                 // and only create them when they change
  342.         sprintf(szHpLineLead,szGrDataFmt, sExpLineSize-iFront-iBack);
  343.  
  344.         BufWrite(pstrcOutFile,szHpLineLead,strlen(szHpLineLead));
  345.         BufWrite(pstrcOutFile,pucExpBuf+k*sExpLineSize+iFront,
  346.                     sExpLineSize-iFront-iBack);
  347.         iCurY++;
  348.         }
  349.       iNewY++;
  350.       }
  351.     }
  352.   BufWrite(pstrcOutFile,szEndGr,strlen(szEndGr));
  353.   BufWrite(pstrcOutFile,"\f",1);
  354.   free(pucLine);
  355.   free(pucExpBuf);
  356.   FileClose(pstrcInFile);
  357.   return 0;
  358. }
  359. /*******************************************************************/
  360. void usage(void)    // displays help info about usage, return to system
  361. {
  362.   printf("PCXHP\n");
  363.   printf("  Given a .PCX file, this program creates a file which can be\n");
  364.   printf("   sent to an HP LaserJet printer to print the image.\n");
  365.   printf(" PCXHP [-xX] [-yY][-d] [-i] [-ofilename] filename\n");
  366.   printf("   Options include:               (units)              [default]\n");
  367.   printf("   -xPOS  set horizontal position (pixels from left)   [0]\n");
  368.   printf("   -yPOS  set vertical position   (pixels from bottom) [0]\n");
  369.   printf("   -d     dump PCX file info to stdout                 [off]\n");
  370.   printf("   -i     sInv image                                 [off]\n");
  371.   printf("   -oFIL  set output filename, or use SET PCXHP=filename\n");
  372.   exit(1);
  373. }
  374. /*******************************************************************
  375.  * PcxReadHeader -- Reads the header of a PCX file. Returns NULL if can't.
  376.  *******************************************************************/
  377. PCX_HDR *PcxReadHeader(PCX_HDR *pstrcHdr, FILEBUFFER *pstrcF)
  378. { lseek(pstrcF->hFile,0L,SEEK_SET);
  379.   if (read(pstrcF->hFile,(char*)pstrcHdr,sizeof(PCX_HDR))
  380.           != sizeof(*pstrcHdr))
  381.           return NULL;
  382.   else    return pstrcHdr;
  383. }
  384. /*******************************************************************
  385.  * PcxReadLines         --- returns TRUE if success, FALSE if out of data
  386.  *  Reads and expands the next  N line from the PCX file.  Assumes
  387.  *  that the file pointer is positioned at the point in the file at
  388.  *  which to begin reading.  Performs data expansion as necessary.
  389.  *  pstrcHdr   :     pointer to PCX header struct for the file
  390.  *  pbLine     :     pointer to the buffer in which to put lines
  391.  *  pstrcF     :     pointer to the opened FILEBUFFER for the file
  392.  *  sLines     :     number of lines to read and expand
  393.  *******************************************************************/
  394. int PcxReadLines(PCX_HDR *pstrcHdr, UCHAR *pucLine, FILEBUFFER *pstrcF,
  395.                  SHORT sLines, OPTIONS *pstrcOpt)
  396. {
  397. int     iData, iData2;
  398. UCHAR   *pucDst, *pucLineStart;
  399. USHORT  usLSize = pstrcHdr->usBytePerLine;
  400. int     i, j;
  401.   for (j=0, pucDst=pucLine; j<sLines; j++)  {
  402.     for (i=0, pucLineStart=pucDst; i<usLSize; )    {
  403.               // if we get EOF on the first line, return FALSE
  404.               // to indicate we're done, otherwise fill the
  405.               // rest of the lines with 0xff (i.e. blank)
  406.       if ((iData=GetBufCh(pstrcF)) == EOF)    {
  407.         if ( (j > 0) || (i > 0) )  {
  408.           memset(pucDst,0xff,usLSize-i);
  409.           i = usLSize;
  410.           pucDst += (usLSize-i);
  411.           }
  412.         else
  413.           return FALSE;
  414.         }
  415.       else   {
  416.         if ((iData & 0xc0) == 0xc0) {     // check for run length
  417.               // read data to be repeated; if EOF, return FALSE
  418.           if ((iData2=GetBufCh(pstrcF)) == EOF)
  419.             return FALSE;
  420.           memset(pucDst, (UCHAR)iData2, iData & 0x3f);
  421.           pucDst += iData & 0x3f;
  422.           i += iData & 0x3f;
  423.         }
  424.     else {
  425.           *pucDst++ = (UCHAR)iData;
  426.           i++;
  427.           }
  428.         }
  429.       }
  430.     if (i=pstrcOpt->sEndAdjust) {
  431.       pucLineStart += pstrcOpt->sAdjOffset;
  432.       *pucLineStart |= pstrcOpt->ucMask;
  433.       while (--i)
  434.         *(++pucLineStart) = 0xff;
  435.       }
  436.     }
  437.   return TRUE;
  438. }
  439. /*******************************************************************
  440.  * IndexNE -- Scans a buffer for the first byte not equal to a specified byte.
  441.  *  pbBuf           pointer to the buffer to test
  442.  *  bVal            value to test for
  443.  *  iCount          number of bytes to test
  444.  *  Returns: -1 if the buffer contains only the specified byte
  445.  *  otherwise offset of the first byte that is not the specified byte
  446.  *******************************************************************/
  447. int IndexNE(UCHAR *bBuf, UCHAR bVal, int iCount)
  448. { int iOrig = iCount;
  449.   while (iCount && (*bBuf == bVal)) {  iCount--;  bBuf++;  }
  450.   if (iCount)    return iOrig-iCount;
  451.   return -1;
  452. }
  453. /*******************************************************************
  454.  * CntREQ -- Counts the number of bytes equal to a specified byte from a
  455.  *  starting point in memory backwards.
  456.  *  pbBuf    :       pointer to the (end of the) buffer to test
  457.  *  bVal     :       value to test for
  458.  *  iCount   :       number of bytes to test
  459.  *  Returns number of bytes found that are equal to the specified byte
  460.  *******************************************************************/
  461. int CntREQ(UCHAR *bBuf, UCHAR bVal, int iCount)
  462. { int iOrig = iCount;
  463.   while (iCount && (*bBuf == bVal)) { iCount--; bBuf--; }
  464.   return iOrig-iCount;
  465. }
  466. /*******************************************************************/
  467. int main(int argc, char *argv[])
  468. {
  469. int i;
  470. FILEBUFFER  *OutFile;
  471. char    *outfname = NULL;
  472. char    *filename = NULL;
  473. static OPTIONS Opt = {0,0,TRUE,0,0,0};
  474.   if (argc < 2) usage();
  475.   for (i=1; i<argc; i++)  {
  476.     if (argv[i][0] == '-' || argv[i][0] == '/')
  477.       switch (toupper(argv[i][1]))
  478.         {
  479.         case 'X':  Opt.sXpos = atoi(argv[i]+2); break;
  480.         case 'Y':  Opt.sYpos = atoi(argv[i]+2); break;
  481.         case 'I':  Opt.sInv = !Opt.sInv;        break;
  482.         case 'O':  outfname=argv[i]+2;          break;
  483.         case '?':  usage();                     break;
  484.         default:  fprintf(stderr, "Unknown option %s\n",argv[i]);
  485.                   usage();                      break;
  486.         }
  487.       else
  488.         filename = argv[i];
  489.     }
  490.   if ( (outfname == NULL) && ((outfname = getenv("PCXHP")) == NULL) )
  491.     outfname = "prn";
  492.   if ( (OutFile=FileOpen(outfname,1)) == NULL )  exit(1);
  493.   i = PCXToHP(filename, OutFile, &Opt);
  494.   FileClose(OutFile);
  495.   return i;
  496. }
  497.  
  498.