home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / grafik / giflib11 / util / gif2epsn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-03  |  20.3 KB  |  588 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.1, Jul. 1989   *
  5. ******************************************************************************
  6. * Program to dump GIF file into EPSON type printers                 *
  7. * Options:                                     *
  8. * -d factor : use dithering of matrix of size factor by factor.             *
  9. * -t level : set the threshold level of white in the result (0..100).         *
  10. * -m mapping : methods for mapping the 24bits colors into 1 BW bit.         *
  11. * -p printer : specify printer to print to (lpt1: by default).             *
  12. * -n : nice mode : uses double density to achieve better quality.         *
  13. * -i : invert the image.                             *
  14. * -h : on line help.                                 *
  15. ******************************************************************************
  16. * History:                                     *
  17. * 15 Jul 89 - Version 1.0 by Gershon Elber.                     *
  18. * 22 Dec 89 - Fix problems with const strings been modified (Version 1.1).   *
  19. *****************************************************************************/
  20.  
  21. #ifdef __MSDOS__
  22. #include <graphics.h>
  23. #include <stdlib.h>
  24. #include <alloc.h>
  25. #include <io.h>
  26. #include <dos.h>
  27. #include <bios.h>
  28. #endif /* __MSDOS__ */
  29.  
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. #include <string.h>
  33. #include <fcntl.h>
  34. #include "gif_lib.h"
  35. #include "getarg.h"
  36.  
  37. #define PROGRAM_NAME    "Gif2Epsn"
  38.  
  39. #define    C2BW_BACK_GROUND    0 /*Methods to map 24bits Colors to 1 BW bit.*/
  40. #define    C2BW_GREY_LEVELS    1
  41. #define C2BW_DITHER        2
  42. #define C2BW_NUM_METHODS    3            /* Always hold # of methods. */
  43.  
  44. #define DEFAULT_THRESHOLD    5000         /* Color -> BW threshold level. */
  45.  
  46. #define DITHER_MIN_MATRIX    2
  47. #define DITHER_MAX_MATRIX    4
  48.  
  49. /* The epson specific are defined here: */
  50. #define EPSON_WIDTH        80                /* 80 char per line. */
  51. #define EPSON_PIXEL_2_CHAR    8      /* 8 pixels per char, in REG_DENSITY. */
  52.  
  53. #define EPSON_ESC        "\033"        /* Actually regular escape char. */
  54. #define EPSON_RESET        "\033@"               /* Reset the printer. */
  55. #define EPSON_VERTICAL_SPACE    "\033A\010"         /* 8/72 inch vertically. */
  56. #define EPSON_REG_DENSITY    "\033K"          /* 640 pixels per 7.5" (line). */
  57. #define EPSON_DUAL_DENSITY    "\033L"         /* 1280 pixels per 7.5" (line). */
  58.  
  59. #ifdef __MSDOS__
  60. extern unsigned int
  61.     _stklen = 16384;                 /* Increase default stack size. */
  62. #endif /* __MSDOS__ */
  63.  
  64. #ifdef SYSV
  65. static char *VersionStr =
  66.         "Gif library module,\t\tGershon Elber\n\
  67.     (C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  68. static char
  69.     *CtrlStr = "Gif2Epsn d%-DitherSize!d t%-BWThreshold!d m%-Mapping!d i%- n%- p%-PrinterName!s h%- GifFile!*s";
  70. #else
  71. static char
  72.     *VersionStr =
  73.     PROGRAM_NAME
  74.     GIF_LIB_VERSION
  75.     "    Gershon Elber,    "
  76.     __DATE__ ",   " __TIME__ "\n"
  77.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  78. static char
  79.     *CtrlStr =
  80.     PROGRAM_NAME
  81.     " d%-DitherSize!d t%-BWThreshold!d m%-Mapping!d i%- n%- p%-PrinterName!s h%- GifFile!*s";
  82. #endif /* SYSV */
  83.  
  84. static char
  85.     *PrinterName = NULL;
  86. /* Make some variables global, so we could access them faster: */
  87. static int
  88.     ImageNum = 0,
  89.     BackGround = 0,
  90.     DitherSize = 2, DitherFlag = FALSE,
  91.     BWThresholdFlag = FALSE, Threshold,
  92.     BWThreshold = DEFAULT_THRESHOLD,       /* Color -> BW mapping threshold. */
  93.     Mapping, MappingFlag = FALSE,
  94.     InvertFlag = FALSE,
  95.     NiceFlag = FALSE,
  96.     PrinterFlag = FALSE,
  97.     HelpFlag = FALSE,
  98.     ColorToBWMapping = C2BW_BACK_GROUND,
  99.     InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should  */
  100.     InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
  101. static GifColorType
  102.     *ColorMap;
  103.  
  104. static void EvalDitheredScanline(GifRowType *ScreenBuffer, int Row,
  105.                     int RowSize, GifRowType *DitherBuffer);
  106. static void DumpScreen2Epsn(GifRowType *ScreenBuffer,
  107.                     int ScreenWidth, int ScreenHeight);
  108. static void PutString(FILE *Prt, int DirectPrint, char *Str, int Len);
  109. static void PutString2(FILE *Prt, int DirectPrint, char *Str, int Len);
  110.  
  111. /******************************************************************************
  112. * Interpret the command line and scan the given GIF file.              *
  113. ******************************************************************************/
  114. void main(int argc, char **argv)
  115. {
  116.     int    i, j, Error, NumFiles, Size, Row, Col, Width, Height, ExtCode, Count;
  117.     GifRecordType RecordType;
  118.     GifByteType *Extension;
  119.     char **FileName = NULL;
  120.     GifRowType *ScreenBuffer;
  121.     GifFileType *GifFile;
  122.  
  123.     if ((Error = GAGetArgs(argc, argv, CtrlStr, &DitherFlag, &DitherSize,
  124.         &BWThresholdFlag, &Threshold, &MappingFlag, &Mapping,
  125.         &InvertFlag, &NiceFlag, &PrinterFlag, &PrinterName, &HelpFlag,
  126.         &NumFiles, &FileName)) != FALSE ||
  127.         (NumFiles > 1 && !HelpFlag)) {
  128.     if (Error)
  129.         GAPrintErrMsg(Error);
  130.     else if (NumFiles > 1)
  131.         GIF_MESSAGE("Error in command line parsing - one GIF file please.");
  132.     GAPrintHowTo(CtrlStr);
  133.     exit(1);
  134.     }
  135.  
  136.     if (HelpFlag) {
  137.     fprintf(stderr, VersionStr);
  138.     GAPrintHowTo(CtrlStr);
  139.     exit(0);
  140.     }
  141.  
  142.     if (!PrinterFlag) PrinterName = "";
  143.  
  144.     if (DitherFlag) {
  145.     /* Make sure we are o.k.: */
  146.     if (DitherSize > DITHER_MAX_MATRIX) DitherSize = DITHER_MAX_MATRIX;
  147.     if (DitherSize < DITHER_MIN_MATRIX) DitherSize = DITHER_MAX_MATRIX;
  148.     }
  149.  
  150.     /* As Threshold is in [0..100] range and BWThreshold is [0..25500]: */
  151.     if (BWThresholdFlag) {
  152.     if (Threshold > 100 || Threshold < 0)
  153.         GIF_EXIT("Threshold not in 0..100 percent.");
  154.     BWThreshold = Threshold * 255;
  155.     if (BWThreshold == 0) BWThreshold = 1;   /* Overcome divide by zero! */
  156.     }
  157.  
  158.     /* No message is emitted, but mapping method is clipped to exists method.*/
  159.     if (MappingFlag) ColorToBWMapping = Mapping % C2BW_NUM_METHODS;
  160.  
  161.     if (NumFiles == 1) {
  162.     if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
  163.         PrintGifError();
  164.         exit(-1);
  165.     }
  166.     }
  167.     else {
  168.     /* Use the stdin instead: */
  169.  
  170. #ifdef __MSDOS__
  171.     setmode(0, O_BINARY);
  172. #endif /* __MSDOS__ */
  173.     if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
  174.         PrintGifError();
  175.         exit(-1);
  176.     }
  177.     }
  178.  
  179.     /* Allocate the screen as vector of column of rows. We cannt allocate    */
  180.     /* the all screen at once, as this broken minded CPU can allocate up to  */
  181.     /* 64k at a time and our image can be bigger than that:             */
  182.     /* Note this screen is device independent - its the screen as defined by */
  183.     /* the GIF file parameters itself.                         */
  184.     if ((ScreenBuffer = (GifRowType *)
  185.     malloc(GifFile -> SHeight * sizeof(GifRowType *))) == NULL)
  186.         GIF_EXIT("Failed to allocate memory required, aborted.");
  187.  
  188.     Size = GifFile -> SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
  189.     if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
  190.     GIF_EXIT("Failed to allocate memory required, aborted.");
  191.  
  192.     for (i = 0; i < GifFile -> SWidth; i++) /* Set its color to BackGround. */
  193.     ScreenBuffer[0][i] = GifFile -> SBackGroundColor;
  194.     for (i = 1; i < GifFile -> SHeight; i++) {
  195.     /* Allocate the other rows, andset their color to background too:   */
  196.     if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
  197.         GIF_EXIT("Failed to allocate memory required, aborted.\n");
  198.  
  199.     memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
  200.     }
  201.  
  202.     /* Scan the content of the GIF file and load the image(s) in: */
  203.     do {
  204.     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
  205.         PrintGifError();
  206.         exit(-1);
  207.     }
  208.     switch (RecordType) {
  209.         case IMAGE_DESC_RECORD_TYPE:
  210.         if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
  211.             PrintGifError();
  212.             exit(-1);
  213.         }
  214.         Row = GifFile -> ITop; /* Image Position relative to Screen. */
  215.         Col = GifFile -> ILeft;
  216.         Width = GifFile -> IWidth;
  217.         Height = GifFile -> IHeight;
  218.         fprintf(stderr, "\n%s: Image %d at (%d, %d) [%dx%d]:     ",
  219.             PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
  220.         if (GifFile -> ILeft + GifFile -> IWidth > GifFile -> SWidth ||
  221.            GifFile -> ITop + GifFile -> IHeight > GifFile -> SHeight) {
  222.             fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n");
  223.             exit(-2);
  224.         }
  225.         if (GifFile -> IInterlace) {
  226.             /* Need to perform 4 passes on the images: */
  227.             for (Count = i = 0; i < 4; i++)
  228.             for (j = Row + InterlacedOffset[i]; j < Row + Height;
  229.                          j += InterlacedJumps[i]) {
  230.                 fprintf(stderr, "\b\b\b\b%-4d", Count++);
  231.                 if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
  232.                 Width) == GIF_ERROR) {
  233.                 PrintGifError();
  234.                 exit(-1);
  235.                 }
  236.             }
  237.         }
  238.         else {
  239.             for (i = 0; i < Height; i++) {
  240.             fprintf(stderr, "\b\b\b\b%-4d", i);
  241.             if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
  242.                 Width) == GIF_ERROR) {
  243.                 PrintGifError();
  244.                 exit(-1);
  245.             }
  246.             }
  247.         }
  248.         break;
  249.         case EXTENSION_RECORD_TYPE:
  250.         /* Skip any extension blocks in file: */
  251.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
  252.             PrintGifError();
  253.             exit(-1);
  254.         }
  255.         while (Extension != NULL) {
  256.             if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
  257.             PrintGifError();
  258.             exit(-1);
  259.             }
  260.         }
  261.         break;
  262.         case TERMINATE_RECORD_TYPE:
  263.         break;
  264.         default:            /* Should be traps by DGifGetRecordType. */
  265.         break;
  266.     }
  267.     }
  268.     while (RecordType != TERMINATE_RECORD_TYPE);
  269.  
  270.     /* Lets display it - set the global variables required and do it: */
  271.     BackGround = GifFile -> SBackGroundColor;
  272.     ColorMap = (GifFile -> IColorMap ? GifFile -> IColorMap :
  273.                        GifFile -> SColorMap);
  274.     DumpScreen2Epsn(ScreenBuffer, GifFile -> SWidth, GifFile -> SHeight);
  275.  
  276.     if (DGifCloseFile(GifFile) == GIF_ERROR) {
  277.     PrintGifError();
  278.     exit(-1);
  279.     }
  280. }
  281.  
  282. /*****************************************************************************
  283. * Routine to evaluate dithered scanlines out of given ones, using Size         *
  284. * dithering matrix, starting from Row. The given scanlines are NOT modified. *
  285. *****************************************************************************/
  286. static void EvalDitheredScanline(GifRowType *ScreenBuffer, int Row,
  287.                     int RowSize, GifRowType *DitherBuffer)
  288. {
  289.     static char Dither2[2][2] = {     /* See Foley & Van Dam pp. 597-601. */
  290.     { 1, 3 },
  291.     { 4, 2 }
  292.     };
  293.     static char Dither3[3][3] = {
  294.     { 7, 9, 5 },
  295.     { 2, 1, 4 },
  296.     { 6, 3, 8 }
  297.     };
  298.     static char Dither4[4][4] = {
  299.     { 1,  9,  3,  11 },
  300.     { 13, 5,  15, 7 },
  301.     { 4,  12, 2,  10 },
  302.     { 16, 8,  14, 6 }
  303.     };
  304.     int i, j, k, Level;
  305.     long Intensity;
  306.     GifColorType *ColorMapEntry;
  307.  
  308.     /* Scan the Rows (Size rows) evaluate intensity every Size pixel and use */
  309.     /* the dither matrix to set the dithered result;                 */
  310.     for (i = 0; i <= RowSize - DitherSize; i += DitherSize) {
  311.     Intensity = 0;
  312.     for (j = Row; j < Row + DitherSize; j++)
  313.         for (k = 0; k < DitherSize; k++) {
  314.         ColorMapEntry = &ColorMap[ScreenBuffer[j][i+k]];
  315.         Intensity += 30 * ((int) ColorMapEntry->Red) +
  316.                  59 * ((int) ColorMapEntry->Green) +
  317.                  11 * ((int) ColorMapEntry->Blue);
  318.         }
  319.  
  320.     /* Find the intensity level (between 0 and Size^2) of our matrix:    */
  321.     /* Expression is "Intensity * BWThreshold / (25500 * DefThresh)"     */
  322.     /* but to prevent from overflow in the long evaluation we do this:   */
  323.     Level = ((Intensity / 2550) * ((long) DEFAULT_THRESHOLD) /
  324.                         (((long) BWThreshold) * 10));
  325.     switch (DitherSize) {
  326.         case 2:     
  327.         for (j = 0; j < DitherSize; j++)
  328.             for (k = 0; k < DitherSize; k++)
  329.             DitherBuffer[j][i+k] = Dither2[j][k] <= Level;
  330.         break;
  331.         case 3:
  332.         for (j = 0; j < DitherSize; j++)
  333.             for (k = 0; k < DitherSize; k++)
  334.             DitherBuffer[j][i+k] = Dither3[j][k] <= Level;
  335.         break;
  336.         case 4:
  337.         for (j = 0; j < DitherSize; j++)
  338.             for (k = 0; k < DitherSize; k++)
  339.             DitherBuffer[j][i+k] = Dither4[j][k] <= Level;
  340.         break;
  341.     }
  342.     }
  343. }
  344.  
  345. /******************************************************************************
  346. * The real dumping routine. Few things are taken into account:              *
  347. * 1. The Nice flag. If TRUE each pixel is printed twice in double density.    *
  348. * 2. The Invert flag. If TRUE each pixel before drawn is inverted.          *
  349. * 3. The rendering mode and dither matrix flag if dithering is selected.      *
  350. *   The image is drawn from ScreenBuffer ScreenTop/Left in the bottom/right   *
  351. * directions.                                           *
  352. *   Unfortunatelly, there is a BUG in DOS that does not handle ctrl-Z          *
  353. * correctly if we open lptx: device in binary mode (should treat it as any    *
  354. * other char). Therefore I had to write to it directly using biosprint. I     *
  355. * dont like it either, and if you have better way to do it, let me know.      *
  356. ******************************************************************************/
  357. static void DumpScreen2Epsn(GifRowType *ScreenBuffer,
  358.                     int ScreenWidth, int ScreenHeight)
  359. {
  360.     int i, j, p, Size, LeftCWidth, Len, DirectPrint = 0,
  361.     DitheredLinesLeft = 0, DitheredLinesCount = 0, MapInvert[2];
  362.     char LinePrefixLen[2];                 /* Length of scan line. */
  363.     GifByteType *EpsonBuffer;
  364.     GifPixelType *Line;
  365.     GifRowType *DitherBuffer;
  366.     GifColorType *ColorMapEntry;
  367.     FILE *Prt = NULL;
  368.  
  369. #ifdef __MSDOS__
  370.     for (i = 0;     i < strlen(PrinterName); i++)
  371.     if (islower(PrinterName[i]))
  372.         PrinterName[i] = toupper(PrinterName[i]);
  373.  
  374.     if (strcmp(PrinterName, "LPT1") == 0 ||
  375.     strcmp(PrinterName, "PRN") == 0)
  376.     DirectPrint = 1;
  377.     else if (strcmp(PrinterName, "LPT2") == 0)
  378.         DirectPrint = 2;
  379.     else if (strcmp(PrinterName, "LPT3") == 0)
  380.         DirectPrint = 3;
  381. #endif /* __MSDOS__ */
  382.  
  383.     if (!DirectPrint) {
  384. #ifdef __MSDOS__
  385.     if (strlen(PrinterName) == 0) {
  386.         setmode(1, O_BINARY);      /* Make sure it is in binary mode. */
  387.         Prt = stdout;
  388.     }
  389.     else if ((Prt = fopen(PrinterName, "wb")) == NULL ||
  390.          setvbuf(Prt, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE))
  391. #else
  392.     if (strlen(PrinterName) == 0)
  393.         Prt = stdout;
  394.     else if ((Prt = fopen(PrinterName, "w")) == NULL)
  395. #endif /* __MSDOS__ */
  396.         GIF_EXIT("Failed to open output (printer) file.");
  397.     }
  398.  
  399.     if ((EpsonBuffer = (GifByteType *) malloc(ScreenWidth)) == NULL)
  400.     GIF_EXIT("Failed to allocate memory required, aborted.");
  401.  
  402.     /* Allocate the buffer to save the dithered information. */
  403.     if (ColorToBWMapping == C2BW_DITHER) {
  404.     if ((DitherBuffer = (GifRowType *)
  405.         malloc(DITHER_MAX_MATRIX * sizeof(GifRowType *))) != NULL) {
  406.         Size = ScreenWidth * sizeof(GifPixelType);     /* Size of one row. */
  407.         for (i = 0; i < DITHER_MAX_MATRIX; i++) {
  408.         if ((DitherBuffer[i] = (GifRowType) malloc(Size)) == NULL) {
  409.             DitherBuffer = NULL;
  410.             break;
  411.         }
  412.         }
  413.     }
  414.     if (DitherBuffer == NULL)
  415.         GIF_EXIT("Failed to allocate memory required, aborted.");
  416.     }
  417.     else
  418.     DitherBuffer = NULL;
  419.  
  420.     /* Reset the printer, and make sure no space between adjacent lines: */
  421.     PutString(Prt, DirectPrint, EPSON_RESET, 2);
  422.     PutString(Prt, DirectPrint, EPSON_VERTICAL_SPACE, 3);
  423.  
  424.     /* Prepar left spacing to begin with, so image will be in the middle.    */
  425.     LeftCWidth = (EPSON_WIDTH - (ScreenWidth / EPSON_PIXEL_2_CHAR)) / 2;
  426.  
  427.     if (InvertFlag) {           /* Make the inversion as fast a possible. */
  428.     MapInvert[0] = 1;
  429.     MapInvert[1] = 0;
  430.     }
  431.     else {
  432.     MapInvert[0] = 0;
  433.     MapInvert[1] = 1;
  434.     }
  435.  
  436.     for (i = 0, p = 0; i < ScreenHeight; i++, p++) {
  437.     fprintf(stderr, "\b\b\b\b%-4d", ScreenHeight - i);
  438.     Line = ScreenBuffer[i];
  439.  
  440.     /* If 8 lines were accumulated in printer buffer - dump them out.    */
  441.     if (p == 8) {
  442.         for (Len = ScreenWidth-1; Len >= 0; Len--)
  443.             if (EpsonBuffer[Len]) break;
  444.  
  445.         /* Only in case this line is not empty: */
  446.         if (Len++ >= 0) {
  447.         /* Make the left space, so image will be centered: */
  448.         for (j = 0; j < LeftCWidth; j++)
  449.             PutString(Prt, DirectPrint,  " ", 1);
  450.  
  451.         /* Full printer line is ready to be dumped - send it out: */
  452.         if (NiceFlag) {
  453.             PutString(Prt, DirectPrint, EPSON_DUAL_DENSITY, 2);
  454.             LinePrefixLen[0] = (Len * 2) % 256;
  455.             LinePrefixLen[1] = (Len * 2) / 256;
  456.             PutString(Prt, DirectPrint, LinePrefixLen, 2);
  457.             PutString2(Prt, DirectPrint, (char *) EpsonBuffer, Len);
  458.         }
  459.         else {
  460.             PutString(Prt, DirectPrint, EPSON_REG_DENSITY, 2);
  461.             LinePrefixLen[0] = Len % 256;
  462.             LinePrefixLen[1] = Len / 256;
  463.             PutString(Prt, DirectPrint, LinePrefixLen, 2);
  464.             PutString(Prt, DirectPrint, (char *) EpsonBuffer, Len);
  465.         }
  466.         }
  467.         PutString(Prt, DirectPrint, "\015\012", 2);
  468.         p = 0;
  469.     }
  470.  
  471.     /* We decide right here what method to map Colors to BW so the inner */
  472.     /* loop will be independent of it (and therefore faster):         */
  473.     switch(ColorToBWMapping) {
  474.         case C2BW_BACK_GROUND:
  475.         for (j = 0; j < ScreenWidth; j++)
  476.             EpsonBuffer[j] = (EpsonBuffer[j] << 1) +
  477.                     MapInvert[Line[j] != BackGround];
  478.         break;
  479.         case C2BW_GREY_LEVELS:
  480.         for (j = 0; j < ScreenWidth; j++) {
  481.             ColorMapEntry = &ColorMap[Line[j]];
  482.             /* For the transformation from RGB to BW, see Folley &   */
  483.             /* Van Dam pp 613: The Y channel is the BW we need:         */
  484.             /* As colors are 255 maximum, the result can be up to    */
  485.             /* 25500 which is still in range of our 16 bits integers */
  486.             EpsonBuffer[j] = (EpsonBuffer[j] << 1) +
  487.             MapInvert[(30 * (int) ColorMapEntry->Red) +
  488.                    59 * ((int) ColorMapEntry->Green) +
  489.                    11 * ((int) ColorMapEntry->Blue) >
  490.                     BWThreshold];
  491.         }
  492.         break;
  493.         case C2BW_DITHER:
  494.         if (DitheredLinesLeft-- == 0) {
  495.             EvalDitheredScanline(ScreenBuffer,
  496.             (i < ScreenHeight - DitherSize ? i :
  497.                          ScreenHeight - DitherSize),
  498.             ScreenWidth, DitherBuffer);
  499.             DitheredLinesLeft = DitherSize - 1;
  500.             DitheredLinesCount = 0;
  501.         }
  502.         Line = DitherBuffer[DitheredLinesCount++];
  503.         for (j = 0; j < ScreenWidth; j++)
  504.             EpsonBuffer[j] = (EpsonBuffer[j] << 1) +
  505.                             MapInvert[Line[j]];
  506.         break;
  507.     }
  508.     }
  509.  
  510.     /* If buffer in incomplete - complete it and dump it out: */
  511.     if (p != 0) {
  512.     for (Len = ScreenWidth - 1; Len >= 0; Len--)
  513.         if (EpsonBuffer[Len]) break;
  514.     if (Len++ >= 0) {
  515.         i = 8 - p;                     /* Amount to shift. */
  516.         for (j = 0; j < ScreenWidth; j++) EpsonBuffer[j] <<= i;
  517.  
  518.         /* Make the left space, so image will be centered: */
  519.         for (j = 0; j < LeftCWidth; j++)
  520.         PutString(Prt, DirectPrint, " ", 1);
  521.  
  522.         if (NiceFlag) {
  523.         PutString(Prt, DirectPrint, EPSON_DUAL_DENSITY, 2);
  524.         LinePrefixLen[0] = (Len * 2) % 256;
  525.         LinePrefixLen[1] = (Len * 2) / 256;
  526.         PutString(Prt, DirectPrint, LinePrefixLen, 2);
  527.         PutString2(Prt, DirectPrint, (char *) EpsonBuffer, Len);
  528.         }
  529.         else {
  530.         PutString(Prt, DirectPrint, EPSON_REG_DENSITY, 2);
  531.         LinePrefixLen[0] = Len % 256;
  532.         LinePrefixLen[1] = Len / 256;
  533.         PutString(Prt, DirectPrint, LinePrefixLen, 2);
  534.         PutString(Prt, DirectPrint, (char *) EpsonBuffer, Len);
  535.         }
  536.     }
  537.     PutString(Prt, DirectPrint, "\015\012", 2);
  538.     }
  539.  
  540.     fclose(Prt);
  541. }
  542.  
  543. /******************************************************************************
  544. * Dumps the string of given length, to Prt. No char in Str has special          *
  545. * meaning, and even zero (NULL) chars are dumped.                  *
  546. * If however DirectPrint is non zero, string is dumped to specifed lpt port.  *
  547. ******************************************************************************/
  548. static void PutString(FILE *Prt, int DirectPrint, char *Str, int Len)
  549. {
  550.     int i;
  551.  
  552.     if (DirectPrint) {
  553. #ifdef __MSDOS__
  554.     for (i = 0; i < Len; i++) biosprint(0, Str[i], DirectPrint - 1);
  555. #else
  556.     GIF_EXIT("Can not print directly to a printer if not MSDOS.");
  557. #endif /* __MSDOS__ */
  558.     }
  559.     else
  560.     for (i = 0; i < Len; i++) fputc(Str[i], Prt);
  561. }
  562.  
  563. /******************************************************************************
  564. * Dumps the string of given length, to Prt. No char in Str has special          *
  565. * meaning, and even zero (NULL) chars are dumped. Every char is dumped twice. *
  566. * If however DirectPrint is non zero, string is dumped to specifed lpt port.  *
  567. ******************************************************************************/
  568. static void PutString2(FILE *Prt, int DirectPrint, char *Str, int Len)
  569. {
  570.     int i;
  571.  
  572.     if (DirectPrint) {
  573. #ifdef __MSDOS__
  574.     for (i = 0; i < Len; i++) {
  575.         biosprint(0, Str[i], DirectPrint - 1);
  576.         biosprint(0, Str[i], DirectPrint - 1);
  577.     }
  578. #else
  579.     GIF_EXIT("Can not print directly to a printer if not MSDOS.");
  580. #endif /* __MSDOS__ */
  581.     }
  582.     else
  583.     for (i = 0; i < Len; i++) {
  584.         fputc(Str[i], Prt);
  585.         fputc(Str[i], Prt);
  586.     }
  587. }
  588.