Logo Search packages:      
Sourcecode: lexmark7000linux version File versions

pbm2l7k.c

/*
 * pbm2l7k.c -- convert monochromatic PBMraw file into Lexmark 7000
 *              printing escape sequences
 *              Usage: ./pbm2l7k < file.pbm > /dev/lp1
 *              
 * (C) 1999 Henryk Paluch, released under GNU GPL license, version 2
 * 
 * $Id: pbm2l7k.c,v 1.24 1999/03/28 18:08:49 henryk Exp $
 */

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h> /* getopt() */
#include<syslog.h>

/* this will be model dependent section */
enum LX_MODELS { LXM_7000=0,LXM_5700,LXM_LAST};
int lx_model=0; /* current selected Lexmark pritner model */
                /* temporarily set to 5700 */

struct lx_smodel{
   char printer_name[16];
   char prologoue_name[64];
};

struct lx_smodel lx[]={{"Lexmark 7000","pr7000.prn"},
                            {"Lexmark 5700","pr5700.prn"}};



#define DIV8(x) ( (x) >> 3 )
#define MOD8(x) ( (x) & 0x7 )

#define BLINES (lines)
                      /* offset for B&W printing */
#define CLINES (lines)
                      /* offset for Cyan plate */
#define MLINES (lines+(1*pheight*width))
                      /* offset for Magenta plate */
#define YLINES (lines+(2*pheight*width))
                      /* offset for Yellow plate */
#define KLINES (lines+(3*pheight*width))
                      /* offset for additional K (black) plate */

int height;                 /* height of PBM bitmap (lines e.g., pixels) */
int width;                  /* width of line bitmap + LR_MARGINS 
                       * (in bytes)
                       */
int bwidth;                 /* real bitmap width (bytes) */
int lr_shift8;              /* LEFT-RIGHT shift (bytes) */
int pheight;                /* height of one color plate */
                            /* aligned to VERTSIZE or st similar... */
int psize;            /* plate size */
unsigned char *lines=NULL; /* this is pixel buffer for one pass */
int plates;              /* number of color plates:
                      * 1 = traditional Black & White
                      * 3 = CMY
                      * 4 = CMYK
                      */
int passheight;          /* 192 for B&W or 192/3=64 for CMY colour */
int mayeof;

/*printing constants*/
const int  TOP_MARGIN=0x100;
const int  LEFT_MARGIN=50;
const int  VERT_SHIFT=0x180;  /* paper shift betwen printed lines */
const int  LR_SHIFT=16; /* distance betwen two series of Left & Right
                     inkjets */

const int VCOL_SPACE=12; /* vertical space between two colors */


/* number of vertical lines printed in one pass 
 * Lexmark 7000 has (probably) 2 series of 12 * 8 = 96 InkJets
 * e.g. total 2 * 96 = 192 is height (in pixels) printed in one pass
 *
 * don't change this, unless you know what you are doing!
 */
const int VERTSIZE=192;

/* offsets to print line sequence (defined in outbuf)
 */
const int IDX_SEQLEN=5;
const int IDX_PACKETS=13;
const int IDX_HSTART=15;
const int IDX_HEND=17;
const int IDX_DATA=26;
const int IDX_CARTRIDGE=10;

#define OUT_BUF_SIZE 65535
/* most important print packet
 * see lexmarkprotocol.txt for more information */
/*          length of complete sequence ---  vvvvvvvvv */
char outbuf[OUT_BUF_SIZE]={0x1B,0x2A,0x04,0x00,0x00,0xFF,0xFF,
   /* number of packets ----     vvvvvvvvv */ 
   0x00,0x02,0x01,0x01,0x1A,0x11,0xFF,0xFF,
   /* horiz start, horiz end: packets = (horiz end - horiz start) +1 */
   0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x22,0x33,0x44,0x55,0x01};

/* fast_cat() - just emulates cat
 *              writes 'filename' to stdout
 *              Used to print captured prologue 'prolog.prn' to printer
 */
void fast_cat(char *filename)
{
  FILE *f;
  char buf[1024];
  int n;

  if ( (f=fopen(filename,"r"))==NULL )
  {
      syslog(LOG_INFO,"fopen '%s': %s\n",filename,strerror(errno));
      perror("fopen");
      exit(-1);
  }
  while (  (n=fread(buf,1,1024,f))>0)
    if ( fwrite(buf,1,n,stdout)!=n)
    {
      perror("fwrite or short write");
      exit(-1);
    }
 fclose(f);
}

