gdevhl7x.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. /* Copyright (C) 1997, 2001 artofcode LLC. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: gdevhl7x.c,v 1.10 2004/08/10 13:02:36 stefan Exp $ */
  14. /*
  15. * Brother HL 720 and 730 driver for Ghostscript
  16. *
  17. * Note: for the HL 760, use the HP driver.
  18. *
  19. * The original code was borrowed from the
  20. * HP LaserJet/DeskJet driver for Ghostscript.
  21. * The code specific to the Brother HL 720 was written by :
  22. * Pierre-Olivier Gaillard (pierre.gaillard@hol.fr)
  23. * Thanks to the documentation kindly provided by :
  24. * Richard Thomas <RICHARDT@brother.co.uk>
  25. *
  26. * Removal of compression code on 1/17/00 by Ross Martin
  27. * (ross@ross.interwrx.com, martin@walnut.eas.asu.edu)
  28. * enables this driver to correctly print tiger.eps on a
  29. * Brother MFC6550MC Fax Machine. Change to the Horizontal
  30. * Offset fixes incorrect page alignment at 300dpi in
  31. * Landscape mode with a2ps.
  32. */
  33. #include "gdevprn.h"
  34. /* The following line is used though these printers are not PCL printers*/
  35. /* This is because we want the paper size access function */
  36. /* (The 720 is a simple GDI printer) */
  37. #include "gdevpcl.h"
  38. /*
  39. * You may select a default resolution of 150 (for 730), 300, or
  40. * 600 DPI in the makefile, or an actual resolution on
  41. * the gs command line.
  42. *
  43. * If the preprocessor symbol A4 is defined, the default paper size is
  44. * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
  45. *
  46. * You may find the following test page useful in determining the exact
  47. * margin settings on your printer. It prints four big arrows which
  48. * point exactly to the for corners of an A4 sized paper. Of course the
  49. * arrows cannot appear in full on the paper, and they are truncated by
  50. * the margins. The margins measured on the testpage must match those
  51. * in gdevdjet.c. So the testpage indicates two facts: 1) the page is
  52. * not printed in the right position 2) the page is truncated too much
  53. * because the margins are wrong. Setting wrong margins in gdevdjet.c
  54. * will also move the page, so both facts should be matched with the
  55. * real world.
  56. %!
  57. newpath
  58. 0 0 moveto 144 72 lineto 72 144 lineto
  59. closepath fill stroke 0 0 moveto 144 144 lineto stroke
  60. 595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto
  61. closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke
  62. 0 841.88 moveto 144 769.88 lineto 72 697.88 lineto
  63. closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke
  64. 595.27 0 moveto 451.27 72 lineto 523.27 144 lineto
  65. closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke
  66. /Helvetica findfont
  67. 14 scalefont setfont
  68. 100 600 moveto
  69. (This is an A4 testpage. The arrows should point exactly to the) show
  70. 100 580 moveto
  71. (corners and the margins should match those given in gdev*.c) show
  72. showpage
  73. */
  74. /* Type definitions */
  75. typedef struct {
  76. short width; /* physical width of the paper */
  77. short height; /* physical height of the paper */
  78. } PaperFormat; /* Rep. of the charateristics of a sheet of paper */
  79. typedef unsigned char Byte; /* Rep. of elementary data unit */
  80. /*
  81. * Definition of a Helper structure to handle a list of commands
  82. */
  83. typedef struct {
  84. Byte * data;
  85. short maxSize;
  86. short current;
  87. } ByteList;
  88. /*
  89. * Type for representing a summary of the previous lines
  90. *
  91. */
  92. typedef struct {
  93. short previousSize;
  94. Byte previousData[1500]; /* Size bigger than any possible line */
  95. short nbBlankLines;
  96. short nbLinesSent;
  97. short pageWidth;
  98. short pageHeight;
  99. short horizontalOffset;
  100. short resolution;
  101. } Summary;
  102. /* Constants */
  103. /* We need a boolean : true , we got it from gdevprn.h */
  104. /* Other constants */
  105. private const int DumpFinished = 0;
  106. private const int DumpContinue = 1;
  107. private const int HL7X0_LENGTH = 5; /* Length of a command to tell the size of the data to be sent to the printer*/
  108. private void makeCommandsForSequence(Byte * pSource,
  109. short length,
  110. ByteList * pCommandList,
  111. short offset,
  112. Byte * pCommandCount,
  113. short rest);
  114. /* Auxiliary Functions */
  115. private int dumpPage(gx_device_printer * pSource,
  116. Byte * pLineTmp,
  117. ByteList * pCommandList,
  118. Summary * pSummary
  119. );
  120. private void initSummary(Summary * s,short pw, short ph, short resolution);
  121. private void resetPreviousData(Summary * s);
  122. private void makeFullLine( Byte * pCurrentLine,
  123. Byte * pPreviousLine,
  124. short lineWidth,
  125. ByteList * commandsList,
  126. short horizontalOffset
  127. );
  128. /*
  129. * Initialize a list of Bytes structure
  130. */
  131. private void initByteList(ByteList *list, Byte *array, short maxSize,short initCurrent);
  132. private void addByte(ByteList *list,Byte value );
  133. private void addArray(ByteList *list, Byte *source, short nb);
  134. private void addNBytes(ByteList * list, Byte value, short nb);
  135. private Byte * currentPosition(ByteList * list);
  136. private void addCodedNumber(ByteList * list, short number);
  137. private int isThereEnoughRoom(ByteList * list, short biggest);
  138. private short roomLeft(ByteList * list);
  139. private void dumpToPrinter(ByteList * list,FILE * printStream);
  140. /* Real Print function */
  141. private int hl7x0_print_page(gx_device_printer *, FILE *, int, int, ByteList *);
  142. /* Define the default, maximum resolutions. */
  143. #ifdef X_DPI
  144. # define X_DPI2 X_DPI
  145. #else
  146. # define X_DPI 300
  147. # define X_DPI2 600
  148. #endif
  149. #ifdef Y_DPI
  150. # define Y_DPI2 Y_DPI
  151. #else
  152. # define Y_DPI 300
  153. # define Y_DPI2 600
  154. #endif
  155. #define LETTER_WIDTH 5100
  156. #define LEFT_MARGIN 30
  157. /* The following table is not actually used.... */
  158. private const PaperFormat tableOfFormats[] = {
  159. /* 0 P LETTER */ { 2550, 3300 },
  160. /* 1 P LEGAL */ { 2550, 4200 },
  161. /* 2 P EXEC */ { 2175, 3150 },
  162. /* 3 P A4(78) */ { 2480, 3507 },
  163. /* 4 P B5 */ { 2078, 2953 },
  164. /* 5 P A5 */ { 1754, 2480 },
  165. /* 6 P MONARC */ { 1162, 2250 },
  166. /* 7 P COM10 */ { 1237, 2850 },
  167. /* 8 P DL */ { 1299, 2598 },
  168. /* 9 P C5 */ { 1913, 2704 },
  169. /* 10 P A4Long */ { 2480, 4783 },
  170. /* 11 L LETTER */ { 3300, 2550 },
  171. /* 12 L LEGAL */ { 4200, 2550 },
  172. /* 13 L EXEC */ { 3150, 2175 },
  173. /* 14 L A4 */ { 3507, 2480 },
  174. /* 15 L B5 */ { 2952, 2078 },
  175. /* 16 L A5 */ { 2480, 1754 },
  176. /* 17 L MONARC */ { 2250, 1162 },
  177. /* 18 L COM10 */ { 2850, 1237 },
  178. /* 19 L DL */ { 2598, 1299 },
  179. /* 20 L C5 */ { 2704, 1913 },
  180. /* 21 L A4Long */ { 4783, 2480 }
  181. };
  182. /* Compute the maximum length of a compressed line */
  183. private short MaxLineLength(short resolution){
  184. return (((156 * resolution / 150 ) * 5 )/4) + 8;
  185. }
  186. /* Margins are left, bottom, right, top. */
  187. /* Quotation from original gdevdjet.c */
  188. /* from Frans van Hoesel hoesel@rugr86.rug.nl. */
  189. /* A4 has a left margin of 1/8 inch and at a printing width of
  190. * 8 inch this give a right margin of 0.143. The 0.09 top margin is
  191. * not the actual margin - which is 0.07 - but compensates for the
  192. * inexact paperlength which is set to 117 10ths.
  193. * Somebody should check for letter sized paper. I left it at 0.07".
  194. */
  195. /* The A4 margins are almost good */
  196. /* The one for Letter are those of the gdevdjet.c file... */
  197. #define HL7X0_MARGINS_A4 0.1, 0.15, 0.07, 0.05
  198. #define HL7X0_MARGINS_LETTER 0.275, 0.20, 0.25, 0.07
  199. /* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
  200. #define W sizeof(word)
  201. /* Printer types */
  202. #define HL720 0
  203. #define HL730 0 /* No difference */
  204. /* The device descriptors */
  205. private dev_proc_open_device(hl7x0_open);
  206. private dev_proc_close_device(hl7x0_close);
  207. private dev_proc_print_page(hl720_print_page);
  208. private dev_proc_print_page(hl730_print_page);
  209. private const gx_device_procs prn_hl_procs =
  210. prn_params_procs(hl7x0_open, gdev_prn_output_page, hl7x0_close,
  211. gdev_prn_get_params, gdev_prn_put_params);
  212. const gx_device_printer far_data gs_hl7x0_device =
  213. prn_device(prn_hl_procs, "hl7x0",
  214. DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
  215. X_DPI, Y_DPI,
  216. 0, 0, 0, 0, /* margins filled in by hl7x0_open */
  217. 1, hl720_print_page); /* The hl720 and hl730 can both use the same print method */
  218. /* Open the printer, adjusting the margins if necessary. */
  219. private int
  220. hl7x0_open(gx_device *pdev)
  221. { /* Change the margins if necessary. */
  222. static const float m_a4[4] = { HL7X0_MARGINS_A4 };
  223. static const float m_letter[4] = { HL7X0_MARGINS_LETTER };
  224. const float *m =
  225. (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 : m_letter);
  226. gx_device_set_margins(pdev, m, true);
  227. return gdev_prn_open(pdev);
  228. }
  229. /* The orders sent are those provided in the Brother DOS example */
  230. private int
  231. hl7x0_close(gx_device *pdev)
  232. {
  233. gx_device_printer *const ppdev = (gx_device_printer *)pdev;
  234. int code = gdev_prn_open_printer(pdev, 1);
  235. if (code < 0)
  236. return code;
  237. fputs("@N@N@N@N@X", ppdev->file) ;
  238. return gdev_prn_close_printer(pdev);
  239. }
  240. /* ------ Internal routines ------ */
  241. /* The HL 720 can compress*/
  242. private int
  243. hl720_print_page(gx_device_printer *pdev, FILE *prn_stream)
  244. {
  245. Byte prefix[] ={
  246. 0x1B,'%','-','1','2','3','4','5','X'
  247. ,'@','P','J','L',0x0A /* set PJL mode */
  248. ,'@','P','J','L',' ','E','N','T','E','R',' '
  249. ,'L','A','N','G','U','A','G','E'
  250. ,' ','=',' ','H','B','P',0x0A /* set GDI Printer mode */
  251. ,'@','L', 0x0
  252. };
  253. ByteList initCommand;
  254. int x_dpi = pdev->x_pixels_per_inch;
  255. initByteList(&initCommand,
  256. prefix, /* Array */
  257. sizeof(prefix), /* Total size */
  258. sizeof(prefix) - 1); /* Leave one byte free since*/
  259. /* we need to add the following order at the end */
  260. addByte(&initCommand, (Byte) ((((600/x_dpi) >> 1) \
  261. | (((600/x_dpi) >> 1) << 2))));
  262. /* Put the value of the used resolution into the init string */
  263. return hl7x0_print_page(pdev, prn_stream, HL720, 300,
  264. &initCommand);
  265. }
  266. /* The HL 730 can compress */
  267. private int
  268. hl730_print_page(gx_device_printer *pdev, FILE *prn_stream)
  269. { return hl720_print_page(pdev, prn_stream);
  270. }
  271. /* Send the page to the printer. For speed, compress each scan line, */
  272. /* since computer-to-printer communication time is often a bottleneck. */
  273. private int
  274. hl7x0_print_page(gx_device_printer *pdev, FILE *printStream, int ptype,
  275. int dots_per_inch, ByteList *initCommand)
  276. {
  277. /* UTILE*/
  278. /* Command for a formFeed (we can't use strings because of the zeroes...)*/
  279. Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'};
  280. ByteList formFeedCommand;
  281. /* Main characteristics of the page */
  282. int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
  283. int x_dpi = pdev->x_pixels_per_inch;
  284. /* int y_dpi = pdev->y_pixels_per_inch; */
  285. int num_rows = dev_print_scan_lines(pdev);
  286. int result;
  287. int sizeOfBuffer = MaxLineLength(x_dpi) + 30;
  288. Byte * storage = (Byte *) gs_malloc(pdev->memory,
  289. sizeOfBuffer + line_size,
  290. 1,
  291. "hl7x0_print_page");
  292. /* bool dup = pdev->Duplex; */
  293. /* bool dupset = pdev->Duplex_set >= 0; */
  294. Summary pageSummary;
  295. ByteList commandsBuffer;
  296. initSummary(&pageSummary,
  297. line_size,
  298. num_rows,
  299. x_dpi);
  300. if ( storage == 0 ) /* can't allocate working area */
  301. return_error(gs_error_VMerror);
  302. initByteList(&commandsBuffer, storage, sizeOfBuffer,0 );
  303. /* PLUS A MOI */
  304. if ( pdev->PageCount == 0 )
  305. {
  306. /* Put out init string before first page. */
  307. dumpToPrinter(initCommand, printStream); /* send init to printer */
  308. }
  309. do {
  310. result = dumpPage(pdev,
  311. storage + sizeOfBuffer, /* The line buffer is after the dump buffer */
  312. &commandsBuffer,
  313. &pageSummary);
  314. dumpToPrinter(&commandsBuffer,printStream);
  315. } while (result == DumpContinue);
  316. /* end raster graphics and eject page */
  317. initByteList(&formFeedCommand,
  318. FormFeed, /* Array */
  319. sizeof(FormFeed), /* Size in bytes */
  320. sizeof(FormFeed)); /* First free byte */
  321. dumpToPrinter(&formFeedCommand, printStream);
  322. /* free temporary storage */
  323. gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page");
  324. return 0; /* If we reach this line, it means there was no error */
  325. }
  326. /*
  327. * Useful auxiliary declarations
  328. *
  329. */
  330. private short stripTrailingBlanks(Byte * line, short length){
  331. short positionOfFirstZero = length - 1;
  332. while (positionOfFirstZero > 0) {
  333. if (line[positionOfFirstZero] != 0) {
  334. return positionOfFirstZero + 1;
  335. }
  336. positionOfFirstZero -- ;
  337. }
  338. return 0;
  339. }
  340. /*
  341. * Changed the horizontalOffset function 1/17/00 Ross Martin.
  342. * ross@ross.interwrx.com or martin@walnut.eas.asu.edu
  343. *
  344. * The equation used to muliply pixWidth by resolution/600
  345. * also. This didn't work right at resolution 300; it caused
  346. * landscape pages produced by a2ps to be half off the
  347. * page, when they were not at 600dpi or on other
  348. * devices. I'm not sure the equation below is exactly
  349. * correct, but it now looks to be pretty close visually,
  350. * and works correctly at 600dpi and 300dpi.
  351. */
  352. private short horizontalOffset(short pixWidth,
  353. short pixOffset,
  354. short resolution){
  355. return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8;
  356. }
  357. /*
  358. * First values in a Summary
  359. */
  360. private void initSummary(Summary * s,short pw, short ph, short resolution){
  361. s->previousSize = -1 ;
  362. s->nbBlankLines = 1;
  363. s->nbLinesSent = 0;
  364. s->pageWidth = pw; /* In Bytes */
  365. s->pageHeight = ph;
  366. s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ;
  367. s->resolution = resolution;
  368. }
  369. /*
  370. * The previous line was blank, so we need to clean the corresponding array
  371. */
  372. private void resetPreviousData(Summary * s){
  373. memset(s->previousData,0,s->pageWidth);
  374. }
  375. /*
  376. * dumpPage :
  377. *
  378. */
  379. private int dumpPage(gx_device_printer * pSource,
  380. Byte * pLineTmp,
  381. ByteList * pCommandList,
  382. Summary * pSummary
  383. ){
  384. /* Declarations */
  385. Byte * pSaveCommandStart;
  386. short lineNB;
  387. short usefulLength;
  388. short tmpLength;
  389. /* Initializations */
  390. /* Make room for size of commands buffer */
  391. pSaveCommandStart = currentPosition(pCommandList);
  392. addNBytes(pCommandList,0,HL7X0_LENGTH);
  393. /* pSource += pSummary->nbLinesSent * pSummary->pageWidth;*/
  394. /* Process all possible Lines */
  395. for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ;
  396. lineNB < pSummary->pageHeight ; lineNB ++ ) {
  397. /* Fetch the line and put it into the buffer */
  398. gdev_prn_copy_scan_lines(pSource,
  399. lineNB,
  400. pLineTmp,
  401. pSummary->pageWidth);
  402. usefulLength = stripTrailingBlanks(pLineTmp,pSummary->pageWidth);
  403. if (usefulLength != 0) {
  404. /* The line is not blank */
  405. /* Get rid of the precedent blank lines */
  406. if (pSummary->nbBlankLines != 0) {
  407. if ( isThereEnoughRoom( pCommandList, pSummary->nbBlankLines ) ) {
  408. addNBytes(pCommandList,0xff,pSummary->nbBlankLines);
  409. pSummary->nbBlankLines = 0;
  410. }
  411. else {
  412. short availableRoom = roomLeft(pCommandList);
  413. addNBytes(pCommandList,0xff,availableRoom);
  414. pSummary->nbBlankLines -= availableRoom;
  415. break ; /* We have no more room */
  416. }
  417. resetPreviousData(pSummary); /* Make sure there are zeroes for the previous line */
  418. pSummary->previousSize = 0; /* The previous line was empty */
  419. }
  420. /* Deal with the current line */
  421. if (!isThereEnoughRoom(pCommandList,MaxLineLength(pSummary->resolution))){
  422. break; /* We can process this line */
  423. }
  424. if (pSummary->previousSize > usefulLength){
  425. tmpLength = pSummary->previousSize;
  426. }
  427. else {
  428. tmpLength = usefulLength;
  429. }
  430. if (pSummary->previousSize == -1 ) {/* This is the first line */
  431. Byte *save = currentPosition(pCommandList);
  432. addByte(pCommandList,0); /* One byte for the number of commands */
  433. makeCommandsForSequence(pLineTmp,
  434. tmpLength,
  435. pCommandList,
  436. pSummary->horizontalOffset,
  437. save,
  438. 0);
  439. }
  440. else { /*There is a previous line */
  441. makeFullLine(pLineTmp,
  442. pSummary->previousData,
  443. tmpLength,
  444. pCommandList,
  445. pSummary->horizontalOffset);
  446. }
  447. /* The present line will soon be considered as "previous" */
  448. pSummary->previousSize = tmpLength;
  449. /* Update the data representing the line will soon be the "previous line" */
  450. memcpy(pSummary->previousData,pLineTmp,tmpLength);
  451. }
  452. else { /* the current line is blank */
  453. pSummary->nbBlankLines++;
  454. }
  455. /* And one more line */
  456. pSummary->nbLinesSent ++;
  457. }
  458. if (pCommandList->current > HL7X0_LENGTH){
  459. short size = pCommandList->current - HL7X0_LENGTH;
  460. *(pSaveCommandStart++) = '@';
  461. *(pSaveCommandStart++) = 'G';
  462. *(pSaveCommandStart++) = (Byte) (size >> 16);
  463. *(pSaveCommandStart++) = (Byte) (size >> 8);
  464. *(pSaveCommandStart++) = (Byte) (size);
  465. }
  466. else { /* We only met blank lines and reached the end of the page */
  467. pCommandList->current = 0;
  468. }
  469. if (lineNB == pSummary->pageHeight){
  470. return DumpFinished;
  471. }
  472. else {
  473. return DumpContinue;
  474. }
  475. }
  476. /*
  477. * makeFullLine :
  478. * process an arbitrary line for which a former line is available
  479. * The line will be split in sequences that are different from the
  480. * corresponding ones of the previous line. These sequences will be processed
  481. * by makeCommandsOfSequence.
  482. */
  483. private void makeFullLine( Byte * pCurrentLine,
  484. Byte * pPreviousLine,
  485. short lineWidth,
  486. ByteList * commandsList,
  487. short horizontalOffset
  488. ){
  489. /* Declarations */
  490. Byte *pPreviousTmp;
  491. Byte *pCurrentTmp;
  492. Byte *pNumberOfCommands;
  493. int loopCounter;
  494. short remainingWidth;
  495. Byte *pStartOfSequence;
  496. /*****************/
  497. /* Special cases */
  498. /*****************/
  499. /* I believe this situation to be impossible */
  500. if (lineWidth <= 0) {
  501. addByte(commandsList,0xff);
  502. return;
  503. }
  504. /*******************/
  505. /* Initializations */
  506. /*******************/
  507. pNumberOfCommands = currentPosition(commandsList); /* Keep a pointer to the number of commands */
  508. addByte(commandsList,0); /* At the moment there are 0 commands */
  509. pPreviousTmp = pPreviousLine;
  510. pCurrentTmp = pCurrentLine;
  511. /* Build vector of differences with a Xor */
  512. for (loopCounter = lineWidth ; 0 < loopCounter ; loopCounter -- )
  513. *pPreviousTmp++ ^= *pCurrentTmp++;
  514. /* Find sequences that are different from the corresponding (i.e. vertically aligned)
  515. * one of the previous line. Make commands for them.
  516. */
  517. pStartOfSequence = pPreviousLine;
  518. remainingWidth = lineWidth;
  519. while (true) {
  520. /*
  521. * Disabled line-to-line compression, 1/17/00 Ross Martin
  522. * ross@ross.interwrx.com and/or martin@walnut.eas.asu.edu
  523. *
  524. * The compression here causes problems printing tiger.eps.
  525. * The problem is vertical streaks. The printer I'm printing
  526. * to is a Brother MFC6550MC Fax Machine, which may be
  527. * slightly different from the hl720 and hl730. Note that
  528. * this fax machine does support HP LaserJet 2p emulation,
  529. * but in order to enable it I believe one needs special
  530. * setup from a DOS program included with the printer. Thus,
  531. * the hl7x0 driver seems a better choice. In any case,
  532. * on the MFC6550MC, some files print fine with compression
  533. * turned on, but others such as tiger.eps print with streaks.
  534. * disabling the compression fixes the problem, so I haven't
  535. * looked any further at the cause. It may be that the
  536. * compression is correct for the hl720 and hl730, and only
  537. * different for the MFC6550MC, or it may be that tiger.eps
  538. * won't print correctly with compression enabled on any
  539. * of these. It may be that the problem is only with color
  540. * and/or grayscale prints. YMMV. I don't think it likely
  541. * that turning off compression will cause problems with
  542. * other printers, except that they may possibly print slower.
  543. */
  544. #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
  545. /* Count and skip bytes that are not "new" */
  546. while (true) {
  547. if (remainingWidth == 0) /* There is nothing left to do */
  548. {
  549. return;
  550. }
  551. if (*pStartOfSequence != 0)
  552. break;
  553. pStartOfSequence ++;
  554. horizontalOffset ++; /* the offset takes count of the bytes that are not "new" */
  555. --remainingWidth;
  556. }
  557. #endif
  558. pPreviousTmp = pStartOfSequence + 1; /* The sequence contains at least this byte */
  559. --remainingWidth;
  560. /* Find the end of the sequence of "new" bytes */
  561. #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
  562. while (remainingWidth != 0 && *pPreviousTmp != 0) {
  563. ++pPreviousTmp; /* Enlarge the sequence Of new bytes */
  564. --remainingWidth;
  565. }
  566. #else
  567. pPreviousTmp += remainingWidth;
  568. remainingWidth = 0;
  569. #endif
  570. makeCommandsForSequence(pCurrentLine + (pStartOfSequence - pPreviousLine),
  571. pPreviousTmp - pStartOfSequence,
  572. commandsList,
  573. horizontalOffset,
  574. pNumberOfCommands,
  575. remainingWidth);
  576. if (*pNumberOfCommands == 0xfe /* If the number of commands has reached the maximum value */
  577. || /* or */
  578. remainingWidth == 0 ) /* There is nothing left to process */
  579. {
  580. return;
  581. }
  582. pStartOfSequence = pPreviousTmp + 1; /* We go on right after the sequence of "new" bytes */
  583. horizontalOffset = 1;
  584. --remainingWidth;
  585. } /* End of While */
  586. } /* End of makeFullLine */
  587. /*
  588. * Declarations of functions that are defined further in the file
  589. */
  590. private void makeSequenceWithoutRepeat(
  591. Byte * pSequence,
  592. short lengthOfSequence,
  593. ByteList * pCommandList,
  594. short offset );
  595. private void makeSequenceWithRepeat(
  596. Byte * pSequence,
  597. short lengthOfSequence,
  598. ByteList * pCommandList,
  599. short offset );
  600. /*
  601. * makeCommandsForSequence :
  602. * Process a sequence of new bytes (i.e. different from the ones on the former line)
  603. */
  604. private void makeCommandsForSequence(Byte * pSource,
  605. short length,
  606. ByteList * pCommandList,
  607. short offset,
  608. Byte * pNumberOfCommands,
  609. short rest) {
  610. /* Declarations */
  611. Byte * pStartOfSequence;
  612. Byte * pEndOfSequence;
  613. short remainingLength = length - 1;
  614. pStartOfSequence = pSource;
  615. pEndOfSequence = pStartOfSequence + 1;
  616. /*
  617. * Process the whole "new" Sequence that is divided into
  618. * repetitive and non-repetitive sequences.
  619. */
  620. while (true) {
  621. /* If we have already stored too many commands, make one last command with
  622. * everything that is left in the line and return.
  623. */
  624. if (*pNumberOfCommands == 0xfd) {
  625. makeSequenceWithoutRepeat(pStartOfSequence,
  626. 1 + remainingLength + rest,
  627. pCommandList,
  628. offset);
  629. ++*pNumberOfCommands;
  630. return;
  631. }
  632. /* Start with a sub-sequence without byte-repetition */
  633. while (true) {
  634. /* If we have completed the last subsequence */
  635. if (remainingLength == 0) {
  636. makeSequenceWithoutRepeat(pStartOfSequence,
  637. pEndOfSequence - pStartOfSequence,
  638. pCommandList,
  639. offset);
  640. ++*pNumberOfCommands;
  641. return;
  642. }
  643. /* If we have discovered a repetition */
  644. if (*pEndOfSequence == *(pEndOfSequence - 1)) {
  645. break;
  646. }
  647. ++ pEndOfSequence; /* The subsequence is bigger*/
  648. --remainingLength;
  649. }
  650. /* If this is a sequence without repetition */
  651. if (pStartOfSequence != pEndOfSequence - 1) {
  652. makeSequenceWithoutRepeat(pStartOfSequence,
  653. (pEndOfSequence - 1) - pStartOfSequence,
  654. pCommandList,
  655. offset);
  656. ++*pNumberOfCommands;
  657. offset = 0;
  658. pStartOfSequence = pEndOfSequence - 1;
  659. /* If we have too many commands */
  660. if (*pNumberOfCommands == 0xfd) {
  661. makeSequenceWithoutRepeat(pStartOfSequence,
  662. 1 + remainingLength + rest,
  663. pCommandList,
  664. offset);
  665. ++*pNumberOfCommands;
  666. return;
  667. }
  668. } /* End If */
  669. /*
  670. * Process a subsequence that repeats the same byte
  671. */
  672. while (true) {
  673. /* If there is nothing left to process */
  674. if (remainingLength == 0) {
  675. makeSequenceWithRepeat(pStartOfSequence,
  676. pEndOfSequence - pStartOfSequence,
  677. pCommandList,
  678. offset);
  679. ++*pNumberOfCommands;
  680. return;
  681. }
  682. /* If we find a different byte */
  683. if (*pEndOfSequence != *pStartOfSequence){
  684. break;
  685. }
  686. ++pEndOfSequence; /* The subsequence is yet bigger */
  687. --remainingLength;
  688. } /* End of While */
  689. makeSequenceWithRepeat(pStartOfSequence,
  690. pEndOfSequence - pStartOfSequence,
  691. pCommandList,
  692. offset);
  693. ++*pNumberOfCommands;
  694. offset = 0; /* The relative offset between two subsequences is 0 */
  695. pStartOfSequence = pEndOfSequence ++ ; /* we loop again from the end of this subsequence */
  696. --remainingLength;
  697. } /* End of While */
  698. } /* End makeCommandsForSequence */
  699. /*
  700. * makeSequenceWithoutRepeat
  701. */
  702. private void makeSequenceWithoutRepeat(
  703. Byte * pSequence,
  704. short lengthOfSequence,
  705. ByteList * pCommandList,
  706. short offset ){
  707. /*
  708. * Constant definitions
  709. */
  710. static const short MAX_OFFSET = 15;
  711. static const short POSITION_OF_OFFSET = 3;
  712. static const short MAX_LENGTH = 7;
  713. Byte tmpFirstByte = 0;
  714. Byte * pSaveFirstByte;
  715. short reducedLength = lengthOfSequence - 1; /* Length is alway higher than 1
  716. Therefore a reduced value is stored
  717. */
  718. /* Initialization */
  719. pSaveFirstByte = currentPosition(pCommandList);
  720. addByte( pCommandList, 0 /* Dummy value */);
  721. /* Computations */
  722. if (offset >= MAX_OFFSET) {
  723. addCodedNumber(pCommandList,offset - MAX_OFFSET);
  724. tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  725. }
  726. else
  727. tmpFirstByte |= offset << POSITION_OF_OFFSET;
  728. if (reducedLength >= MAX_LENGTH) {
  729. addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
  730. tmpFirstByte |= MAX_LENGTH ;
  731. }
  732. else
  733. tmpFirstByte |= reducedLength ;
  734. /* Add a copy of the source sequence */
  735. addArray(pCommandList, pSequence, lengthOfSequence);
  736. /* Store the computed value of the first byte */
  737. *pSaveFirstByte = tmpFirstByte;
  738. return ;
  739. } /* End of makeSequenceWithoutRepeat */
  740. /*
  741. * makeSequenceWithRepeat
  742. */
  743. private void makeSequenceWithRepeat(
  744. Byte * pSequence,
  745. short lengthOfSequence,
  746. ByteList * pCommandList,
  747. short offset ){
  748. /*
  749. * Constant definitions
  750. */
  751. static const short MAX_OFFSET = 3;
  752. static const short POSITION_OF_OFFSET = 5;
  753. static const short MAX_LENGTH = 31;
  754. Byte tmpFirstByte = 0x80;
  755. Byte * pSaveFirstByte;
  756. short reducedLength = lengthOfSequence - 2; /* Length is always higher than 2
  757. Therefore a reduced value is stored
  758. */
  759. /* Initialization */
  760. pSaveFirstByte = currentPosition(pCommandList);
  761. addByte( pCommandList, 0 /* Dummy value */);
  762. /* Computations */
  763. if (offset >= MAX_OFFSET) {
  764. addCodedNumber(pCommandList, offset - MAX_OFFSET);
  765. tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  766. }
  767. else
  768. tmpFirstByte |= offset << POSITION_OF_OFFSET;
  769. if (reducedLength >= MAX_LENGTH) {
  770. addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
  771. tmpFirstByte |= MAX_LENGTH ;
  772. }
  773. else
  774. tmpFirstByte |= reducedLength ;
  775. /* Add a copy the byte that is repeated throughout the sequence */
  776. addByte(pCommandList, *pSequence );
  777. /* Store the computed value of the first byte */
  778. *pSaveFirstByte = tmpFirstByte;
  779. return ;
  780. } /* End of makeSequenceWithRepeat*/
  781. /*
  782. * Initialize a list of Bytes structure
  783. */
  784. private void initByteList(ByteList *list, Byte *array, short maxSize, short initCurrent) {
  785. list->current = initCurrent;
  786. list->maxSize = maxSize;
  787. list->data = array;
  788. }
  789. /*
  790. * Add a Byte to a list of Bytes
  791. */
  792. private void addByte(ByteList *list,Byte value ) {
  793. if (list->current < list->maxSize)
  794. list->data[list->current++] = value;
  795. else
  796. errprintf("Could not add byte to command\n");
  797. }
  798. /*
  799. * Add a copy of an array to a list of Bytes
  800. */
  801. private void addArray(ByteList *list, Byte *source, short nb){
  802. if (list->current <= list->maxSize - nb)
  803. {
  804. memcpy(list->data + list->current, source , (size_t) nb);
  805. list->current += nb;
  806. }
  807. else
  808. errprintf("Could not add byte array to command\n");
  809. }
  810. /*
  811. * Add N bytes to a list of Bytes
  812. */
  813. private void addNBytes(ByteList * list, Byte value, short nb){
  814. int i;
  815. if (list->current <= list->maxSize - nb)
  816. {
  817. for (i = list->current ; i < (list->current + nb) ; i++)
  818. {
  819. list->data[i] = value;
  820. }
  821. list->current += nb;
  822. }
  823. else
  824. errprintf("Could not add %d bytes to command\n",nb);
  825. }
  826. /*
  827. * Get pointer to the current byte
  828. */
  829. private Byte * currentPosition(ByteList * list) {
  830. return &(list->data[list->current]);
  831. }
  832. /*
  833. * add a number coded in the following way :
  834. * q bytes with 0xff value
  835. * 1 byte with r value
  836. * where q is the quotient of the number divided by 0xff and r is the
  837. * remainder.
  838. */
  839. private void addCodedNumber(ByteList * list, short number){
  840. short q = number / 0xff;
  841. short r = number % 0xff;
  842. addNBytes(list, 0xff, q);
  843. addByte(list,r);
  844. }
  845. /*
  846. * See if there is enough room for a set of commands of size biggest
  847. *
  848. */
  849. private int isThereEnoughRoom(ByteList * list, short biggest){
  850. return ((list->maxSize-list->current) >= biggest);
  851. }
  852. /*
  853. * Tell how much room is left
  854. */
  855. private short roomLeft(ByteList * list){
  856. return list->maxSize - list->current;
  857. }
  858. /*
  859. * Dump all commands to the printer and reset the structure
  860. *
  861. */
  862. private void dumpToPrinter(ByteList * list,FILE * printStream){
  863. short loopCounter;
  864. /* Actual dump */
  865. /* Please note that current is the first empty byte */
  866. for (loopCounter = 0; loopCounter < list->current; loopCounter++)
  867. {
  868. fputc(list->data[loopCounter],printStream);
  869. }
  870. /* Reset of the ByteList */
  871. list->current = 0;
  872. }