roo_e/thirdparty/grx249/addons/print/grxprint.c
2022-05-16 17:59:47 -05:00

1272 lines
49 KiB
C

/*****************************************************************************/
/* */
/* 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 <io.h>
# include <dos.h>
#endif
#include <fcntl.h>
#include <grx20.h>
#include <stdio.h>
#include <assert.h>
#include <libgrx.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <grxprint.h>
#include <grxprn00.h>
#include <sys/stat.h>
#include <stddef.h>
#if !defined(__WATCOMC__) && !defined(__DJGPP__) && !defined(__WIN32__)
#include <sys/ioctl.h>
#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<ColorBits; i++) Buffer[i]=Buffer[i-1]+PlaneSize;
while (X<MaxX)
{
for (Pass=0; Pass<PassCount; Pass++)
{
memset (Buffer[0],0,BufSize); /* Clear buffer */
for (i=0; i<ColorBits; i++)
{
Curr[i] = Buffer[i];
OrVal[i] = 0;
}
for (Y=0; Y<MaxY; Y++)
{
X1 = Pass;
for (j=0; j<ColBytes; j++)
{
Mask = Reverse ? 0x01 : 0x80U;
for (k=0; k<8; k++)
{
int cMask = 0x01;
int xPos = MaxX - X - X1 - 1;
c = xPos>=0 ? (GrPixelNC (xPos,Y)) : 0;
/* Insert color conversion here if needed */
X1 += PassCount;
for (l=0; l<ColorBits; l++, cMask<<=1)
if (c & cMask)
*(Curr[l]) |= Mask;
if (Reverse) Mask <<=1; else Mask >>= 1;
}
for (l=0; l<ColorBits; l++)
{
OrVal[l] |= *((Curr[l])++);
}
}
}
for (Bits=0; Bits<ColorBits; Bits++)
{
if (OrVal[Bits])
{
/* Falls mehr als eine Farbe existiert, */
/* jetzt Farbe umschalten */
if (ColorBits > 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<MaxX; Count++) {
PX[Count] = GrPixelNC (Count,X);
}
# else
for (X = MaxX-1; X >= 0; X--) {
for (Count = 0; Count<MaxY; Count++) {
PX[Count] = GrPixelNC (X,Count);
}
/*GrReadVLineC (GrScreenContext(),X,PX);*/
# endif
/* Daten fuer alle Ebenen ausgeben */
for (Plane = 1; Plane <= PlaneCount; Plane++) {
/*
** Bytes in den Kompressionspuffer lesen. Wenn es sich um
** einen Modus mit Schwarz-Abtrennung handelt, wird die erste
** Plane aus den drei anderen zusammengestellt, die Schwarz-Bits
** werden in den anderen Planes geloescht und zwar direkt im
** Bildschirmspeicher (problemlos, weil nach dem Ausdruck die
** Zeichenflaeche leer ist).
*/
if (SeparateBlack && Plane == 1) {
/* Schwarz-Ebene zusammenstellen. */
for (Count = 0; Count < RowBytes; Count++)
{
/* Je ein Byte aus den drei Ebenen holen */
/*Y = *Map (Abs);*/
/*C = *Map (Abs + RowBytes);*/
/*M = *Map (Abs + 2 * RowBytes);*/
unsigned char Mask = 0x80;
Buf[Count] = 0;
/* This code contains support of 8 color modes only !!! */
for (i=0; i<8; i++) /* Remove black */
{
int Y, px;
Y = (Count<<3)+i;
# ifdef LJ_LANDSCAPE_MODE
if (Y>=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<Size; i++)
PrintByte (Data[i]);
}
static void PrintString (char * S)
/* Gibt einen Pascal-String auf den Drucker (bzw. in den Ausgabepuffer) aus. */
/* Springt PrintAbortLabel an bei Fehlern. */
{
if (S) PrintData ((unsigned char *) (S+1), *S);
}
static void PrintZString (char * S)
/* Gibt einen nullterminierten String auf den Drucker (bzw. in den */
/* Ausgabepuffer) aus. Springt PrintAbortLabel an bei Fehlern. */
{
PrintData ((unsigned char * ) S, strlen (S));
}