diff options
author | Ralph Giles <ralph.giles@artifex.com> | 2008-08-29 18:46:21 +0000 |
---|---|---|
committer | Ralph Giles <ralph.giles@artifex.com> | 2008-08-29 18:46:21 +0000 |
commit | 6ff2582d038f99b79178082b200bdfe73f734456 (patch) | |
tree | 6db04fc72813760fdc6912a15875ad83d57943df /gs/base/gdevhl7x.c | |
parent | 9d36ee856e41244d3cf0469fc0004d21e6911994 (diff) | |
download | ghostpdl-6ff2582d038f99b79178082b200bdfe73f734456.tar.gz |
Split the source tree into two new directories.
PSSRC files are now in 'gs/psi'.
GLSRC files are now in 'gs/base'.
This is to facilitate build modularization and merging in the ghostpdl
tree.
NOTE: msvc32.mak is now in psi, not src.
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@9048 a1074d23-0009-0410-80fe-cf8c14f379e6
Diffstat (limited to 'gs/base/gdevhl7x.c')
-rw-r--r-- | gs/base/gdevhl7x.c | 1068 |
1 files changed, 1068 insertions, 0 deletions
diff --git a/gs/base/gdevhl7x.c b/gs/base/gdevhl7x.c new file mode 100644 index 000000000..b829f81fb --- /dev/null +++ b/gs/base/gdevhl7x.c @@ -0,0 +1,1068 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ +/* $Id$ */ +/* + * Brother HL 720 and 730 driver for Ghostscript + * + * Note: for the HL 760, use the HP driver. + * + * The original code was borrowed from the + * HP LaserJet/DeskJet driver for Ghostscript. + * The code specific to the Brother HL 720 was written by : + * Pierre-Olivier Gaillard (pierre.gaillard@hol.fr) + * Thanks to the documentation kindly provided by : + * Richard Thomas <RICHARDT@brother.co.uk> + * + * Removal of compression code on 1/17/00 by Ross Martin + * (ross@ross.interwrx.com, martin@walnut.eas.asu.edu) + * enables this driver to correctly print tiger.eps on a + * Brother MFC6550MC Fax Machine. Change to the Horizontal + * Offset fixes incorrect page alignment at 300dpi in + * Landscape mode with a2ps. + */ +#include "gdevprn.h" +/* The following line is used though these printers are not PCL printers*/ +/* This is because we want the paper size access function */ +/* (The 720 is a simple GDI printer) */ +#include "gdevpcl.h" + +/* + * You may select a default resolution of 150 (for 730), 300, or + * 600 DPI in the makefile, or an actual resolution on + * the gs command line. + * + * If the preprocessor symbol A4 is defined, the default paper size is + * the European A4 size; otherwise it is the U.S. letter size (8.5"x11"). + * + * You may find the following test page useful in determining the exact + * margin settings on your printer. It prints four big arrows which + * point exactly to the for corners of an A4 sized paper. Of course the + * arrows cannot appear in full on the paper, and they are truncated by + * the margins. The margins measured on the testpage must match those + * in gdevdjet.c. So the testpage indicates two facts: 1) the page is + * not printed in the right position 2) the page is truncated too much + * because the margins are wrong. Setting wrong margins in gdevdjet.c + * will also move the page, so both facts should be matched with the + * real world. + +%! + newpath + 0 0 moveto 144 72 lineto 72 144 lineto + closepath fill stroke 0 0 moveto 144 144 lineto stroke + + 595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto + closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke + + 0 841.88 moveto 144 769.88 lineto 72 697.88 lineto + closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke + + 595.27 0 moveto 451.27 72 lineto 523.27 144 lineto + closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke + + /Helvetica findfont + 14 scalefont setfont + 100 600 moveto + (This is an A4 testpage. The arrows should point exactly to the) show + 100 580 moveto + (corners and the margins should match those given in gdev*.c) show + showpage + + */ + + +/* Type definitions */ +typedef struct { + short width; /* physical width of the paper */ + short height; /* physical height of the paper */ +} PaperFormat; /* Rep. of the charateristics of a sheet of paper */ + +typedef unsigned char Byte; /* Rep. of elementary data unit */ + + + +/* + * Definition of a Helper structure to handle a list of commands + */ +typedef struct { + Byte * data; + short maxSize; + short current; + +} ByteList; + +/* + * Type for representing a summary of the previous lines + * + */ + +typedef struct { + short previousSize; + Byte previousData[1500]; /* Size bigger than any possible line */ + short nbBlankLines; + short nbLinesSent; + short pageWidth; + short pageHeight; + short horizontalOffset; + short resolution; +} Summary; + + + +/* Constants */ + +/* We need a boolean : true , we got it from gdevprn.h */ + +/* Other constants */ +static const int DumpFinished = 0; +static const int DumpContinue = 1; +static const int HL7X0_LENGTH = 5; /* Length of a command to tell the size of the data to be sent to the printer*/ +static void makeCommandsForSequence(Byte * pSource, + short length, + ByteList * pCommandList, + short offset, + Byte * pCommandCount, + short rest); + +/* Auxiliary Functions */ + + + +static int dumpPage(gx_device_printer * pSource, + Byte * pLineTmp, + ByteList * pCommandList, + Summary * pSummary + ); +static void initSummary(Summary * s,short pw, short ph, short resolution); + +static void resetPreviousData(Summary * s); + +static void makeFullLine( Byte * pCurrentLine, + Byte * pPreviousLine, + short lineWidth, + ByteList * commandsList, + short horizontalOffset + ); + + + +/* + * Initialize a list of Bytes structure + */ +static void initByteList(ByteList *list, Byte *array, short maxSize,short initCurrent); +static void addByte(ByteList *list,Byte value ); +static void addArray(ByteList *list, Byte *source, short nb); +static void addNBytes(ByteList * list, Byte value, short nb); +static Byte * currentPosition(ByteList * list); +static void addCodedNumber(ByteList * list, short number); +static int isThereEnoughRoom(ByteList * list, short biggest); +static short roomLeft(ByteList * list); +static void dumpToPrinter(ByteList * list,FILE * printStream); + +/* Real Print function */ + +static int hl7x0_print_page(gx_device_printer *, FILE *, int, int, ByteList *); + + + + + + +/* Define the default, maximum resolutions. */ +#ifdef X_DPI +# define X_DPI2 X_DPI +#else +# define X_DPI 300 +# define X_DPI2 600 +#endif +#ifdef Y_DPI +# define Y_DPI2 Y_DPI +#else +# define Y_DPI 300 +# define Y_DPI2 600 +#endif + + +#define LETTER_WIDTH 5100 +#define LEFT_MARGIN 30 +/* The following table is not actually used.... */ +static const PaperFormat tableOfFormats[] = { + /* 0 P LETTER */ { 2550, 3300 }, + /* 1 P LEGAL */ { 2550, 4200 }, + /* 2 P EXEC */ { 2175, 3150 }, + /* 3 P A4(78) */ { 2480, 3507 }, + /* 4 P B5 */ { 2078, 2953 }, + /* 5 P A5 */ { 1754, 2480 }, + /* 6 P MONARC */ { 1162, 2250 }, + /* 7 P COM10 */ { 1237, 2850 }, + /* 8 P DL */ { 1299, 2598 }, + /* 9 P C5 */ { 1913, 2704 }, + /* 10 P A4Long */ { 2480, 4783 }, + + /* 11 L LETTER */ { 3300, 2550 }, + /* 12 L LEGAL */ { 4200, 2550 }, + /* 13 L EXEC */ { 3150, 2175 }, + /* 14 L A4 */ { 3507, 2480 }, + /* 15 L B5 */ { 2952, 2078 }, + /* 16 L A5 */ { 2480, 1754 }, + /* 17 L MONARC */ { 2250, 1162 }, + /* 18 L COM10 */ { 2850, 1237 }, + /* 19 L DL */ { 2598, 1299 }, + /* 20 L C5 */ { 2704, 1913 }, + /* 21 L A4Long */ { 4783, 2480 } +}; + + +/* Compute the maximum length of a compressed line */ +static short MaxLineLength(short resolution){ +return (((156 * resolution / 150 ) * 5 )/4) + 8; +} + + +/* Margins are left, bottom, right, top. */ +/* Quotation from original gdevdjet.c */ +/* from Frans van Hoesel hoesel@rugr86.rug.nl. */ +/* A4 has a left margin of 1/8 inch and at a printing width of + * 8 inch this give a right margin of 0.143. The 0.09 top margin is + * not the actual margin - which is 0.07 - but compensates for the + * inexact paperlength which is set to 117 10ths. + * Somebody should check for letter sized paper. I left it at 0.07". + */ + + +/* The A4 margins are almost good */ +/* The one for Letter are those of the gdevdjet.c file... */ +#define HL7X0_MARGINS_A4 0.1, 0.15, 0.07, 0.05 +#define HL7X0_MARGINS_LETTER 0.275, 0.20, 0.25, 0.07 + + + +/* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */ +#define W sizeof(word) + +/* Printer types */ + +#define HL720 0 +#define HL730 0 /* No difference */ + + + + +/* The device descriptors */ +static dev_proc_open_device(hl7x0_open); +static dev_proc_close_device(hl7x0_close); +static dev_proc_print_page(hl720_print_page); +static dev_proc_print_page(hl730_print_page); + + + +static const gx_device_procs prn_hl_procs = + prn_params_procs(hl7x0_open, gdev_prn_output_page, hl7x0_close, + gdev_prn_get_params, gdev_prn_put_params); + + +const gx_device_printer far_data gs_hl7x0_device = + prn_device(prn_hl_procs, "hl7x0", + DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, + X_DPI, Y_DPI, + 0, 0, 0, 0, /* margins filled in by hl7x0_open */ + 1, hl720_print_page); /* The hl720 and hl730 can both use the same print method */ + + + +/* Open the printer, adjusting the margins if necessary. */ + +static int +hl7x0_open(gx_device *pdev) +{ /* Change the margins if necessary. */ + static const float m_a4[4] = { HL7X0_MARGINS_A4 }; + static const float m_letter[4] = { HL7X0_MARGINS_LETTER }; + const float *m = + (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 : m_letter); + + gx_device_set_margins(pdev, m, true); + return gdev_prn_open(pdev); +} + + +/* The orders sent are those provided in the Brother DOS example */ +static int +hl7x0_close(gx_device *pdev) +{ + gx_device_printer *const ppdev = (gx_device_printer *)pdev; + int code = gdev_prn_open_printer(pdev, 1); + + if (code < 0) + return code; + fputs("@N@N@N@N@X", ppdev->file) ; + return gdev_prn_close_printer(pdev); +} + +/* ------ Internal routines ------ */ + +/* The HL 720 can compress*/ +static int +hl720_print_page(gx_device_printer *pdev, FILE *prn_stream) +{ + Byte prefix[] ={ + 0x1B,'%','-','1','2','3','4','5','X' + ,'@','P','J','L',0x0A /* set PJL mode */ + ,'@','P','J','L',' ','E','N','T','E','R',' ' + ,'L','A','N','G','U','A','G','E' + ,' ','=',' ','H','B','P',0x0A /* set GDI Printer mode */ + ,'@','L', 0x0 + }; + ByteList initCommand; + int x_dpi = pdev->x_pixels_per_inch; + initByteList(&initCommand, + prefix, /* Array */ + sizeof(prefix), /* Total size */ + sizeof(prefix) - 1); /* Leave one byte free since*/ + /* we need to add the following order at the end */ + addByte(&initCommand, (Byte) ((((600/x_dpi) >> 1) \ + | (((600/x_dpi) >> 1) << 2)))); + /* Put the value of the used resolution into the init string */ + + return hl7x0_print_page(pdev, prn_stream, HL720, 300, + &initCommand); +} +/* The HL 730 can compress */ +static int +hl730_print_page(gx_device_printer *pdev, FILE *prn_stream) +{ return hl720_print_page(pdev, prn_stream); +} + +/* Send the page to the printer. For speed, compress each scan line, */ +/* since computer-to-printer communication time is often a bottleneck. */ +static int +hl7x0_print_page(gx_device_printer *pdev, FILE *printStream, int ptype, + int dots_per_inch, ByteList *initCommand) +{ + /* UTILE*/ + /* Command for a formFeed (we can't use strings because of the zeroes...)*/ + Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'}; + ByteList formFeedCommand; + /* Main characteristics of the page */ + int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev); + int x_dpi = pdev->x_pixels_per_inch; + /* int y_dpi = pdev->y_pixels_per_inch; */ + int num_rows = dev_print_scan_lines(pdev); + int result; + int sizeOfBuffer = MaxLineLength(x_dpi) + 30; + Byte * storage = (Byte *) gs_malloc(pdev->memory, + sizeOfBuffer + line_size, + 1, + "hl7x0_print_page"); + /* bool dup = pdev->Duplex; */ + /* bool dupset = pdev->Duplex_set >= 0; */ + Summary pageSummary; + ByteList commandsBuffer; + initSummary(&pageSummary, + line_size, + num_rows, + x_dpi); + if ( storage == 0 ) /* can't allocate working area */ + return_error(gs_error_VMerror); + initByteList(&commandsBuffer, storage, sizeOfBuffer,0 ); + /* PLUS A MOI */ + if ( pdev->PageCount == 0 ) + { + /* Put out init string before first page. */ + dumpToPrinter(initCommand, printStream); /* send init to printer */ + + } + + do { + result = dumpPage(pdev, + storage + sizeOfBuffer, /* The line buffer is after the dump buffer */ + &commandsBuffer, + &pageSummary); + dumpToPrinter(&commandsBuffer,printStream); + + } while (result == DumpContinue); + + + /* end raster graphics and eject page */ + initByteList(&formFeedCommand, + FormFeed, /* Array */ + sizeof(FormFeed), /* Size in bytes */ + sizeof(FormFeed)); /* First free byte */ + dumpToPrinter(&formFeedCommand, printStream); + + /* free temporary storage */ + gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page"); + + return 0; /* If we reach this line, it means there was no error */ +} + +/* + * Useful auxiliary declarations + * + */ + + +static short stripTrailingBlanks(Byte * line, short length){ + short positionOfFirstZero = length - 1; + while (positionOfFirstZero > 0) { + if (line[positionOfFirstZero] != 0) { + return positionOfFirstZero + 1; + } + positionOfFirstZero -- ; + } + return 0; +} + +/* + * Changed the horizontalOffset function 1/17/00 Ross Martin. + * ross@ross.interwrx.com or martin@walnut.eas.asu.edu + * + * The equation used to muliply pixWidth by resolution/600 + * also. This didn't work right at resolution 300; it caused + * landscape pages produced by a2ps to be half off the + * page, when they were not at 600dpi or on other + * devices. I'm not sure the equation below is exactly + * correct, but it now looks to be pretty close visually, + * and works correctly at 600dpi and 300dpi. + */ +static short horizontalOffset(short pixWidth, + short pixOffset, + short resolution){ +return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8; + +} + + + +/* + * First values in a Summary + */ +static void initSummary(Summary * s,short pw, short ph, short resolution){ + s->previousSize = -1 ; + s->nbBlankLines = 1; + s->nbLinesSent = 0; + s->pageWidth = pw; /* In Bytes */ + s->pageHeight = ph; + s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ; + s->resolution = resolution; +} + +/* + * The previous line was blank, so we need to clean the corresponding array + */ +static void resetPreviousData(Summary * s){ + memset(s->previousData,0,s->pageWidth); +} + + +/* + * dumpPage : + * + */ +static int dumpPage(gx_device_printer * pSource, + Byte * pLineTmp, + ByteList * pCommandList, + Summary * pSummary + ){ + + /* Declarations */ + Byte * pSaveCommandStart; + short lineNB; + short usefulLength; + short tmpLength; + /* Initializations */ + /* Make room for size of commands buffer */ + pSaveCommandStart = currentPosition(pCommandList); + addNBytes(pCommandList,0,HL7X0_LENGTH); + /* pSource += pSummary->nbLinesSent * pSummary->pageWidth;*/ + /* Process all possible Lines */ + for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ; + lineNB < pSummary->pageHeight ; lineNB ++ ) { + /* Fetch the line and put it into the buffer */ + gdev_prn_copy_scan_lines(pSource, + lineNB, + pLineTmp, + pSummary->pageWidth); + + usefulLength = stripTrailingBlanks(pLineTmp,pSummary->pageWidth); + if (usefulLength != 0) { + + /* The line is not blank */ + /* Get rid of the precedent blank lines */ + if (pSummary->nbBlankLines != 0) { + if ( isThereEnoughRoom( pCommandList, pSummary->nbBlankLines ) ) { + + addNBytes(pCommandList,0xff,pSummary->nbBlankLines); + pSummary->nbBlankLines = 0; + + } + else { + + short availableRoom = roomLeft(pCommandList); + addNBytes(pCommandList,0xff,availableRoom); + pSummary->nbBlankLines -= availableRoom; + + break ; /* We have no more room */ + + } + + resetPreviousData(pSummary); /* Make sure there are zeroes for the previous line */ + pSummary->previousSize = 0; /* The previous line was empty */ + + } + + /* Deal with the current line */ + if (!isThereEnoughRoom(pCommandList,MaxLineLength(pSummary->resolution))){ + break; /* We can process this line */ + } + + if (pSummary->previousSize > usefulLength){ + tmpLength = pSummary->previousSize; + } + else { + tmpLength = usefulLength; + } + + if (pSummary->previousSize == -1 ) {/* This is the first line */ + + Byte *save = currentPosition(pCommandList); + addByte(pCommandList,0); /* One byte for the number of commands */ + + makeCommandsForSequence(pLineTmp, + tmpLength, + pCommandList, + pSummary->horizontalOffset, + save, + 0); + } + else { /*There is a previous line */ + + makeFullLine(pLineTmp, + pSummary->previousData, + tmpLength, + pCommandList, + pSummary->horizontalOffset); + } + /* The present line will soon be considered as "previous" */ + pSummary->previousSize = tmpLength; + /* Update the data representing the line will soon be the "previous line" */ + memcpy(pSummary->previousData,pLineTmp,tmpLength); + + } + else { /* the current line is blank */ + pSummary->nbBlankLines++; + } + + /* And one more line */ + pSummary->nbLinesSent ++; + } + + if (pCommandList->current > HL7X0_LENGTH){ + short size = pCommandList->current - HL7X0_LENGTH; + *(pSaveCommandStart++) = '@'; + *(pSaveCommandStart++) = 'G'; + *(pSaveCommandStart++) = (Byte) (size >> 16); + *(pSaveCommandStart++) = (Byte) (size >> 8); + *(pSaveCommandStart++) = (Byte) (size); + } + else { /* We only met blank lines and reached the end of the page */ + pCommandList->current = 0; + } + if (lineNB == pSummary->pageHeight){ + return DumpFinished; + } + else { + return DumpContinue; + } +} + + +/* + * makeFullLine : + * process an arbitrary line for which a former line is available + * The line will be split in sequences that are different from the + * corresponding ones of the previous line. These sequences will be processed + * by makeCommandsOfSequence. + */ + + + +static void makeFullLine( Byte * pCurrentLine, + Byte * pPreviousLine, + short lineWidth, + ByteList * commandsList, + short horizontalOffset + ){ + /* Declarations */ + Byte *pPreviousTmp; + Byte *pCurrentTmp; + Byte *pNumberOfCommands; + int loopCounter; + short remainingWidth; + Byte *pStartOfSequence; + /*****************/ + /* Special cases */ + /*****************/ + + /* I believe this situation to be impossible */ + if (lineWidth <= 0) { + addByte(commandsList,0xff); + return; + } + + /*******************/ + /* Initializations */ + /*******************/ + + pNumberOfCommands = currentPosition(commandsList); /* Keep a pointer to the number of commands */ + addByte(commandsList,0); /* At the moment there are 0 commands */ + + pPreviousTmp = pPreviousLine; + pCurrentTmp = pCurrentLine; + + /* Build vector of differences with a Xor */ + + for (loopCounter = lineWidth ; 0 < loopCounter ; loopCounter -- ) + *pPreviousTmp++ ^= *pCurrentTmp++; + + /* Find sequences that are different from the corresponding (i.e. vertically aligned) + * one of the previous line. Make commands for them. + */ + + pStartOfSequence = pPreviousLine; + remainingWidth = lineWidth; + + while (true) { + + /* + * Disabled line-to-line compression, 1/17/00 Ross Martin + * ross@ross.interwrx.com and/or martin@walnut.eas.asu.edu + * + * The compression here causes problems printing tiger.eps. + * The problem is vertical streaks. The printer I'm printing + * to is a Brother MFC6550MC Fax Machine, which may be + * slightly different from the hl720 and hl730. Note that + * this fax machine does support HP LaserJet 2p emulation, + * but in order to enable it I believe one needs special + * setup from a DOS program included with the printer. Thus, + * the hl7x0 driver seems a better choice. In any case, + * on the MFC6550MC, some files print fine with compression + * turned on, but others such as tiger.eps print with streaks. + * disabling the compression fixes the problem, so I haven't + * looked any further at the cause. It may be that the + * compression is correct for the hl720 and hl730, and only + * different for the MFC6550MC, or it may be that tiger.eps + * won't print correctly with compression enabled on any + * of these. It may be that the problem is only with color + * and/or grayscale prints. YMMV. I don't think it likely + * that turning off compression will cause problems with + * other printers, except that they may possibly print slower. + */ + +#ifdef USE_POSSIBLY_FLAWED_COMPRESSION + /* Count and skip bytes that are not "new" */ + while (true) { + if (remainingWidth == 0) /* There is nothing left to do */ + { + return; + } + if (*pStartOfSequence != 0) + break; + pStartOfSequence ++; + horizontalOffset ++; /* the offset takes count of the bytes that are not "new" */ + --remainingWidth; + } +#endif + + pPreviousTmp = pStartOfSequence + 1; /* The sequence contains at least this byte */ + --remainingWidth; + + /* Find the end of the sequence of "new" bytes */ + +#ifdef USE_POSSIBLY_FLAWED_COMPRESSION + while (remainingWidth != 0 && *pPreviousTmp != 0) { + ++pPreviousTmp; /* Enlarge the sequence Of new bytes */ + --remainingWidth; + } +#else + pPreviousTmp += remainingWidth; + remainingWidth = 0; +#endif + + makeCommandsForSequence(pCurrentLine + (pStartOfSequence - pPreviousLine), + pPreviousTmp - pStartOfSequence, + commandsList, + horizontalOffset, + pNumberOfCommands, + remainingWidth); + if (*pNumberOfCommands == 0xfe /* If the number of commands has reached the maximum value */ + || /* or */ + remainingWidth == 0 ) /* There is nothing left to process */ + { + return; + } + + pStartOfSequence = pPreviousTmp + 1; /* We go on right after the sequence of "new" bytes */ + horizontalOffset = 1; + --remainingWidth; + } /* End of While */ + + + + +} /* End of makeFullLine */ + + + +/* + * Declarations of functions that are defined further in the file + */ +static void makeSequenceWithoutRepeat( + Byte * pSequence, + short lengthOfSequence, + ByteList * pCommandList, + short offset ); + +static void makeSequenceWithRepeat( + Byte * pSequence, + short lengthOfSequence, + ByteList * pCommandList, + short offset ); + + +/* + * makeCommandsForSequence : + * Process a sequence of new bytes (i.e. different from the ones on the former line) + */ + +static void makeCommandsForSequence(Byte * pSource, + short length, + ByteList * pCommandList, + short offset, + Byte * pNumberOfCommands, + short rest) { + /* Declarations */ + Byte * pStartOfSequence; + Byte * pEndOfSequence; + short remainingLength = length - 1; + + pStartOfSequence = pSource; + pEndOfSequence = pStartOfSequence + 1; + /* + * Process the whole "new" Sequence that is divided into + * repetitive and non-repetitive sequences. + */ + while (true) { + + /* If we have already stored too many commands, make one last command with + * everything that is left in the line and return. + */ + if (*pNumberOfCommands == 0xfd) { + makeSequenceWithoutRepeat(pStartOfSequence, + 1 + remainingLength + rest, + pCommandList, + offset); + ++*pNumberOfCommands; + return; + } + + /* Start with a sub-sequence without byte-repetition */ + while (true) { + /* If we have completed the last subsequence */ + if (remainingLength == 0) { + makeSequenceWithoutRepeat(pStartOfSequence, + pEndOfSequence - pStartOfSequence, + pCommandList, + offset); + ++*pNumberOfCommands; + return; + } + /* If we have discovered a repetition */ + if (*pEndOfSequence == *(pEndOfSequence - 1)) { + break; + } + ++ pEndOfSequence; /* The subsequence is bigger*/ + --remainingLength; + } + /* If this is a sequence without repetition */ + if (pStartOfSequence != pEndOfSequence - 1) { + makeSequenceWithoutRepeat(pStartOfSequence, + (pEndOfSequence - 1) - pStartOfSequence, + pCommandList, + offset); + ++*pNumberOfCommands; + offset = 0; + pStartOfSequence = pEndOfSequence - 1; + + /* If we have too many commands */ + if (*pNumberOfCommands == 0xfd) { + makeSequenceWithoutRepeat(pStartOfSequence, + 1 + remainingLength + rest, + pCommandList, + offset); + ++*pNumberOfCommands; + return; + } + } /* End If */ + + /* + * Process a subsequence that repeats the same byte + */ + while (true) { + /* If there is nothing left to process */ + if (remainingLength == 0) { + makeSequenceWithRepeat(pStartOfSequence, + pEndOfSequence - pStartOfSequence, + pCommandList, + offset); + ++*pNumberOfCommands; + return; + } + /* If we find a different byte */ + if (*pEndOfSequence != *pStartOfSequence){ + break; + } + ++pEndOfSequence; /* The subsequence is yet bigger */ + --remainingLength; + } /* End of While */ + makeSequenceWithRepeat(pStartOfSequence, + pEndOfSequence - pStartOfSequence, + pCommandList, + offset); + ++*pNumberOfCommands; + offset = 0; /* The relative offset between two subsequences is 0 */ + pStartOfSequence = pEndOfSequence ++ ; /* we loop again from the end of this subsequence */ + --remainingLength; + + } /* End of While */ + +} /* End makeCommandsForSequence */ + + + + + + + + +/* + * makeSequenceWithoutRepeat + */ +static void makeSequenceWithoutRepeat( + Byte * pSequence, + short lengthOfSequence, + ByteList * pCommandList, + short offset ){ + /* + * Constant definitions + */ + static const short MAX_OFFSET = 15; + static const short POSITION_OF_OFFSET = 3; + static const short MAX_LENGTH = 7; + + Byte tmpFirstByte = 0; + Byte * pSaveFirstByte; + short reducedLength = lengthOfSequence - 1; /* Length is alway higher than 1 + Therefore a reduced value is stored + */ + /* Initialization */ + + pSaveFirstByte = currentPosition(pCommandList); + addByte( pCommandList, 0 /* Dummy value */); + + /* Computations */ + + if (offset >= MAX_OFFSET) { + addCodedNumber(pCommandList,offset - MAX_OFFSET); + tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET; + } + else + tmpFirstByte |= offset << POSITION_OF_OFFSET; + + if (reducedLength >= MAX_LENGTH) { + addCodedNumber(pCommandList,reducedLength - MAX_LENGTH); + tmpFirstByte |= MAX_LENGTH ; + } + else + tmpFirstByte |= reducedLength ; + /* Add a copy of the source sequence */ + + addArray(pCommandList, pSequence, lengthOfSequence); + + /* Store the computed value of the first byte */ + + *pSaveFirstByte = tmpFirstByte; + + return ; +} /* End of makeSequenceWithoutRepeat */ + + + +/* + * makeSequenceWithRepeat + */ +static void makeSequenceWithRepeat( + Byte * pSequence, + short lengthOfSequence, + ByteList * pCommandList, + short offset ){ + /* + * Constant definitions + */ + static const short MAX_OFFSET = 3; + static const short POSITION_OF_OFFSET = 5; + static const short MAX_LENGTH = 31; + + Byte tmpFirstByte = 0x80; + Byte * pSaveFirstByte; + short reducedLength = lengthOfSequence - 2; /* Length is always higher than 2 + Therefore a reduced value is stored + */ + /* Initialization */ + + pSaveFirstByte = currentPosition(pCommandList); + addByte( pCommandList, 0 /* Dummy value */); + + /* Computations */ + + if (offset >= MAX_OFFSET) { + addCodedNumber(pCommandList, offset - MAX_OFFSET); + tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET; + } + else + tmpFirstByte |= offset << POSITION_OF_OFFSET; + + if (reducedLength >= MAX_LENGTH) { + addCodedNumber(pCommandList,reducedLength - MAX_LENGTH); + tmpFirstByte |= MAX_LENGTH ; + } + else + tmpFirstByte |= reducedLength ; + /* Add a copy the byte that is repeated throughout the sequence */ + + addByte(pCommandList, *pSequence ); + + /* Store the computed value of the first byte */ + + *pSaveFirstByte = tmpFirstByte; + + return ; +} /* End of makeSequenceWithRepeat*/ + + + + +/* + * Initialize a list of Bytes structure + */ +static void initByteList(ByteList *list, Byte *array, short maxSize, short initCurrent) { + list->current = initCurrent; + list->maxSize = maxSize; + list->data = array; +} + +/* + * Add a Byte to a list of Bytes + */ +static void addByte(ByteList *list,Byte value ) { + if (list->current < list->maxSize) + list->data[list->current++] = value; + else + errprintf("Could not add byte to command\n"); +} + + +/* + * Add a copy of an array to a list of Bytes + */ + +static void addArray(ByteList *list, Byte *source, short nb){ + if (list->current <= list->maxSize - nb) + { + memcpy(list->data + list->current, source , (size_t) nb); + list->current += nb; + } + else + errprintf("Could not add byte array to command\n"); +} + + +/* + * Add N bytes to a list of Bytes + */ + +static void addNBytes(ByteList * list, Byte value, short nb){ + int i; + if (list->current <= list->maxSize - nb) + { + for (i = list->current ; i < (list->current + nb) ; i++) + { + list->data[i] = value; + } + list->current += nb; + } + else + errprintf("Could not add %d bytes to command\n",nb); +} + +/* + * Get pointer to the current byte + */ +static Byte * currentPosition(ByteList * list) { + return &(list->data[list->current]); +} + +/* + * add a number coded in the following way : + * q bytes with 0xff value + * 1 byte with r value + * where q is the quotient of the number divided by 0xff and r is the + * remainder. + */ +static void addCodedNumber(ByteList * list, short number){ + short q = number / 0xff; + short r = number % 0xff; + + addNBytes(list, 0xff, q); + addByte(list,r); + +} + +/* + * See if there is enough room for a set of commands of size biggest + * + */ + +static int isThereEnoughRoom(ByteList * list, short biggest){ + return ((list->maxSize-list->current) >= biggest); +} +/* + * Tell how much room is left + */ +static short roomLeft(ByteList * list){ + return list->maxSize - list->current; +} +/* + * Dump all commands to the printer and reset the structure + * + */ +static void dumpToPrinter(ByteList * list,FILE * printStream){ + short loopCounter; + /* Actual dump */ + /* Please note that current is the first empty byte */ + for (loopCounter = 0; loopCounter < list->current; loopCounter++) + { + fputc(list->data[loopCounter],printStream); + } + + /* Reset of the ByteList */ + list->current = 0; +} |