/*****************************************************************************/ /* */ /* grxprint.cc : Output of graphics on printer from GRX graphic library */ /* Version 0.5 (beta) 98/01/26 Andris Pavenis (pavenis@acad.latnet.lv) */ /* - Initial version */ /* */ /* Version 0.51 98/02/18 A.Pavenis */ /* - Fixes to allow to work under Linux (still printing to file only) */ /* */ /* Version 0.52 98/02/24 A.Pavenis */ /* - Changed name of function from GrDoPrinting to GrPrintToFile */ /* - Added function GrDoPrinting(void) that prints to prn in MS-DOS */ /* and pipes output to lpr in Linux */ /* - Some other small changes, such as saving current video driver in */ /* GrSetPrintMode and restoring it from GrDoPrinting */ /* or GrPrintToFile */ /* */ /* Version 0.6 98/02/28 A.Pavenis */ /* - Many changes and fixed bugs, e.g. the mirror image was */ /* printed */ /* */ /* Version 0.61 98/03/03 A.Pavenis */ /* - Fixed problem when printing directly to printer (DJGPP version). */ /* The opened file was opened in text mode (old bug in libc). */ /* A workaround for this problem is used */ /* - Get rid of most of warnings that appears with -Wall */ /* */ /* Version 0.65 98/03/09 A.Pavenis */ /* - Changed GrPrintToFile() under Linux. Now GrPrintToFile("|lpr") */ /* is equivalent to GrDoPrinting(); */ /* */ /* Version 0.66 98/05/07 H.Schirmer */ /* - minor changes for Watcom support */ /* made cpp # start on first column */ /* */ /* Version 0.67 98/05/10 H.Schirmer */ /* - eleminated C++ style comments for better portability */ /* */ /* Version 0.68 98/05/13 H.Schirmer */ /* - clean source for better portability / ANSI-C conformance */ /* */ /* Version 0.7 98/05/14 A.Pavenis */ /* - internal procedures that are used only from this file are */ /* defined static and the definitions are removed from prn000.h */ /* - changed restoring previous state after printing to avoid */ /* unnecessary autodetection of video driver */ /* */ /* This code is port of part of printer BGI driver */ /* (C) 1990-1995 Ullrich von Bassewitz (see copying.uz). */ /* Only the code of printing itself is ported. */ /* */ /* Full version of printer BGI driver version 4.0 can be found */ /* at URL ftp://ftp.musoftware.com/pub/uz/printerbgi+src.zip */ /* An alternate URL is http://www.lanet.lv/~pavenis/printerbgi+src.zip */ /* */ /*****************************************************************************/ /* >>>>> We need to configure this code on Unix like systems <<<<< >>>>> for popen(), ... <<<<< */ #if defined(__MSDOS__) # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(__WATCOMC__) && !defined(__DJGPP__) && !defined(__WIN32__) #include #endif static short InitDone=0; static short Mode=-1; /* Print mode to be used */ static GrColor numGrxColors; /* Number of colors for GRX to use */ static int MaxX=0, MaxY=0; static long AspectRatio=10000L; static jmp_buf PrintAborted; /****************************************************************************/ /* Extern deklarierte Variable */ /****************************************************************************/ /* Die Farbtabelle wird (da nicht verwendet) als Moeglichkeit zur Einstellung */ /* von diversen Daten von aussen benutzt. Sie heisst daher nicht ColorTable */ /* (wie im SVGA-Treiber), sondern Settings (fuer die aktuelle Tabelle) und */ /* DefaultSettings (fuer die Default-Einstellungen). */ static struct GrPrintOptionsType DefaultSettings = { 0, /* Output quality, 0 --> keypad setting */ /* 1 --> draft */ /* 2 --> high */ 0, /* Shingling, 0 --> normal */ /* 1 --> 25% (2 pass) */ /* 2 --> 50% (4 pass) */ 1, /* Depletion 0 --> none */ /* 1 --> 25% */ /* 2 --> 50% */ 0 /* Media type, 0 --> Plain paper */ /* 1 --> Bond paper */ /* 2 --> Special paper */ /* 3 --> Glossy film */ /* 4 --> Transparency film */ }; /* Die folgenden Farbtabelle wird als Einstellungstabelle "missbraucht" */ static struct GrPrintOptionsType Settings = { 0, /* Output quality, 0 --> keypad setting */ /* 1 --> draft */ /* 2 --> high */ 0, /* Shingling, 0 --> normal */ /* 1 --> 25% (2 pass) */ /* 2 --> 50% (4 pass) */ 1, /* Depletion 0 --> none */ /* 1 --> 25% */ /* 2 --> 50% */ 0 /* Media type, 0 --> Plain paper */ /* 1 --> Bond paper */ /* 2 --> Special paper */ /* 3 --> Glossy film */ /* 4 --> Transparency film */ }; /* RGB-Palette */ static struct RGBEntry RGBPal [256]; /* Der Zeiger auf die aktuelle DST */ static struct _DST * DSTPtr = NULL; /*****************************************************************************/ /* Prototypes of internal procedures */ /*****************************************************************************/ static BOOLEAN InitPrinter (BYTE *Buf, int BufSize, int Handle); /* Stellt das Ausgabegeraet auf "binary" um und prueft gleichzeitig, ob */ /* das Handle 4 ok (offen) ist. Der aktuelle Zustand wird gemerkt und bei */ /* Post wiederhergestellt. Buf wird als Puffer fuer die Ausgabe verwendet */ /* und muss PrintBufSize Bytes gross sein, Handle ist das Handle auf das */ /* ausgegeben wird. */ static void ResetPrinter (void); /* Stellt den orginalen Zustand des Ausgabegeraets wieder her. */ static void Flush (void); /* Schreibt den Ausgabepuffer leer. Muss am Ende eines Ausdrucks */ /* aufgerufen werden. Springt PrintAbortLabel an bei Fehlern. */ static void PrintByte (BYTE B); /* Gibt ein Byte auf den Drucker (bzw. in den Ausgabepuffer) aus. */ /* Springt PrintAbortLabel an bei Fehlern. */ static void PrintData (BYTE * Data, unsigned Size); /* Gibt Daten auf den Drucker (bzw. in den Ausgabepuffer) aus. */ /* Springt PrintAbortLabel an bei Fehlern. */ static void PrintString (char * S); /* Gibt einen Pascal-String auf den Drucker (bzw. in den Ausgabepuffer) aus.*/ /* Springt PrintAbortLabel an bei Fehlern. */ static void PrintZString (char * S); /* Gibt einen nullterminierten String auf den Drucker (bzw. in den */ /* Ausgabepuffer) aus. Springt PrintAbortLabel an bei Fehlern. */ /****************************************************************************/ /* */ /* Interne Variablen */ /* */ /****************************************************************************/ /* Default-Palette fuer die ersten Eintraege */ static struct RGBEntry RGBDefPal [8] = { { 0, 0, 0 }, /* Black */ { 255, 0, 0 }, /* Red */ { 0, 255, 0 }, /* Green */ { 255, 255, 0 }, /* Yellow */ { 0, 0, 255 }, /* Blue */ { 255, 0, 255 }, /* Magenta */ { 255, 255, 0 }, /* Cyan */ { 255, 255, 255 } /* White */ }; static GrVideoDriver * PrevDrv = NULL; int GrPrintSetMode ( int _mode_ ) { int rc; unsigned I; struct RGBEntry * P; PrevDrv = GrDriverInfo->vdriver; Mode = _mode_; if (Mode<0 || Mode>MaxModes) return -1; /* Check mode range */ if (DSTTable[Mode]==0) return -1; DSTPtr = DSTTable[Mode]; MaxX = (int) ((((long) (DSTPtr->XDPI))*((long) (DSTPtr->XInch)))/1000L); MaxY = (int) ((((long) (DSTPtr->YDPI))*((long) (DSTPtr->YInch)))/1000L); AspectRatio = (long) ((10000L*DSTPtr->YDPI)/DSTPtr->XDPI); if (DSTPtr->ColorBits==1) numGrxColors=2; else if (DSTPtr->ColorBits<=4) numGrxColors=16; else if (DSTPtr->ColorBits<=8) numGrxColors=256; else numGrxColors=256; /* Palette initialisieren, erste 8 Eintraege wie beim DeskJet */ memcpy (RGBPal, RGBDefPal, sizeof (RGBDefPal)); /* Rest der Palette mit Grautoenen vorbesetzen */ I = sizeof (RGBDefPal) / sizeof (struct RGBEntry); P = &RGBPal [I]; while (I < sizeof (RGBPal) / sizeof (struct RGBEntry)) { P->R = P->G = P->B = I; P++; I++; } rc = GrSetDriver ("memory"); if (rc==TRUE) { rc = GrSetMode (GR_width_height_color_graphics, MaxX, MaxY, numGrxColors); InitDone = 1; } return rc; } int GrPrintToFile (const char * DestFile) { int handle; # ifdef __MSDOS__ handle = creat (DestFile,S_IREAD+S_IWRITE); if (!handle) return -1; if (DSTPtr) (DSTPtr->Print) (DSTPtr,handle); close (handle); GrSetMode (GR_default_text); # else FILE * output; if (*DestFile=='|') output = popen (DestFile+1,"w"); else output = fopen (DestFile ,"w"); if (!output) return -1; handle = fileno (output); if (DSTPtr) (DSTPtr->Print) (DSTPtr,handle); if (*DestFile=='|') pclose (output); else fclose (output); # endif if (PrevDrv) GrSetDriver (PrevDrv->name); else DRVINFO->vdriver = NULL; return 0; } int GrDoPrinting (void) { int handle; # ifdef __MSDOS__ handle = creat ("prn",S_IREAD+S_IWRITE); if (!handle) return -1; # else FILE * output = popen ("lpr","w"); if (!output) return -1; handle = fileno (output); # endif if (DSTPtr) (DSTPtr->Print) (DSTPtr,handle); # ifdef __MSDOS__ close (handle); # else pclose (output); # endif GrSetMode (GR_default_text); if (PrevDrv) GrSetDriver (PrevDrv->name); else DRVINFO->vdriver = NULL; return 0; } void GrPrintGetAspectRatio ( unsigned * x , unsigned * y ) { *x = AspectRatio; *y = 10000U; } /*****************************************************************************/ /* NP.CPP */ /* */ /* */ /* (C) 1994 by Ullrich von Bassewitz */ /* Zwehrenbuehlstrasse 33 */ /* 72070 Tuebingen */ /* */ /* E-Mail: uz@ibb.schwaben.de */ /* */ /* Port of printing code to DJGPP */ /* Revision 0.5 98/01/26 Andris Pavenis (pavenis@acad.latnet.lv) */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Printing on dot matrix printers */ /* */ /*****************************************************************************/ /* */ /* */ /* Anmerkung zur Speicheraufteilung: Die urspruengliche Speicheraufteilung */ /* wurde so geaendert, dass sich alle Bytes einer Druckerspalte (also bis */ /* zu 3 bei einem 24-Nadler) linear hintereinander im Speicher befinden. */ /* Dadurch ergibt sich ein wesentlich schnellerer Ausdruck, da eine */ /* komplette Zeile mit Druckdaten am Stueck im Speicher steht. */ /* */ /* Die Berechnung fuer Adresse und Pixel erfolgt nach folgenden Formeln: */ /* */ /* Pixelmaske im Byte: */ /* */ /* PixelMask = 0x01 << (7 - (X % 8)); */ /* */ /* bzw. (bei Reverse) */ /* */ /* PixelMask = 0x01 << (X % 8); */ /* */ /* Lineare Adresse des Bytes in dem das Pixel steht (Achtung: die Formel */ /* kann _nicht_ vereinfacht werden, d.h. es darf nichts weggekuerzt werden, */ /* da es sich um Ganzzahlarithmetik handelt). */ /* */ /* X */ /* Abs = -------------- * MaxY * ColBytes */ /* 8 * ColBytes */ /* */ /* */ /* + (MaxY - Y - 1) * ColBytes */ /* */ /* */ /* X % (8 * ColBytes) */ /* + -------------------- */ /* 8 */ /* */ /****************************************************************************/ /* Drucker-Ausgaberoutinen */ /****************************************************************************/ void EpsonPrint ( struct _DST * DSTPtr , int PRNHandle ) /* Universelle Drucker-Routine fuer Nadeldrucker */ { /* ** Steuerstrings fuer EPSON/NEC P6 Farbe. Diese sind bisher fest ** eincodiert, da die Drucker alle dieselben Steuerstrings haben. ** ACHTUNG: Zwei der Bit-Ebenen sind vertauscht um eine dem DeskJet ** aehnliche Farb-Verteilung zu erhalten. ** Alle Steuerstrings enthalten zusaetzlich zuerst einen Wagenruecklauf. */ static char *ColorSel [4] = { "\x04\r\x1Br\x02", /* Bit 0 = Cyan */ "\x04\r\x1Br\x01", /* Bit 1 = Magenta */ "\x04\r\x1Br\x04", /* Bit 2 = Gelb */ "\x04\r\x1Br\x00" /* Bit 3 = Schwarz */ }; WORD X, Y, EndX; BYTE Bytes, Pass, PassCount, ColBytes, ColorBits, Bits; DWORD Abs; /*DWORD A;*/ /*BYTE Buf [6]; */ /* Maximale Groesse: ColBytes(max) * PassCount(max) */ /*BYTE PrintBuf [3];*/ /* Maximale Groesse: ColBytes(max) */ /*int I,J,K;*/ char Reverse; int MaxX = GrSizeX(); int MaxY = GrSizeY(); unsigned char *Buffer[4]; /* Where to create buffer for printing */ unsigned char *Curr[4] , Mask; char OrVal[4]; int i, j, k, l, c, X1; int PlaneSize, BufSize; struct EpsonDST * dst = (struct EpsonDST *) DSTPtr; /* Handle auf "raw data" umstellen. Direkt Ende wenn Handle nicht Ok */ BYTE * OutputBuf = (BYTE *) malloc (PrintBufSize); assert (OutputBuf!=0); if (InitPrinter (OutputBuf, PrintBufSize, PRNHandle) == FALSE) return; /* Vor Beginn der Druck-Ausgabe jetzt das Sprunglabel fuer Druckerfehler */ /* setzen. */ if (setjmp(PrintAborted)!=0) { /* Fehler! */ return; } PrintString (dst->GraphicsOn); /* Variablen-Init */ Abs = 0L; PassCount = dst->PassCount; ColBytes = dst->ColBytes; ColorBits = DSTPtr->ColorBits; Bytes = ColBytes * PassCount; EndX = MaxX / (ColBytes * 8); Reverse = DSTPtr->Flags & pfReverse; X = 0; PlaneSize = ((int) ColBytes)*MaxY; BufSize = PlaneSize*ColorBits; Buffer[0] = (unsigned char *) malloc (BufSize); if (Buffer[0]==0) { fprintf(stderr,"Not enough memory\n"); longjmp(PrintAborted,-1); } for (i=1; i=0 ? (GrPixelNC (xPos,Y)) : 0; /* Insert color conversion here if needed */ X1 += PassCount; for (l=0; l>= 1; } for (l=0; l 1) PrintString (ColorSel [Bits]); PrintString (dst->PreBytes); PrintData (Buffer[Bits], PlaneSize); PrintString (dst->PostBytes); } } if (Pass == (PassCount - 1)) PrintString (dst->LineFeed1); else PrintString (dst->LineFeed2); } X += PassCount*ColBytes*8; Flush (); } /* Grafik beenden, Puffer leeren */ Flush (); ResetPrinter (); free (Buffer[0]); free (OutputBuf); } /****************************************************************************/ /* */ /* LaserJet/DeskJet-Ausgaberoutinen fuer BGI-Druckertreiber */ /* */ /****************************************************************************/ /* */ /* (C) 1990-1993 Ullrich von Bassewitz */ /* */ /* Port to printing code to DJGPP */ /* Revision 0.5 1998/01/26 Andris Pavenis (pavenis@acad.latnet.lv) */ /* This code is not yet optimized and is rather slow espacially for */ /* color printing. Tested on HP LaserJet 4L (Modes HPLJ_300x300, */ /* HPLJ_300x300_NC) and on HP DeskJet 690C (Mode HPDJ500C_300x300x8_B). */ /* Other modes are not tested. */ /* */ /* $Id: lj.cpp 2.10 1995/04/28 16:20:46 Uz Exp $ */ /* */ /* $Log: lj.cpp $ */ /* Revision 2.10 1995/04/28 16:20:46 Uz */ /* Umstellung auf PCX-Treiber. */ /* */ /* Revision 2.9 95/04/22 17:32:48 Uz */ /* Diverse Aenderungen, Funktionen LaserPrint und LJPrint zusammengefasst, */ /* Anpassungen an geaenderte Struktur von _DST und Support fuer DeskJet */ /* 1200C mit einstellbarer Palette. */ /* */ /* Revision 2.8 94/09/08 14:14:38 Uz */ /* Kleinere Aenderungen zur Einsprung von ein paar Bytes. */ /* */ /* Revision 2.7 94/09/08 09:32:52 Uz */ /* Anpassung an extra modedata Modul. */ /* */ /* Revision 2.6 94/03/29 20:44:54 Uz */ /* str.h anstelle von string.h verwendet */ /* */ /* Revision 2.5 94/03/19 16:16:51 Uz */ /* Cleanup und Kosmetik. */ /* */ /* Revision 2.4 94/01/13 11:32:50 Uz */ /* Ausdruck erweitert um schaltbare Schwarzabtrennung */ /* fuer DeskJet 550C. */ /* */ /* Revision 2.3 93/08/01 20:53:05 Uz */ /* Neues Format mit DPMI-Support */ /* */ /****************************************************************************/ /* Controlstrings zur Ansteuerung des LJ */ /****************************************************************************/ /* defining LJ_LANDSCAPE_MODE changes order of data data output to */ /* printer to more effectively use memory organization of GRX frame drivers */ /* Unfortunatelly I was not able to remove some shift of image so part */ /* of it was not printed (top was shifted down by about 6 mm) */ /* (A.Pavenis) */ /*#define LJ_LANDSCAPE_MODE*/ /* Drucker-Kontrollstrings */ #ifndef LJ_LANDSCAPE_MODE static char InitString [] = "\x1B""E" /* Reset Printer */ "\x1B*rbC" /* End Raster Graphics */ "\x1B&l26A" /* Format: DIN A4 */ "\x1B&l0o" /* Portrait orientation */ "0L"; /* perf.-skip off */ #else static char InitString [] = "\x1B""E" /* Reset Printer */ "\x1B*rbC" /* End Raster Graphics */ "\x1B&l26A" /* Format: DIN A4 */ "\x1B&l1o" /* Landscape orientation */ "\x1B*r0F" /* Follows orientation */ "\x1B&l6D" /* Vertical line spacing */ "\x1B&l0E" /* Top margin 0 */ "\x1B*p0Y" /* Y position is 0 */ "\x1B*p0Y\x1B*p0X" /* Cursor position 0,0 */ "0L"; /* perf.-skip off */ #endif static char ColorString1 [] = "\x1B*r-3U"; /* 3 planes, CMY palette */ static char ColorString2 [] = "\x1B*r-4U"; /* 4 planes, KCMY palette */ static char ColorString3 [13] = "\x0B" /* Stringlaenge */ "\x1B*v6W" /* CID Command */ "\x00" /* Device RGB */ "\x00" /* Indexed by plane */ "\x00" /* Bits/Index (wird spaeter gesetzt) */ "\x08\x08\x08"; /* 8 Bits per Primary */ static char Quality [3][6] = { "\x1B*r0Q", /* Use keypad setting */ "\x1B*r1Q", /* draft */ "\x1B*r2Q" /* high */ }; static char Shingling [3][6] = { "\x1B*o0Q", /* None */ "\x1B*o1Q", /* 25% (2 pass) */ "\x1B*o2Q" /* 50% (4 pass) */ }; static char Depletion [3][6] = { "\x1B*o1D", /* None */ "\x1B*o2D", /* 25% (default) */ "\x1B*o3D" /* 50% */ }; static char MediaType [5][6] = { "\x1B&l0M", /* Plain paper */ "\x1B&l1M", /* Bond paper */ "\x1B&l2M", /* Special paper */ "\x1B&l3M", /* Glossy film */ "\x1B&l4M" /* Transparency film */ }; #ifdef LJ_LANDSCAPE_MODE static char StartGraphics [] = "\x1B*r1A"; /* Start graphics */ /* "\x1B&a1N"; */ /* No negative motion (DeskJet 1200C) */ #else static char StartGraphics [] = "\x1B*r0A"; /* Start graphics*/ /* "\x1B&a1N"; */ /* No negative motion (DeskJet 1200C) */ #endif /* Steuerstring zur Einstellung der Palette.*/ static char RGBCompStr [] = "\x03" /* Stringlaenge */ "\x1B*v"; /* String der nach der Grafik geschickt wird. */ static char EndGraphics [] = "\x1B*rbC" /* Grafik-Ende */ "\x0C"; /* Papier-Auswurf */ /* Steuerstring fuer TIFF-Pacbits Kompression */ static char Compression [] = "\x1B*b2M"; /* Steuerstring fuer keine Kompression */ static char NoCompression [] = "\x1B*b0M"; /* Hier werden die Steuercodes fuer eine Zeile zusammengebaut. */ static char PreBytes [25] = "\x1B*b"; /****************************************************************************/ /* */ /* Kompressionspuffer und dessen Verwaltung */ /* */ /****************************************************************************/ /*#define CompBufSize 600 */ /* 600 Bytes Puffer */ #define CompBufSize 6000 /* 6000 Bytes Puffer */ static BYTE * CompBuf = 0; /* Zeiger auf Kompressionspuffer */ static WORD CompBufFill = 0; /* Anzahl Zeichen im Puffer */ static void ToBuf (BYTE B) /* Speichert das uebergebene Byte im Puffer wenn noch Platz ist. Der Zaehler */ /* wird auf jeden Fall hochgezaehlt, so dass sich spaeter die theoretische */ /* Anzahl an Bytes im Puffer auf jeden Fall feststellen laesst. */ { if (CompBufFill < (CompBufSize-1)) { /* Platz ist da, speichern */ CompBuf [CompBufFill++] = B; } } static void RepeatByte (WORD bCount, BYTE B) /* Speichert ein wiederholtes Byte im Kompressionspuffer, wobei Count die */ /* echte Anzahl ist und B das Byte. Der Zaehler wird auf Maximum */ /* ueberprueft und eventuell auf zwei oder drei verteilt. */ { int RepeatCount; while (bCount) { /* Maximal koennen 128 Bytes am Stueck geschrieben werden, wobei */ /* der Wert 0 einem Byte entspricht usw. 127 entsprechen 128 Byte */ RepeatCount = (bCount > 128) ? 128 : bCount; bCount -= RepeatCount; /* Byte schreiben */ ToBuf (-(RepeatCount-1)); ToBuf (B); } } static void MultiByte (WORD bCount, char *S) /* Speichert eine Folge von ungleichen Bytes im Kompressionspuffer, wobei */ /* Count die echte Anzahl ist und S ein Zeiger auf das erste Byte. Der */ /* Zaehler wird auf Maximum ueberprueft und die komplette Anzahl wird */ /* evtl. auf mehrere Male rausgeschrieben. */ { WORD ByteCount; while (bCount) { /* Maximal koennen 128 Bytes am Stueck geschrieben werden, wobei der */ /* Wert 0 einem Byte entspricht usw. 127 entsprechen 128 Byte */ ByteCount = (bCount > 128) ? 128 : bCount; bCount -= ByteCount; /* Bytefolge schreiben */ ToBuf (ByteCount-1); while (ByteCount--) { ToBuf (*S++); } } } static void PrintNum (WORD W) /* Gibt das Wort W vorzeichenlos in ASCII auf den Drucker aus. Zur Wandlung */ /* wird der Kompressionspuffer verwendet! */ { /*Num (W, CompBuf);*/ char numBuf[16]; /*itoa (W,numBuf,10);*/ sprintf (numBuf,"%u",(unsigned) W); PrintZString (numBuf); } /****************************************************************************/ /* Some setup functions for LaserJet and DeskJet printers */ /****************************************************************************/ static void ljSetRasterSize (int width, int height) { char cmd[32]; sprintf (cmd,"\x1B*r%dT\x1B*r%dS",height,width); PrintZString (cmd); } /*****************************************************************************/ /* */ /* Universelle Ausgaberoutine fuer den LaserJet/DeskJet/Color-DeskJet. Die */ /* Routine fuehrt die Drucker-Initialisierung ueber den uebergebenen String */ /* in Buf aus (der das passende Format haben muss, also mit fuehrendem */ /* Laengenbyte) und druckt dann den Inhalt des Speichers. Es ist Farbe */ /* moeglich (im DeskJet-Format), die passende Initialisierung muss aber in */ /* Buf stehen. Die Routine behandelt nur (falls vorhanden) die Planes */ /* korrekt. */ /* Da Buf spaeter als Komprimierungs-Puffer verwendet wird, muss er im Daten-*/ /* segment liegen (sowieso weil Zeiger) und mindestens 600 Bytes gross sein. */ /* */ /* Die Routine wurde spaeter noch erweitert um eine Moeglichkeit, die Daten */ /* auch gezwungenermassen ohne Kompression rauszuschicken. Dabei wird der */ /* Einfachheit halber die Zeile auch komprimiert, dann aber bei der */ /* Abfrage, welcher Puffer kuerzer ist, gleichzeitig das Flag ausgewertet. */ /* Die zusaetzliche Laufzeit wird hier in Kauf genommen, da diese Modi ja */ /* wohl nur eine Notloesung fuer Uralt-Drucker sein koennen. */ /* */ /* */ /* Parameter: */ /* Buf wie oben beschrieben */ /* */ /* Ergebnisse: */ /* (keine) bzw. hoffentlich ein Ausdruck... */ /* */ /*****************************************************************************/ void LaserPrint ( struct _DST * DSTPtr , int PRNHandle ) { int i,rc; int X, Count, FullCount, Len, Plane, A, PlaneCount; int RowBytes; unsigned I; BYTE B, *S; BOOLEAN SeparateBlack; BYTE *OutputBuf=0 , *Buf=0; int *PX=0; /*int *PXCurr;*/ struct RGBEntry *P; int MaxX = GrSizeX(); int MaxY = GrSizeY(); /* Variablen-Init */ volatile enum {Unknown, Compressed, NotCompressed} CompStatus = Unknown; OutputBuf = (BYTE *) malloc (PrintBufSize); # ifdef LJ_LANDSCAPE_MODE PX = (int *) calloc (MaxX,sizeof(int)); # else PX = (int *) calloc (MaxY,sizeof(int)); # endif /* Bytes pro (Plane-) Zeile berechnen */ # ifdef LJ_LANDSCAPE_MODE RowBytes = MaxX / 8; # else RowBytes = MaxY / 8; # endif /* Dynamischen Speicher fuer die Puffer belegen */ Buf = (BYTE *) malloc (RowBytes); CompBuf = (BYTE *) malloc (CompBufSize); /* Vor Beginn der Druck-Ausgabe jetzt das Sprunglabel fuer Druckerfehler */ /* setzen. */ if ((rc=setjmp (PrintAborted))==0) { /* Handle auf "raw data" umstellen. Direkt Ende wenn Handle nicht Ok*/ /* ACHTUNG: Ab hier Ausstieg mit return nicht mehr zulaessig, es */ /* muss goto Exit verwendet werden. */ if (OutputBuf==0 || PX==0) longjmp (PrintAborted,-1); if (InitPrinter (OutputBuf, PrintBufSize, PRNHandle) == FALSE) { longjmp (PrintAborted,-2); } if (Buf==0 || CompBuf==0) longjmp (PrintAborted,-1); /* Variable aus DST zwischenspeichern */ SeparateBlack = hasSeparateBlack (DSTPtr); /* Anzahl der Farb-Ebenen rechnen. Diese entspricht der Anzahl der */ /* Farb-Bits mit Ausnahme der Modi mit Schwarz-Abtrennung, hier */ /* kommt eine Plane dazu. */ PlaneCount = DSTPtr->ColorBits; if (SeparateBlack) PlaneCount++; /* Ausgabe der Initialisierungs-Sequenzen */ PrintZString (InitString); # ifdef LJ_LANDSCAPE_MODE ljSetRasterSize (MaxX, MaxY); # else ljSetRasterSize (MaxY, MaxX); # endif if (DSTPtr->ColorCount == 8) { /* DeskJet Farbe, Schwarz-Abtrennung hat 4 Ebenen, sonst 3 */ PrintZString (hasSeparateBlack (DSTPtr) ? ColorString2 : ColorString1); } else if (DSTPtr->ColorCount > 8) { /* Deskjet 1200C, Farbmodell und Palette setzen */ ColorString3 [8] = DSTPtr->ColorBits; PrintString (ColorString3); /* Zeiger auf die Palette */ P = RGBPal; /* Alle Eintraege setzen */ for (I = 0; I < DSTPtr->ColorCount; I++) { /* Steuerstring zum Setzen des Eintrags */ PrintString (RGBCompStr); PrintNum (P->R); PrintByte ('a'); PrintNum (P->G); PrintByte ('b'); PrintNum (P->B); PrintByte ('c'); PrintNum (I); PrintByte ('I'); /* Naechster Eintrag */ P++; } } PrintZString (((struct LJDST *) DSTPtr)->GraphicsOn); PrintZString (Quality [djQuality]); if (DSTPtr->ColorCount >= 8) { /* Farb-Deskjets */ PrintZString (Shingling [djShingling]); PrintZString (Depletion [djDepletion]); } if (DSTPtr->ColorCount > 8) { /* Nur Deskjet 1200C */ PrintZString (MediaType [djMediaType]); } PrintZString (StartGraphics); /* Ausgabe beginnt */ /*for (X = 0; X < MaxX; X++) {*/ # ifdef LJ_LANDSCAPE_MODE for (X = 0; X < MaxY; X++) { for (Count = 0; Count= 0; X--) { for (Count = 0; Count=MaxX) break; # else if (Y>=MaxY) break; # endif px = PX[Y]; /* GrPixelNC (X,Y); */ if ((px & 7)==7) { Buf[Count] |= Mask; PX[Y] = 0; /* GrPlotNC (X,Y,0); */ } Mask >>= 1; } } } else { /* Es handelt sich um eine ganz normale Farb-Ebene...*/ int cmask = 1 << ((SeparateBlack ? Plane-1 : Plane)-1); for (Count = 0; Count < RowBytes; Count++) { unsigned char Mask = 0x80; int Y = Count<<3; Buf[Count] = 0; for (i=0; i<8; i++) { int px; # ifdef LJ_LANDSCAPE_MODE if (Y>=MaxX) break; # else if (Y>=MaxY) break; # endif px = PX[Y]; /* GrPixelNC (X,Y); */ if (px & cmask) Buf[Count] |= Mask; Mask >>= 1; Y++; } } } /* Pruefen, wieviele Bytes am Ende des Puffers Null-Bytes sind */ S = Buf + RowBytes; FullCount = RowBytes; while (FullCount>0 && *(--S)==0) FullCount--; /* Versuchen die Zeile nach Algorithmus 2 (TIFF Pacbits) zu */ /* komprimieren. Abgeschickt wird dann der kuerzere der beiden */ /* Puffer. */ S = Buf; Count = FullCount; /* Anzahl zu pruefender Bytes */ CompBufFill = 0; /* Puffer ist leer */ while (Count) { /* Erstes Byte holen */ B = *S++; Count--; A = 1; if (Count) { /* Es kommen noch Bytes */ if (*S == B) { /* Das naechste ist gleich, zaehlen wieviele ** gleiche kommen */ while ((Count) && (*S == B)) { A++; Count--; S++; } /* Abschicken */ RepeatByte (A, B); } else { /* Das naechste ist ungleich, zaehlen wieviele ** ungleiche kommen */ while ((Count) && (*S != B)) { A++; Count--; B = *(S++); } /* Wenn Count nicht 0 ist, dann sind die Bytes an ** Position S und S-1 gleich, koennen also beim ** naechsten Durchgang mit einer RepeatByte-Sequenz ** dargestellt werden. In diesem Fall wird der letzte ** Durchgang wieder rueckgaengig gemacht. */ if (Count) { S--; A--; Count++; } /* Abschicken */ MultiByte (A, (char *) (S-A)); } } else { /* Es kommen keine Bytes mehr, das letzte Byte als ** Einzelbyte schicken */ MultiByte (1, (char *) (S-1)); } } /* Sodele, den kuerzeren der beiden Puffer abschicken. Hier auch ** pruefen ob eine Kompression ueberhaupt gewuenscht ist... */ if (CompBufFill < FullCount && DoCompression (DSTPtr)) { /* Der komprimierte Puffer ist kuerzer, Kontrollstring zur */ /* Festlegung der Kompression senden, falls diese nicht */ /* schon eingestellt ist. */ if (CompStatus != Compressed) { CompStatus = Compressed; PrintZString (Compression); } FullCount = CompBufFill; S = CompBuf; } else { /* Der unkomprimierte Puffer ist kuerzer, Kontrollstring zur*/ /* Festlegung der Kompression schicken, falls diese nicht */ /* schon eingestellt ist. */ if (CompStatus != NotCompressed) { CompStatus = NotCompressed; PrintZString (NoCompression); } S = Buf; } /* Die Steuersequenz fuer die nicht leeren Zeichen zusammenbauen. ** Beachten, dass sich die letzte Plane in Code von den vorigen ** unterscheidet. */ sprintf (&PreBytes[3],"%u",(unsigned) FullCount); /*Num (FullCount, &PreBytes [3]); */ Len = strlen (PreBytes); PreBytes [Len] = (Plane == PlaneCount) ? 'W' : 'V'; PreBytes [Len+1] = '\0'; /* Steuersequenz und dann die Zeichen senden */ PrintZString (PreBytes); /* Puffer folgt */ PrintData (S, FullCount); } } /* Das war's, Grafik beenden und Puffer leeren */ PrintZString (EndGraphics); Flush (); } else switch (rc) { case -1: fprintf (stderr,"LaserPrint(): Memory allocation failed\n"); break; case -2: fprintf (stderr,"LaserPrint(): Error writing output file\n"); break; } /* Bei Fehlern geht's hier raus */ /* Handle wieder in den Orginalzustand versetzen */ if (OutputBuf) free(OutputBuf); if (Buf) free(Buf); if (PX) free(PX); if (CompBuf) { free(CompBuf); CompBuf=0; } ResetPrinter (); } void GrPrintGetDefaultOptions ( struct GrPrintOptionsType * opt ) { *opt=DefaultSettings; } void GrPrintGetCurrentOptions ( struct GrPrintOptionsType * opt ) { *opt=Settings; } void GrPrintSetOptions ( struct GrPrintOptionsType * opt ) { Settings.Quality = opt->Quality<0 || opt->Quality>2 ? 0 : opt->Quality; Settings.Shingling = opt->Shingling<0 || opt->Shingling>2 ? 0 : opt->Shingling; Settings.Depletion = opt->Depletion<0 || opt->Depletion>2 ? 1 : opt->Depletion; Settings.MediaType = opt->MediaType<0 || opt->MediaType>4 ? 0 : opt->MediaType; } /****************************************************************************/ /* */ /* Modul fuer BGI-Treiber zum Ansprechen des Druckers */ /* */ /****************************************************************************/ /* */ /* (C) 1990-1993 Ullrich von Bassewitz */ /* */ /* Port to DJGPP */ /* Revision 0.5 98/01/26 Andris Pavenis (pavenis@acad.latnet.lv) */ /* */ /* $Id: print.cpp 2.6 1995/04/28 16:21:14 Uz Exp $ */ /* */ /* $Log: print.cpp $ */ /* Revision 2.6 1995/04/28 16:21:14 Uz */ /* Umstellung auf PCX-Treiber. */ /* */ /* Revision 2.5 95/04/22 17:34:02 Uz */ /* Neue Funktionen fuer den Ausdruck, PrintZString, PrintData, kleinere */ /* Aenderungen bei existierenden Funktionen. */ /* */ /* Revision 2.4 94/09/08 14:14:51 Uz */ /* Kleinere Aenderungen zur Einsparung von ein paar Bytes. */ /* */ /* Revision 2.3 93/08/01 20:53:10 Uz */ /* Neues Format mit DPMI-Support */ /* */ /****************************************************************************/ /* */ /* Variable */ /* */ /****************************************************************************/ /* Ausgabepuffer und Deklarationen dazu */ static BYTE *OutputBuf; /* Der Puffer */ static WORD OutputBufFill = 0; /* Anzahl Zeichen im Puffer */ /* Handle auf das geschrieben wird */ static WORD OutputHandle = 4; /* Merker fuer die Flags des Printer-Devices */ WORD PrinterFlags; /****************************************************************************/ /* Code */ /****************************************************************************/ static BOOLEAN InitPrinter (BYTE * Buf, int BufSize, int Handle) /* Stellt das Ausgabegeraet auf "binary" um und prueft gleichzeitig, ob das */ /* Handle 4 ok (offen) ist. Der aktuelle Zustand wird gemerkt und bei Post */ /* wiederhergestellt. Buf wird als Puffer fuer die Ausgabe verwendet und */ /* muss PrintBufSize Bytes gross sein. ACHTUNG: Buf muss bis zum Aufruf von */ /* ResetPrinter gueltig sein! */ { /* Puffer und Handle uebernehmen */ OutputBuf = Buf; OutputBufFill = 0; # ifdef __MSDOS__ PrinterFlags = setmode (Handle,O_BINARY); # endif OutputHandle = Handle; return TRUE; } static void ResetPrinter (void) /* Stellt den orginalen Zustand des Ausgabegeraets wieder her. */ { # ifdef __MSDOS__ setmode (OutputHandle,PrinterFlags); # endif } static void Flush (void) /* Schreibt den Ausgabepuffer leer. Muss am Ende eines Ausdrucks aufgerufen */ /* werden. Springt PrintAbortLabel an bei Fehlern. */ { if (OutputBufFill > 0) { if (write (OutputHandle, OutputBuf, OutputBufFill) != OutputBufFill) { /* Fehler beim Schreiben, Fehleraussprung */ longjmp (PrintAborted, -2); } /* Puffer ist wieder leer */ OutputBufFill = 0; memset (OutputBuf,0,PrintBufSize); } } static void PrintByte (BYTE B) /* Gibt ein Byte auf den Drucker (bzw. in den Ausgabepuffer) aus. */ /* Springt PrintAbortLabel an bei Fehlern. */ { /* Pruefen ob noch Platz im Puffer ist, wenn Nein Puffer leeren */ if (OutputBufFill == PrintBufSize) { /* Puffer ist voll, leeren */ Flush (); } /* Neues Byte in den Puffer schreiben */ OutputBuf [OutputBufFill++] = B; } static void PrintData (BYTE * Data, unsigned Size) /* Gibt Daten auf den Drucker (bzw. in den Ausgabepuffer) aus. */ /* Springt PrintAbortLabel an bei Fehlern. */ { int i; for (i=0; i