/*  parse_pbm_header() - decodes header of PBM bitmap
 *        sets global vars: height (pixels), 
 *                          bwidth (real bitamp width - bytes)
 *                          width  (memory bitmap width - bytes)
 *        PBMraw is simple monochromatic bitmap. It consists
 *        of text header and raw data bytes.
 *        Example: P4
 *                 # comment lines
 *                 width height
 *                 raw bytes
 *                 
 *                 width & height is in pixels, lines are byte aligned
 *                 0x80 is most left bit, 0x1 most right
 */
int parse_pbm_header(FILE *f,int *width, int *height)
{
   char buf[1024];
   
   if (fgets(buf,1023,f)==0  || strncmp(buf,"P4",2)!=0)
   {
      if (mayeof)
       return 0;
      else
      {
       fprintf(stderr,"Illegal pbmraw header"); 
       exit(-1);
      }
   }
   do{
   fgets(buf,1023,f); /* skip comment line(s) */
   }while(buf[0]=='#');

   sscanf(buf,"%d %d\n",width,height);
   if ( (*width) <=0 || (*height) <=0)
   {
      fprintf(stderr,"Illegal width (%d) or height (%d)\n",*width,*height);
      exit(-1);
   }
   return 1;

  return 1;
}

/* paper_shift() -- shift paper in printer -- units are unknown :-)
 */
void paper_shift(int offset)
{
   unsigned char buf[5]={0x1b,0x2a,0x3,0x0,0x0};
   buf[3]=(unsigned char)(offset >> 8);
   buf[4]=(unsigned char)(offset & 0xFF);
   if (fwrite(buf,1,5,stdout)!=5)
   {
     fprintf(stderr,"paper_shift: short write\n");
     exit(-1);
   }
}

/* paper_eject() -- self explaining
 */
void paper_eject(void)
{
   unsigned char buf[4]={0x1b,0x2a,0x7,0x65};
   if (fwrite(buf,1,4,stdout)!=4)
   {
     fprintf(stderr,"paper_shift: short write\n");
     exit(-1);
   }
}

/* read_lines() -- read 'readcount' data lines from PBM bitmap
 *                 to 'lines' -- bitmap in memory
 */

int read_lines(FILE *f,int readcount)
{
   int i,c;

   if (lines==NULL)
      lines=(char*)malloc(width*VERTSIZE);
   /* zero the buffer */
   memset(lines,(char)0,width*VERTSIZE);
   for(i=0;i<readcount;i++)
   {
      c=fread(lines+lr_shift8+width*i,1,bwidth,f);
      if (c==-1)
      {
       perror("fread");
       exit(-1);
      }
      if (c<bwidth)
       return c;
   }
   return c;
}

void read_plate(FILE *f,unsigned char *buf)
{
   int i,c;
   memset(buf,(char)0,psize);
   for(i=0;i<height;i++)
   {
      c=fread(buf+lr_shift8+width*i,1,bwidth,f);
      if (c==-1)
      {
       perror("fread");
       exit(-1);
      }
      if (c<bwidth)
      {
       fprintf(stderr,"read_plate: short read\n");
       exit(-1);
      }
   }
}  
   

/* are_lines_empty() -- return true, if all VERTSIZE 'lines' are
 *                      empty => nothing to print => only paper shift
 */
int are_lines_empty(unsigned char *buf)
{
   int i;
   for(i=0;i<width*passheight;i++)
      if (buf[i]!=0)
       return 0;
   return 1;
}

/*  is_col_empty() -- true, if column 'col' (in pixels) is empty
 */
int is_col_empty(int col,unsigned char *buf) /* col is now in pixels! */
{
   unsigned char mask[8]={128,64,32,16,8,4,2,1};
   int i;
   unsigned char *bofs, *bofs2;
   unsigned char mmask, mmask2;
   mmask=mask[MOD8(col)];
   mmask2=mask[MOD8(col+LR_SHIFT)];
   bofs=buf+DIV8(col);
   bofs2=buf+width+DIV8(col+LR_SHIFT);

   for(i=0;i<passheight/2;i++)
   {
      if ( ( bofs[0] & mmask)!=0 ) /* left series */
       return 0;
/*      if (col+LR_SHIFT<width*8) */
        if ( (bofs2[0] & mmask2)!=0 ) /* right series */
          return 0;
      bofs+=width*2; /* aaddres + 2 lines */
      bofs2+=width*2;
   }
   return 1;
}

/*   find_horiz_ofsets() -- returns horizontal offsets for printing
 *   (e.g. left = 1st pixel on the left, right= last pixel on the row
 *   
 */
void find_horiz_ofsets(int *left,int *right,unsigned char *buf)
{
   int i;
   *left=0;
   *right=width*8-LR_SHIFT; /* left & right is in pixels (bits) now! */
   for(i=0;i<width*8;i++)
   {
      if (!is_col_empty(i,buf))
      {
       *left=i;
       break;
      }
   }
   for(i=width*8-LR_SHIFT-1;i>=0;i--)
      if (!is_col_empty(i,buf))
      {
       *right=i+1;
       break;
      }
}

/*   print_cols() -- most important -- print complete graphics line
 *                   in one pass
 *                   now 600x600dpi, but note, that we must handle
 *                   two series of distant ink jets (distance is
 *                   in (LR_SHIFT)
 */
int print_cols(int left,int right,int vstart, int vend,unsigned char *buf,
      int color)
{
   unsigned char mask[8]={128,64,32,16,8,4,2,1};
   unsigned int masq[12]={2048,1024,512,256,128,64,32,16,8,4,2,1};
   int l8,r8,packets;
   char *p=outbuf+IDX_DATA;
   int clen;
   int i,j,k,m;
   char *tbits;
   int bits;
   int byte;
   int word;
   unsigned char vbuf[VERTSIZE/2]; // Always corresponds to VERTSIZE !!!
   unsigned char *vp,*vp2;
   int smask,smask2;
   
   l8=left+LEFT_MARGIN;
   r8=right+LEFT_MARGIN;

   packets=r8-l8+1;
   
   if (lx_model==LXM_5700)
      outbuf[IDX_PACKETS-1]=0x1; /* Why is 5700 so different, ugh? */

   outbuf[IDX_PACKETS]  =(unsigned char)(packets >> 8);
   outbuf[IDX_PACKETS+1]=(unsigned char)(packets & 0xFF);
   outbuf[IDX_HSTART]   =(unsigned char)(l8 >> 8);
   outbuf[IDX_HSTART+1] =(unsigned char)(l8 & 0xFF);
   outbuf[IDX_HEND]     =(unsigned char)(r8 >> 8);
   outbuf[IDX_HEND+1]   =(unsigned char)(r8 & 0xFF);
   
   outbuf[IDX_CARTRIDGE]= (unsigned char)( color ? 0 : 1 );
   /* fill columns */
   for(i=left;i<right;i++)
   {
      if ( (p-outbuf)>=OUT_BUF_SIZE-26 ) /* 12*2+2 */
      {
       return -1;
      }
       if (is_col_empty(i,buf))
       {
          *(p++)=0x3F;
          *(p++)=0xFF; /* whole column is empty */
       }
       else
       {
          *(p++)=0x3F;
          tbits=p;
          *tbits=0; /* here will be nice bitmap */
          p++;
          bits=0;
          
          /* clear buffer of vertical points */
          memset(vbuf,0,VERTSIZE/2);
          vp=buf+DIV8(i);
                /* vp points to current column for Left Ink */
          vp2=buf+width+DIV8(i+LR_SHIFT);
                /* vp2 for right Ink jets */
          smask=mask[MOD8(i)];
          smask2=mask[MOD8(i+LR_SHIFT)];
          for(k=vstart;k<vend;k++)
          {
             if ( ( vp[0] & smask) != 0)
              vbuf[k] |= 1;
             if (i+LR_SHIFT<width*8)
             {
                if ( (vp2[0] & smask2) !=0 )
                 vbuf[k] |=2;
                 vp2+=width*2;
             }
             vp+=width*2;
          }

          /* every packet contains 12 info bits
           * 1 = 8x left white, 8x right white
           * 0 = 2 data bytes follow (8 bits left, 8 bits right)
           */

          for(k=0;k<12;k++)
          {
             for(m=0;m<8;m++)
              if ( vbuf[k*8+m]!=0 )
                 break;
             if(m==8)
             { /* 8vertical bits are empty */
             bits= (bits<<1);
            bits+=1; 
             }
             else
             {
              bits= (bits<<1);
              byte=0;
              for(m=0;m<8;m++)
              {
                 byte= (byte << 1);
                 if ( (vbuf[k*8+m] & 1) != 0 )
                  byte+=1;
                 byte= (byte << 1);
                 if ( (vbuf[k*8+m] & 2) != 0 )
                  byte+=1; 
              }
              *(p++)= ((byte>>8) & 0xFF);
              *(p++)= ( byte & 0xFF);
             }
          }
          word=0;
          for(m=0;m<12;m++)
          {
             word= (word << 1);
             if ( bits & masq[11-m])
              word +=1;
          }
          *tbits=(unsigned char)( (word) & 0xFF);
          *(tbits-1)=(unsigned char)( ((word>>8) & 0xf) | 0x30 );
       }
   }
   
   
   /* ------------ */
   clen=p-outbuf; 
   outbuf[IDX_SEQLEN]  =(unsigned char)(clen >> 8);
   outbuf[IDX_SEQLEN+1]=(unsigned char)(clen & 0xFF);
   if ( fwrite(outbuf,1,clen,stdout)!=clen)
   {
      fprintf(stderr,"print_cols: short write\n");
      exit(-1);
   }
   return 0;
}

static void usage(void)
{
   int i;
   fprintf(stderr,"Lexmark 7000 printer driver for Linux\n\n");
   fprintf(stderr,"Usage: pbm2l7k [ -h ] [ -m mode ]"
                " < input.pbmraw > output.prn\n");
   fprintf(stderr,"       -h\tthis help text\n");
   fprintf(stderr,"       -c\tprint in CMY colour mode - "
                " assume 3pbmbitmaps generated by pnm2cmykraw\n");
   fprintf(stderr,"       -m mode\tspecifies printer driver:\n");
   for(i=0;i<LXM_LAST;i++)
      fprintf(stderr,"       -m %d\t%s\n",i,lx[i].printer_name);
   fprintf(stderr,"\n default mode is: [%d] %s\n",
       lx_model,lx[lx_model].printer_name);
   exit(-1);
}

int main(int argc, char *argv[])
{
   int i,linepairs;
   int left,right;
   int elinescount=0;
   int rlines;
   int c;
   int pmode;
   int pagecount=0;
   int twopasscount=0;
   
   plates=1;
   while( (c=getopt(argc, argv, ":m:hc"))!=-1 )
      switch(c){
       case 'h':
          usage();
          break;
       case 'm':
          pmode=atoi(optarg);
          if (pmode<=0 || pmode>=LXM_LAST)
          {
             fprintf(stderr,"Invalid mode '%d' specified,"
                 " must be between <0,%d>\n", pmode, LXM_LAST-1);
             exit(-1);
          }
          lx_model=pmode;
          break;
       case 'c':
          plates=3; /* CMY color mode */
          break;
       default:
          usage();
      }
   

   openlog("pbm2l7k", LOG_PID|LOG_PERROR, LOG_LPR);
   syslog(LOG_INFO,"$Id: pbm2l7k.c,v 1.24 1999/03/28 18:08:49 henryk Exp $ started\n");
   syslog(LOG_INFO,"Using driver: '%s'\n",lx[lx_model].printer_name);
   fprintf(stderr,"Using driver for '%s', prologue file '%s'\n",
       lx[lx_model].printer_name,
       lx[lx_model].prologoue_name);
   /* write out printer prolog */
//   fast_cat(lx[lx_model].prologoue_name);

   /* process raw PBM bitmap(s) */
   while(parse_pbm_header(stdin,&width,&height))
   {
      mayeof=1;
      bwidth= (width+7) /8; /* round width to whole byte */
      fprintf(stderr,"bwidth (bytes): %d (%d pixels), height (lines): %d\n",
       bwidth,bwidth*8, height);
      lr_shift8=(LR_SHIFT+8)/8;
      width=bwidth+2*lr_shift8;
      fprintf(stderr,"width: %d (%d pixels)\n",width,width*8);
 

      if (plates==1)
      {
       passheight=192;
      }
      else
      {
       passheight=192/3;
      }

     linepairs=(height+passheight-1)/passheight;
     pheight=linepairs*passheight;
     if (plates>1)
      pheight+=3*passheight; // add space for more colors
     psize=pheight*width;
      
      elinescount=TOP_MARGIN; /* initial paper shift */

      fprintf(stderr,"There will be %d pairs of %d lines\n",
          linepairs,passheight);
      fprintf(stderr,"Plate height is %d pixels\n",pheight);
      fprintf(stderr,"Plate size is %d bytes\n",psize);
      fprintf(stderr,"Allocating %d bytes for %d plates\n",psize*plates,plates);
      lines=(unsigned char*)malloc(psize*plates);

      read_plate(stdin,lines);
      for(i=1;i<plates;i++) /* read additional color plates if needed */
      {
       int tmp1,tmp2;
       parse_pbm_header(stdin,&tmp1,&tmp2);
       read_plate(stdin,lines+(i*psize));
      }

      for(i=0;i<linepairs;i++)
      {
       if (plates==1)
       { /* Black & White printing mode */
          unsigned char *bbuf;
          bbuf=BLINES+(i*width*passheight);
          if (!are_lines_empty(bbuf))
          {
             if (elinescount!=0)
             {
              paper_shift(elinescount);
              elinescount=0;
             }
             find_horiz_ofsets(&left,&right,bbuf);
             fprintf(stderr,"offsets (pixels): left: %d, right %d\n",left,right);
             if (print_cols(left,right,0,VERTSIZE/2,bbuf,0)==-1)
             {
              print_cols(left,right,0,VERTSIZE/4,bbuf,0);
              print_cols(left,right,VERTSIZE/4,VERTSIZE/2,
                  bbuf+192/2*width,0);
              twopasscount++;
             }

          }
          else
          {
             fprintf(stderr,"64 empty lines\n");
          }
          elinescount+=VERT_SHIFT;
       }
       if (plates==3){
          /* color printing (now CMY mode only) */
          /* handle yellow now */
          unsigned char *ybuf;
          unsigned char *mbuf;
          unsigned char *cbuf;
          ybuf=YLINES+(i*width*passheight+(2*64+2*VCOL_SPACE)*width); /* yllow is lowest */
          if (!are_lines_empty(ybuf))
          {
             if (elinescount!=0)
             {
              paper_shift(elinescount);
              elinescount=0;
             }
             find_horiz_ofsets(&left,&right,ybuf);
             fprintf(stderr,"Yellow offsets (pixels): left: %d, right %d\n",
                 left,right);
             print_cols(left,right,128/2,192/2,ybuf,1);
          }
           elinescount+=16*2; // skip small space between 2 colors
         /* now print magenta */
         mbuf=MLINES+(i*width*passheight+(1*64+VCOL_SPACE)*width); /* yllow is lowest */
           if (!are_lines_empty(mbuf))
          {
             if (elinescount!=0)
             {
              paper_shift(elinescount);
              elinescount=0;
             }
             find_horiz_ofsets(&left,&right,mbuf);
             fprintf(stderr,"Magenta offsets (pixels): left: %d, right %d\n",
                 left,right);
             print_cols(left,right,64/2,128/2,mbuf,1);
          }
           elinescount+=16*2; // skip small space between 2 colors
         /* now print cyan */
        cbuf=CLINES+(i*width*passheight); /* cyan is highest */
           if (!are_lines_empty(cbuf))
          {
             if (elinescount!=0)
             {
              paper_shift(elinescount);
              elinescount=0;
             }
             find_horiz_ofsets(&left,&right,cbuf);
             fprintf(stderr,"Cyan offsets (pixels): left: %d, right %d\n",
                 left,right);
             print_cols(left,right,0,64/2,cbuf,1);
          }
           elinescount+=32*2; // skip small space between 2 colors
       }
      }
      paper_eject();
      pagecount++;
      if (lines!=NULL)
      {
       free(lines);
       lines=NULL;
      }

   }

   syslog(LOG_INFO,"Two pass printing was used %d times to prevent"
        "line overflow\n",twopasscount);
   syslog(LOG_INFO,"printed (%d) pages\n",pagecount);
   closelog();
   return 0;
}

Generated by  Doxygen 1.6.0   Back to index