output-pcl.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include <limits.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. /* Lifted from ghostscript gdevjlm.h */
  27. /*
  28. * The notion that there is such a thing as a "PCL printer" is a fiction: no
  29. * two "PCL" printers, even at the same PCL level, have identical command
  30. * sets. (The H-P documentation isn't fully accurate either; for example,
  31. * it doesn't reveal that the DeskJet printers implement anything beyond PCL
  32. * 3.)
  33. *
  34. * This file contains feature definitions for a generic monochrome PCL
  35. * driver (gdevdljm.c), and the specific feature values for all such
  36. * printers that Ghostscript currently supports.
  37. */
  38. /* Printer spacing capabilities. Include at most one of these. */
  39. #define PCL_NO_SPACING 0 /* no vertical spacing capability, must be 0 */
  40. #define PCL3_SPACING 1 /* <ESC>*p+<n>Y (PCL 3) */
  41. #define PCL4_SPACING 2 /* <ESC>*b<n>Y (PCL 4) */
  42. #define PCL5_SPACING 4 /* <ESC>*b<n>Y and clear seed row (PCL 5) */
  43. /* The following is only used internally. */
  44. #define PCL_ANY_SPACING \
  45. (PCL3_SPACING | PCL4_SPACING | PCL5_SPACING)
  46. /* Individual printer properties. Any subset of these may be included. */
  47. #define PCL_MODE_2_COMPRESSION 8 /* compression mode 2 supported */
  48. /* (PCL 4) */
  49. #define PCL_MODE_3_COMPRESSION 16 /* compression modes 2 & 3 supported */
  50. /* (PCL 5) */
  51. #define PCL_END_GRAPHICS_DOES_RESET 32 /* <esc>*rB resets all parameters */
  52. #define PCL_HAS_DUPLEX 64 /* <esc>&l<duplex>S supported */
  53. #define PCL_CAN_SET_PAPER_SIZE 128 /* <esc>&l<sizecode>A supported */
  54. #define PCL_CAN_PRINT_COPIES 256 /* <esc>&l<copies>X supported */
  55. #define HACK__IS_A_LJET4PJL 512
  56. #define HACK__IS_A_OCE9050 1024
  57. #define PCL_HAS_ORIENTATION 2048
  58. #define PCL_CAN_SET_CUSTOM_PAPER_SIZE 4096
  59. #define PCL_HAS_RICOH_PAPER_SIZES 8192
  60. /* Shorthands for the most common spacing/compression combinations. */
  61. #define PCL_MODE0 PCL3_SPACING
  62. #define PCL_MODE0NS PCL_NO_SPACING
  63. #define PCL_MODE2 (PCL4_SPACING | PCL_MODE_2_COMPRESSION)
  64. #define PCL_MODE2P (PCL_NO_SPACING | PCL_MODE_2_COMPRESSION)
  65. #define PCL_MODE3 (PCL5_SPACING | PCL_MODE_3_COMPRESSION)
  66. #define PCL_MODE3NS (PCL_NO_SPACING | PCL_MODE_3_COMPRESSION)
  67. #define MIN_SKIP_LINES 7
  68. static const char *const from2to3 = "\033*b3M";
  69. static const char *const from3to2 = "\033*b2M";
  70. static const int penalty_from2to3 = 5; /* strlen(from2to3); */
  71. static const int penalty_from3to2 = 5; /* strlen(from3to2); */
  72. /* Generic */
  73. static const fz_pcl_options fz_pcl_options_generic =
  74. {
  75. (PCL_MODE2 | PCL_END_GRAPHICS_DOES_RESET | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_SET_CUSTOM_PAPER_SIZE),
  76. "\033&k1W\033*b2M",
  77. "\033&k1W\033*b2M"
  78. };
  79. /* H-P DeskJet */
  80. static const fz_pcl_options fz_pcl_options_ljet4 =
  81. {
  82. (PCL_MODE2 | PCL_END_GRAPHICS_DOES_RESET | PCL_CAN_SET_PAPER_SIZE),
  83. "\033&k1W\033*b2M",
  84. "\033&k1W\033*b2M"
  85. };
  86. /* H-P DeskJet 500 */
  87. static const fz_pcl_options fz_pcl_options_dj500 =
  88. {
  89. (PCL_MODE3 | PCL_END_GRAPHICS_DOES_RESET | PCL_CAN_SET_PAPER_SIZE),
  90. "\033&k1W",
  91. "\033&k1W"
  92. };
  93. /* Kyocera FS-600 */
  94. static const fz_pcl_options fz_pcl_options_fs600 =
  95. {
  96. (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES),
  97. "\033*r0F\033&u%dD",
  98. "\033*r0F\033&u%dD"
  99. };
  100. /* H-P original LaserJet */
  101. /* H-P LaserJet Plus */
  102. static const fz_pcl_options fz_pcl_options_lj =
  103. {
  104. (PCL_MODE0),
  105. "\033*b0M",
  106. "\033*b0M"
  107. };
  108. /* H-P LaserJet IIp, IId */
  109. static const fz_pcl_options fz_pcl_options_lj2 =
  110. {
  111. (PCL_MODE2P | PCL_CAN_SET_PAPER_SIZE),
  112. "\033*r0F\033*b2M",
  113. "\033*r0F\033*b2M"
  114. };
  115. /* H-P LaserJet III* */
  116. static const fz_pcl_options fz_pcl_options_lj3 =
  117. {
  118. (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES),
  119. "\033&l-180u36Z\033*r0F",
  120. "\033&l-180u36Z\033*r0F"
  121. };
  122. /* H-P LaserJet IIId */
  123. static const fz_pcl_options fz_pcl_options_lj3d =
  124. {
  125. (PCL_MODE3 | PCL_HAS_DUPLEX | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES),
  126. "\033&l-180u36Z\033*r0F",
  127. "\033&l180u36Z\033*r0F"
  128. };
  129. /* H-P LaserJet 4 */
  130. static const fz_pcl_options fz_pcl_options_lj4 =
  131. {
  132. (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES),
  133. "\033&l-180u36Z\033*r0F\033&u%dD",
  134. "\033&l-180u36Z\033*r0F\033&u%dD"
  135. };
  136. /* H-P LaserJet 4 PL */
  137. static const fz_pcl_options fz_pcl_options_lj4pl =
  138. {
  139. (PCL_MODE3 | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES | HACK__IS_A_LJET4PJL),
  140. "\033&l-180u36Z\033*r0F\033&u%dD",
  141. "\033&l-180u36Z\033*r0F\033&u%dD"
  142. };
  143. /* H-P LaserJet 4d */
  144. static const fz_pcl_options fz_pcl_options_lj4d =
  145. {
  146. (PCL_MODE3 | PCL_HAS_DUPLEX | PCL_CAN_SET_PAPER_SIZE | PCL_CAN_PRINT_COPIES),
  147. "\033&l-180u36Z\033*r0F\033&u%dD",
  148. "\033&l180u36Z\033*r0F\033&u%dD"
  149. };
  150. /* H-P 2563B line printer */
  151. static const fz_pcl_options fz_pcl_options_lp2563b =
  152. {
  153. (PCL_MODE0NS | PCL_CAN_SET_PAPER_SIZE),
  154. "\033*b0M",
  155. "\033*b0M"
  156. };
  157. /* OCE 9050 line printer */
  158. static const fz_pcl_options fz_pcl_options_oce9050 =
  159. {
  160. (PCL_MODE3NS | PCL_CAN_SET_PAPER_SIZE | HACK__IS_A_OCE9050),
  161. "\033*b0M",
  162. "\033*b0M"
  163. };
  164. enum {
  165. eLetterPaper = 0,
  166. eLegalPaper,
  167. eA4Paper,
  168. eExecPaper,
  169. eLedgerPaper,
  170. eA3Paper,
  171. eCOM10Envelope,
  172. eMonarchEnvelope,
  173. eC5Envelope,
  174. eDLEnvelope,
  175. eJB4Paper,
  176. eJB5Paper,
  177. eB5Envelope,
  178. eB5Paper, /* 2.1 */
  179. eJPostcard,
  180. eJDoublePostcard,
  181. eA5Paper,
  182. eA6Paper, /* 2.0 */
  183. eJB6Paper, /* 2.0 */
  184. eJIS8K, /* 2.1 */
  185. eJIS16K, /* 2.1 */
  186. eJISExec, /* 2.1 */
  187. eDefaultPaperSize = 96, /* 2.1 */
  188. eCustomPaperSize = 101,
  189. eB6JIS = 201, /* non-standard, Ricoh printers */
  190. eC6Envelope = 202, /* non-standard, Ricoh printers */
  191. e8Kai = 203, /* non-standard, Ricoh printers */
  192. e16Kai = 204, /* non-standard, Ricoh printers */
  193. e12x18 = 205, /* non-standard, Ricoh printers */
  194. e13x19_2 = 212, /* non-standard, Ricoh printers */
  195. e13x19 = 213, /* non-standard, Ricoh printers */
  196. e12_6x19_2 = 214, /* non-standard, Ricoh printers */
  197. e12_6x18_5 = 215, /* non-standard, Ricoh printers */
  198. e13x18 = 216, /* non-standard, Ricoh printers */
  199. eSRA3 = 217, /* non-standard, Ricoh printers */
  200. eSRA4 = 218, /* non-standard, Ricoh printers */
  201. e226x310 = 219, /* non-standard, Ricoh printers */
  202. e310x432 = 220, /* non-standard, Ricoh printers */
  203. eEngQuatro = 221, /* non-standard, Ricoh printers */
  204. e11x14 = 222, /* non-standard, Ricoh printers */
  205. e11x15 = 223, /* non-standard, Ricoh printers */
  206. e10x14 = 224, /* non-standard, Ricoh printers */
  207. };
  208. static void copy_opts(fz_pcl_options *dst, const fz_pcl_options *src)
  209. {
  210. if (dst)
  211. *dst = *src;
  212. }
  213. const char *fz_pcl_write_options_usage =
  214. "PCL output options:\n"
  215. "\tcolorspace=mono: render 1-bit black and white page\n"
  216. "\tcolorspace=rgb: render full color page\n"
  217. "\tpreset=generic|ljet4|dj500|fs600|lj|lj2|lj3|lj3d|lj4|lj4pl|lj4d|lp2563b|oce9050\n"
  218. "\tspacing=0: No vertical spacing capability\n"
  219. "\tspacing=1: PCL 3 spacing (<ESC>*p+<n>Y)\n"
  220. "\tspacing=2: PCL 4 spacing (<ESC>*b<n>Y)\n"
  221. "\tspacing=3: PCL 5 spacing (<ESC>*b<n>Y and clear seed row)\n"
  222. "\tmode2: Enable mode 2 graphics compression\n"
  223. "\tmode3: Enable mode 3 graphics compression\n"
  224. "\teog_reset: End of graphics (<ESC>*rB) resets all parameters\n"
  225. "\thas_duplex: Duplex supported (<ESC>&l<duplex>S)\n"
  226. "\thas_papersize: Papersize setting supported (<ESC>&l<sizecode>A)\n"
  227. "\thas_copies: Number of copies supported (<ESC>&l<copies>X)\n"
  228. "\tis_ljet4pjl: Disable/Enable HP 4PJL model-specific output\n"
  229. "\tis_oce9050: Disable/Enable Oce 9050 model-specific output\n"
  230. "\n";
  231. void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset)
  232. {
  233. if (preset == NULL || *preset == 0 || !strcmp(preset, "generic"))
  234. copy_opts(opts, &fz_pcl_options_generic);
  235. else if (!strcmp(preset, "ljet4"))
  236. copy_opts(opts, &fz_pcl_options_ljet4);
  237. else if (!strcmp(preset, "dj500"))
  238. copy_opts(opts, &fz_pcl_options_dj500);
  239. else if (!strcmp(preset, "fs600"))
  240. copy_opts(opts, &fz_pcl_options_fs600);
  241. else if (!strcmp(preset, "lj"))
  242. copy_opts(opts, &fz_pcl_options_lj);
  243. else if (!strcmp(preset, "lj2"))
  244. copy_opts(opts, &fz_pcl_options_lj2);
  245. else if (!strcmp(preset, "lj3"))
  246. copy_opts(opts, &fz_pcl_options_lj3);
  247. else if (!strcmp(preset, "lj3d"))
  248. copy_opts(opts, &fz_pcl_options_lj3d);
  249. else if (!strcmp(preset, "lj4"))
  250. copy_opts(opts, &fz_pcl_options_lj4);
  251. else if (!strcmp(preset, "lj4pl"))
  252. copy_opts(opts, &fz_pcl_options_lj4pl);
  253. else if (!strcmp(preset, "lj4d"))
  254. copy_opts(opts, &fz_pcl_options_lj4d);
  255. else if (!strcmp(preset, "lp2563b"))
  256. copy_opts(opts, &fz_pcl_options_lp2563b);
  257. else if (!strcmp(preset, "oce9050"))
  258. copy_opts(opts, &fz_pcl_options_oce9050);
  259. else
  260. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unknown preset '%s'", preset);
  261. }
  262. fz_pcl_options *
  263. fz_parse_pcl_options(fz_context *ctx, fz_pcl_options *opts, const char *args)
  264. {
  265. const char *val;
  266. memset(opts, 0, sizeof *opts);
  267. if (fz_has_option(ctx, args, "preset", &val))
  268. fz_pcl_preset(ctx, opts, val);
  269. else
  270. fz_pcl_preset(ctx, opts, "generic");
  271. if (fz_has_option(ctx, args, "spacing", &val))
  272. {
  273. switch (atoi(val))
  274. {
  275. case 0: opts->features &= ~PCL_ANY_SPACING; break;
  276. case 1: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL3_SPACING; break;
  277. case 2: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL4_SPACING; break;
  278. case 3: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL5_SPACING; break;
  279. default: fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unsupported PCL spacing %d (0-3 only)", atoi(val));
  280. }
  281. }
  282. if (fz_has_option(ctx, args, "mode2", &val))
  283. {
  284. if (fz_option_eq(val, "no"))
  285. opts->features &= ~PCL_MODE_2_COMPRESSION;
  286. else if (fz_option_eq(val, "yes"))
  287. opts->features |= PCL_MODE_2_COMPRESSION;
  288. else
  289. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for mode2 value");
  290. }
  291. if (fz_has_option(ctx, args, "mode3", &val))
  292. {
  293. if (fz_option_eq(val, "no"))
  294. opts->features &= ~PCL_MODE_3_COMPRESSION;
  295. else if (fz_option_eq(val, "yes"))
  296. opts->features |= PCL_MODE_3_COMPRESSION;
  297. else
  298. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for mode3 value");
  299. }
  300. if (fz_has_option(ctx, args, "eog_reset", &val))
  301. {
  302. if (fz_option_eq(val, "no"))
  303. opts->features &= ~PCL_END_GRAPHICS_DOES_RESET;
  304. else if (fz_option_eq(val, "yes"))
  305. opts->features |= PCL_END_GRAPHICS_DOES_RESET;
  306. else
  307. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for eog_reset value");
  308. }
  309. if (fz_has_option(ctx, args, "has_duplex", &val))
  310. {
  311. if (fz_option_eq(val, "no"))
  312. opts->features &= ~PCL_HAS_DUPLEX;
  313. else if (fz_option_eq(val, "yes"))
  314. opts->features |= PCL_HAS_DUPLEX;
  315. else
  316. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for has_duplex value");
  317. }
  318. if (fz_has_option(ctx, args, "has_papersize", &val))
  319. {
  320. if (fz_option_eq(val, "no"))
  321. opts->features &= ~PCL_CAN_SET_PAPER_SIZE;
  322. else if (fz_option_eq(val, "yes"))
  323. opts->features |= PCL_CAN_SET_PAPER_SIZE;
  324. else
  325. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for has_papersize value");
  326. }
  327. if (fz_has_option(ctx, args, "has_copies", &val))
  328. {
  329. if (fz_option_eq(val, "no"))
  330. opts->features &= ~PCL_CAN_PRINT_COPIES;
  331. else if (fz_option_eq(val, "yes"))
  332. opts->features |= PCL_CAN_PRINT_COPIES;
  333. else
  334. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for has_papersize value");
  335. }
  336. if (fz_has_option(ctx, args, "is_ljet4pjl", &val))
  337. {
  338. if (fz_option_eq(val, "no"))
  339. opts->features &= ~HACK__IS_A_LJET4PJL;
  340. else if (fz_option_eq(val, "yes"))
  341. opts->features |= HACK__IS_A_LJET4PJL;
  342. else
  343. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for is_ljet4pjl value");
  344. }
  345. if (fz_has_option(ctx, args, "is_oce9050", &val))
  346. {
  347. if (fz_option_eq(val, "no"))
  348. opts->features &= ~HACK__IS_A_OCE9050;
  349. else if (fz_option_eq(val, "yes"))
  350. opts->features |= HACK__IS_A_OCE9050;
  351. else
  352. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Expected 'yes' or 'no' for is_oce9050 value");
  353. }
  354. return opts;
  355. }
  356. static void
  357. make_init(fz_pcl_options *pcl, char *buf, unsigned long len, const char *str, int res)
  358. {
  359. int paper_source = -1;
  360. fz_snprintf(buf, len, str, res);
  361. if (pcl->manual_feed_set && pcl->manual_feed)
  362. paper_source = 2;
  363. else if (pcl->media_position_set && pcl->media_position >= 0)
  364. paper_source = pcl->media_position;
  365. if (paper_source >= 0)
  366. {
  367. char buf2[40];
  368. fz_snprintf(buf2, sizeof(buf2), "\033&l%dH", paper_source);
  369. strncat(buf, buf2, len);
  370. }
  371. }
  372. static void
  373. pcl_header(fz_context *ctx, fz_output *out, fz_pcl_options *pcl, int num_copies, int xres, int yres, int w, int h)
  374. {
  375. char odd_page_init[80];
  376. char even_page_init[80];
  377. make_init(pcl, odd_page_init, sizeof(odd_page_init), pcl->odd_page_init, xres);
  378. make_init(pcl, even_page_init, sizeof(even_page_init), pcl->even_page_init, xres);
  379. if (pcl->page_count == 0)
  380. {
  381. if (pcl->features & HACK__IS_A_LJET4PJL)
  382. fz_write_string(ctx, out, "\033%-12345X@PJL\r\n@PJL ENTER LANGUAGE = PCL\r\n");
  383. fz_write_string(ctx, out, "\033E"); /* reset printer */
  384. /* Reset the margins */
  385. /* ESC & l # E = Top Margin in decipoints */
  386. fz_write_string(ctx, out, "\033&l0E");
  387. /* ESC & l # U = Left (Long-Edge) offset registration */
  388. /* I don't like it that we have to hardcode -180 decipoints in here, but it seems to work. */
  389. fz_write_string(ctx, out, "\033&l-180U");
  390. /* ESC & l # Z = Top (Short-Edge) offset registration */
  391. fz_write_string(ctx, out, "\033&l0Z");
  392. /* If the printer supports it, set orientation */
  393. if (pcl->features & PCL_HAS_ORIENTATION)
  394. {
  395. fz_write_printf(ctx, out, "\033&l%dO", pcl->orientation);
  396. }
  397. /* If the printer supports it, set the paper size */
  398. /* based on the actual requested size. */
  399. if (pcl->features & PCL_CAN_SET_PAPER_SIZE)
  400. {
  401. /* It probably never hurts to define the page explicitly */
  402. {
  403. int decipointw = (w * 720 + (xres>>1)) / xres;
  404. int decipointh = (h * 720 + (yres>>1)) / yres;
  405. fz_write_printf(ctx, out, "\033&f%dI", decipointw);
  406. fz_write_printf(ctx, out, "\033&f%dJ", decipointh);
  407. }
  408. fz_write_printf(ctx, out, "\033&l%dA", pcl->paper_size);
  409. }
  410. /* If printer can duplex, set duplex mode appropriately. */
  411. if (pcl->features & PCL_HAS_DUPLEX)
  412. {
  413. if (pcl->duplex_set)
  414. {
  415. if (pcl->duplex)
  416. {
  417. if (!pcl->tumble)
  418. fz_write_string(ctx, out, "\033&l1S");
  419. else
  420. fz_write_string(ctx, out, "\033&l2S");
  421. }
  422. else
  423. fz_write_string(ctx, out, "\033&l0S");
  424. }
  425. else
  426. {
  427. /* default to duplex for this printer */
  428. fz_write_string(ctx, out, "\033&l1S");
  429. }
  430. }
  431. }
  432. /* Put out per-page initialization. */
  433. /* In duplex mode the sheet is already in process, so there are some
  434. * commands which must not be sent to the printer for the 2nd page,
  435. * as these commands will cause the printer to eject the sheet with
  436. * only the 1st page printed. These commands are:
  437. * \033&l%dA (setting paper size)
  438. * \033&l%dH (setting paper tray)
  439. * in simplex mode we set these parameters for each page,
  440. * in duplex mode we set these parameters for each odd page
  441. */
  442. if ((pcl->features & PCL_HAS_DUPLEX) && pcl->duplex_set && pcl->duplex)
  443. {
  444. /* We are printing duplex, so change margins as needed */
  445. if (((pcl->page_count/num_copies)%2) == 0)
  446. {
  447. if (pcl->page_count != 0 && (pcl->features & PCL_CAN_SET_PAPER_SIZE))
  448. {
  449. fz_write_printf(ctx, out, "\033&l%dA", pcl->paper_size);
  450. }
  451. fz_write_string(ctx, out, "\033&l0o0l0E");
  452. fz_write_string(ctx, out, pcl->odd_page_init);
  453. }
  454. else
  455. fz_write_string(ctx, out, pcl->even_page_init);
  456. }
  457. else
  458. {
  459. if (pcl->features & PCL_CAN_SET_PAPER_SIZE)
  460. {
  461. fz_write_printf(ctx, out, "\033&l%dA", pcl->paper_size);
  462. }
  463. fz_write_string(ctx, out, "\033&l0o0l0E");
  464. fz_write_string(ctx, out, pcl->odd_page_init);
  465. }
  466. fz_write_printf(ctx, out, "\033&l%dX", num_copies); /* # of copies */
  467. /* End raster graphics, position cursor at top. */
  468. fz_write_string(ctx, out, "\033*rB\033*p0x0Y");
  469. /* The DeskJet and DeskJet Plus reset everything upon */
  470. /* receiving \033*rB, so we must reinitialize graphics mode. */
  471. if (pcl->features & PCL_END_GRAPHICS_DOES_RESET)
  472. {
  473. fz_write_string(ctx, out, pcl->odd_page_init); /* Assume this does the right thing */
  474. fz_write_printf(ctx, out, "\033&l%dX", num_copies); /* # of copies */
  475. }
  476. /* Set resolution. */
  477. fz_write_printf(ctx, out, "\033*t%dR", xres);
  478. /* Raster units */
  479. /* 96,100,120,144,150,160,180,200,225,240,288,300,360,400,450,480,600,720,800,900,1200,1440,1800,2400,3600,7200 */
  480. /* FIXME: xres vs yres */
  481. fz_write_printf(ctx, out, "\033&u%dD", xres);
  482. pcl->page_count++;
  483. }
  484. typedef struct pcl_papersize_s
  485. {
  486. int code;
  487. const char *text;
  488. int width;
  489. int height;
  490. } pcl_papersize;
  491. static const pcl_papersize papersizes[] =
  492. {
  493. { eLetterPaper, "letter", 2550, 3300},
  494. { eLegalPaper, "legal", 2550, 4200},
  495. { eA4Paper, "a4", 2480, 3507},
  496. { eExecPaper, "executive", 2175, 3150},
  497. { eLedgerPaper, "ledger", 3300, 5100},
  498. { eA3Paper, "a3", 3507, 4960},
  499. { eCOM10Envelope, "com10", 1237, 2850},
  500. { eMonarchEnvelope, "monarch", 1162, 2250},
  501. { eC5Envelope, "c5", 1913, 2704},
  502. { eDLEnvelope, "dl", 1299, 2598},
  503. { eJB4Paper, "jisb4", 3035, 4299},
  504. { eJB4Paper, "jis b4", 3035, 4299},
  505. { eJB5Paper, "jisb5", 2150, 3035},
  506. { eJB5Paper, "jis b5", 2150, 3035},
  507. { eB5Envelope, "b5", 2078, 2952},
  508. { eB5Paper, "b5paper", 2150, 3035},
  509. { eJPostcard, "jpost", 1181, 1748},
  510. { eJDoublePostcard, "jpostd", 2362, 1748},
  511. { eA5Paper, "a5", 1748, 2480},
  512. { eA6Paper, "a6", 1240, 1748},
  513. { eJB6Paper, "jisb6", 1512, 2150},
  514. { eJIS8K, "jis8K", 3154, 4606},
  515. { eJIS16K, "jis16K", 2303, 3154},
  516. { eJISExec, "jisexec", 2551, 3898},
  517. { eB6JIS, "B6 (JIS)", 1512, 2150},
  518. { eC6Envelope, "C6", 1345, 1912},
  519. { e8Kai, "8Kai", 3154, 4608},
  520. { e16Kai, "16Kai", 2304, 3154},
  521. { e12x18, "12x18", 3600, 5400},
  522. { e13x19_2, "13x19.2", 3900, 5758},
  523. { e13x19, "13x19", 3900, 5700},
  524. { e12_6x19_2, "12.6x19.2", 3779, 5758},
  525. { e12_6x18_5, "12.6x18.5", 3779, 5550},
  526. { e13x18, "13x18", 3900, 5400},
  527. { eSRA3, "SRA3", 3779, 5316},
  528. { eSRA4, "SRA4", 2658, 3779},
  529. { e226x310, "226x310", 2670, 3662},
  530. { e310x432, "310x432", 3662, 5104},
  531. { eEngQuatro, "EngQuatro", 2400, 3000},
  532. { e11x14, "11x14", 3300, 4200},
  533. { e11x15, "11x15", 3300, 4500},
  534. { e10x14, "10x14", 3000, 4200}
  535. };
  536. static void guess_paper_size(fz_pcl_options *pcl, int w, int h, int xres, int yres)
  537. {
  538. int size;
  539. int rotated = 0;
  540. /* If we've been given a paper size, live with it */
  541. if (pcl->paper_size != 0)
  542. return;
  543. w = w * 300 / xres;
  544. h = h * 300 / xres;
  545. /* Look for an exact match */
  546. for (size = 0; size < (int)nelem(papersizes); size++)
  547. {
  548. if (papersizes[size].code > eCustomPaperSize && (pcl->features & PCL_HAS_RICOH_PAPER_SIZES) == 0)
  549. continue;
  550. if (w == papersizes[size].width && h == papersizes[size].height)
  551. break;
  552. if ((pcl->features & PCL_HAS_ORIENTATION) && w == papersizes[size].height && h == papersizes[size].width)
  553. {
  554. rotated = 1;
  555. break;
  556. }
  557. }
  558. /* If we didn't find an exact match, find the smallest one that's
  559. * larger. Consider orientation if our printer supports it. */
  560. if (size == nelem(papersizes))
  561. {
  562. if ((pcl->features & PCL_CAN_SET_CUSTOM_PAPER_SIZE) != 0)
  563. {
  564. /* Send it as a custom size */
  565. size = eCustomPaperSize;
  566. }
  567. else
  568. {
  569. /* Send the next larger one (minimise waste) */
  570. int i;
  571. int best_waste = INT_MAX;
  572. for (i = 0; i < (int)nelem(papersizes); i++)
  573. {
  574. int waste;
  575. if (papersizes[i].code > eCustomPaperSize && (pcl->features & PCL_HAS_RICOH_PAPER_SIZES) == 0)
  576. continue;
  577. waste = papersizes[i].width * papersizes[i].height - w * h;
  578. if (waste > best_waste)
  579. continue;
  580. if (w <= papersizes[i].width && h <= papersizes[i].height)
  581. {
  582. best_waste = waste;
  583. rotated = 0;
  584. size = i;
  585. }
  586. if ((pcl->features & PCL_HAS_ORIENTATION) && w <= papersizes[i].height && h <= papersizes[i].width)
  587. {
  588. best_waste = waste;
  589. rotated = 1;
  590. size = i;
  591. }
  592. }
  593. }
  594. }
  595. /* Now, size = The best size we have (or nelem(papersizes)) if it's too big */
  596. if (size < (int)nelem(papersizes))
  597. pcl->paper_size = papersizes[size].code;
  598. else
  599. pcl->paper_size = eCustomPaperSize; /* Custom */
  600. pcl->orientation = rotated;
  601. }
  602. /* Copy a line, returning true if the line was blank. */
  603. static int
  604. line_is_blank(unsigned char *dst, const unsigned char *sp, int w)
  605. {
  606. int zero = 0;
  607. while (w-- > 0)
  608. {
  609. zero |= (*dst++ = *sp++);
  610. zero |= (*dst++ = *sp++);
  611. zero |= (*dst++ = *sp++);
  612. }
  613. return zero == 0;
  614. }
  615. static int
  616. delta_compression(unsigned char *curr, unsigned char *prev, unsigned char *comp, int ds, int space)
  617. {
  618. int left = space;
  619. int x = ds;
  620. while (x > 0)
  621. {
  622. /* Count matching bytes */
  623. int match = 0;
  624. int diff = 0;
  625. while (x > 0 && *curr == *prev)
  626. {
  627. curr++;
  628. prev++;
  629. match++;
  630. x--;
  631. }
  632. /* Count different bytes */
  633. while (x > 0 && *curr != *prev)
  634. {
  635. curr++;
  636. prev++;
  637. diff++;
  638. x--;
  639. }
  640. while (diff > 0)
  641. {
  642. int exts;
  643. int mini_diff = diff;
  644. if (mini_diff > 8)
  645. mini_diff = 8;
  646. exts = (match+255-31)/255;
  647. left -= 1 + mini_diff + exts;
  648. if (left < 0)
  649. return 0;
  650. *comp++ = ((mini_diff-1)<<5) | (match < 31 ? match : 31);
  651. if (exts > 0)
  652. {
  653. match -= 31;
  654. while (--exts)
  655. {
  656. *comp++ = 255;
  657. match -= 255;
  658. }
  659. *comp++ = match;
  660. }
  661. memcpy(comp, curr-diff, mini_diff);
  662. comp += mini_diff;
  663. match = 0;
  664. diff -= mini_diff;
  665. }
  666. }
  667. return space - left;
  668. }
  669. void
  670. fz_write_pixmap_as_pcl(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pcl_options *pcl)
  671. {
  672. fz_band_writer *writer;
  673. if (!pixmap || !out)
  674. return;
  675. writer = fz_new_color_pcl_band_writer(ctx, out, pcl);
  676. fz_try(ctx)
  677. {
  678. fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace, pixmap->seps);
  679. fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
  680. fz_close_band_writer(ctx, writer);
  681. }
  682. fz_always(ctx)
  683. fz_drop_band_writer(ctx, writer);
  684. fz_catch(ctx)
  685. fz_rethrow(ctx);
  686. }
  687. typedef struct color_pcl_band_writer_s
  688. {
  689. fz_band_writer super;
  690. fz_pcl_options options;
  691. unsigned char *linebuf;
  692. unsigned char compbuf[32768];
  693. unsigned char compbuf2[32768];
  694. } color_pcl_band_writer;
  695. static void
  696. color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, fz_colorspace *cs)
  697. {
  698. color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
  699. fz_output *out = writer->super.out;
  700. int w = writer->super.w;
  701. int h = writer->super.h;
  702. int n = writer->super.n;
  703. int s = writer->super.s;
  704. int a = writer->super.alpha;
  705. int xres = writer->super.xres;
  706. int yres = writer->super.yres;
  707. if (a != 0)
  708. fz_throw(ctx, FZ_ERROR_ARGUMENT, "color PCL cannot write alpha channel");
  709. if (s != 0)
  710. fz_throw(ctx, FZ_ERROR_ARGUMENT, "color PCL cannot write spot colors");
  711. if (n != 3)
  712. fz_throw(ctx, FZ_ERROR_ARGUMENT, "color PCL must be RGB");
  713. writer->linebuf = Memento_label(fz_malloc(ctx, w * 3 * 2), "color_pcl_linebuf");
  714. guess_paper_size(&writer->options, w, h, xres, yres);
  715. pcl_header(ctx, out, &writer->options, 1, xres, yres, w, h);
  716. /* Raster presentation */
  717. /* Print in orientation of the logical page */
  718. fz_write_string(ctx, out, "\033&r0F");
  719. /* Set color mode */
  720. fz_write_data(ctx, out, "\033*v6W"
  721. "\000" /* Colorspace 0 = Device RGB */
  722. "\003" /* Pixel encoding mode: 3 = Direct by Pixel*/
  723. "\000" /* Bits per index: 0 = no palette */
  724. "\010" /* Red bits */
  725. "\010" /* Green bits */
  726. "\010", /* Blue bits */
  727. 11
  728. );
  729. /* Raster resolution */
  730. /* Supposed to be strictly 75, 100, 150, 200, 300, 600 */
  731. /* FIXME: xres vs yres */
  732. fz_write_printf(ctx, out, "\033*t%dR", xres);
  733. }
  734. static void flush_if_not_room(fz_context *ctx, fz_output *out, const unsigned char *comp, int *fill, int len)
  735. {
  736. if (len + *fill >= 32767)
  737. {
  738. /* Can't fit any data, so flush */
  739. fz_write_printf(ctx, out, "\033*b%dW", *fill);
  740. fz_write_data(ctx, out, comp, *fill);
  741. *fill = 0;
  742. }
  743. }
  744. static void
  745. color_pcl_compress_column(fz_context *ctx, color_pcl_band_writer *writer, const unsigned char *sp, int w, int h, int stride)
  746. {
  747. fz_output *out = writer->super.out;
  748. int ss = w * 3;
  749. int seed_valid = 0;
  750. int fill = 0;
  751. int y = 0;
  752. unsigned char *prev = writer->linebuf + w * 3;
  753. unsigned char *curr = writer->linebuf;
  754. unsigned char *comp = writer->compbuf;
  755. unsigned char *comp2 = writer->compbuf2;
  756. while (y < h)
  757. {
  758. /* Skip over multiple blank lines */
  759. int blanks;
  760. do
  761. {
  762. blanks = 0;
  763. while (blanks < 32767 && y < h)
  764. {
  765. if (!line_is_blank(curr, sp, w))
  766. break;
  767. blanks++;
  768. y++;
  769. sp += stride;
  770. }
  771. if (blanks)
  772. {
  773. flush_if_not_room(ctx, out, comp, &fill, 3);
  774. comp[fill++] = 4; /* Empty row */
  775. comp[fill++] = blanks>>8;
  776. comp[fill++] = blanks & 0xFF;
  777. seed_valid = 0;
  778. }
  779. }
  780. while (blanks == 32767);
  781. if (y == h)
  782. break;
  783. /* So, at least 1 more line to copy, and it's in curr */
  784. if (seed_valid && memcmp(curr, prev, ss) == 0)
  785. {
  786. int count = 1;
  787. sp += stride;
  788. y++;
  789. while (count < 32767 && y < h)
  790. {
  791. if (memcmp(sp-stride, sp, ss) != 0)
  792. break;
  793. count++;
  794. sp += stride;
  795. y++;
  796. }
  797. flush_if_not_room(ctx, out, comp, &fill, 3);
  798. comp[fill++] = 5; /* Duplicate row */
  799. comp[fill++] = count>>8;
  800. comp[fill++] = count & 0xFF;
  801. }
  802. else
  803. {
  804. unsigned char *tmp;
  805. int len = 0;
  806. /* Compress the line into our fixed buffer. */
  807. if (seed_valid)
  808. len = delta_compression(curr, prev, comp2, ss, fz_mini(ss-1, 32767-3));
  809. if (len > 0)
  810. {
  811. /* Delta compression */
  812. flush_if_not_room(ctx, out, comp, &fill, len+3);
  813. comp[fill++] = 3; /* Delta compression */
  814. comp[fill++] = len>>8;
  815. comp[fill++] = len & 0xFF;
  816. memcpy(&comp[fill], comp2, len);
  817. fill += len;
  818. }
  819. else
  820. {
  821. flush_if_not_room(ctx, out, comp, &fill, 3 + ss);
  822. /* PCL requires that all rows MUST fit in at most 1 block, so
  823. * we are carefully sending columns that are only so wide. */
  824. /* Unencoded */
  825. /* Transfer Raster Data: ss+3 bytes, 0 = Unencoded, count high, count low */
  826. comp[fill++] = 0;
  827. comp[fill++] = ss>>8;
  828. comp[fill++] = ss & 0xFF;
  829. memcpy(&comp[fill], curr, ss);
  830. fill += ss;
  831. seed_valid = 1;
  832. }
  833. /* curr becomes prev */
  834. tmp = prev; prev = curr; curr = tmp;
  835. sp += stride;
  836. y++;
  837. }
  838. }
  839. /* And flush */
  840. if (fill) {
  841. fz_write_printf(ctx, out, "\033*b%dW", fill);
  842. fz_write_data(ctx, out, comp, fill);
  843. }
  844. /* End Raster Graphics */
  845. fz_write_string(ctx, out, "\033*rC");
  846. }
  847. static void
  848. color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_start, int band_height, const unsigned char *sp)
  849. {
  850. color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
  851. fz_output *out = writer->super.out;
  852. int w = writer->super.w;
  853. int h = writer->super.h;
  854. int xres = writer->super.xres;
  855. int cw;
  856. int x;
  857. if (!out)
  858. return;
  859. if (band_start+band_height >= h)
  860. band_height = h - band_start;
  861. /* We have to specify image output size in decipoints (720dpi).
  862. * Most usual PCL resolutions are a multiple of 75.
  863. * Pick our maximum column size to be 10800 = 15*720 = 144*75
  864. * to give us good results. 10800 * 3 = 32400 < 32760 */
  865. cw = 10800; /* Limited by how much rowdata we can send at once */
  866. if (cw > w)
  867. cw = w;
  868. for (x = 0; x*cw < w; x++)
  869. {
  870. int col_w = w - cw*x;
  871. if (col_w > cw)
  872. col_w = cw;
  873. /* Top left corner */
  874. fz_write_printf(ctx, out, "\033*p%dx%dY", x*cw, band_start);
  875. /* Raster height */
  876. fz_write_printf(ctx, out, "\033*r%dT", band_height);
  877. /* Raster width */
  878. fz_write_printf(ctx, out, "\033*r%dS", col_w);
  879. /* Destination height */
  880. fz_write_printf(ctx, out, "\033*t%dV", band_height*720/xres);
  881. /* Destination width */
  882. fz_write_printf(ctx, out, "\033*t%dH", col_w*720/xres);
  883. /* start raster graphics */
  884. /* 1 = start at cursor position */
  885. fz_write_string(ctx, out, "\033*r3A");
  886. /* Now output the actual bitmap */
  887. /* Adaptive Compression */
  888. fz_write_string(ctx, out, "\033*b5M");
  889. color_pcl_compress_column(ctx, writer, sp + x * cw * 3, col_w, band_height, stride);
  890. }
  891. }
  892. static void
  893. color_pcl_write_trailer(fz_context *ctx, fz_band_writer *writer_)
  894. {
  895. }
  896. static void
  897. color_pcl_drop_band_writer(fz_context *ctx, fz_band_writer *writer_)
  898. {
  899. color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
  900. fz_free(ctx, writer->linebuf);
  901. }
  902. fz_band_writer *fz_new_color_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options)
  903. {
  904. color_pcl_band_writer *writer = fz_new_band_writer(ctx, color_pcl_band_writer, out);
  905. writer->super.header = color_pcl_write_header;
  906. writer->super.band = color_pcl_write_band;
  907. writer->super.trailer = color_pcl_write_trailer;
  908. writer->super.drop = color_pcl_drop_band_writer;
  909. if (options)
  910. writer->options = *options;
  911. else
  912. fz_pcl_preset(ctx, &writer->options, "generic");
  913. return &writer->super;
  914. }
  915. /*
  916. * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
  917. * Compresses data from row up to end_row, storing the result
  918. * starting at out. Returns the number of bytes stored.
  919. * Runs of K<=127 literal bytes are encoded as K-1 followed by
  920. * the bytes; runs of 2<=K<=127 identical bytes are encoded as
  921. * 257-K followed by the byte.
  922. * In the worst case, the result is N+(N/127)+1 bytes long,
  923. * where N is the original byte count (end_row - row).
  924. */
  925. static int
  926. mode2compress(unsigned char *out, const unsigned char *in, int in_len)
  927. {
  928. int x;
  929. int out_len = 0;
  930. int run;
  931. for (x = 0; x < in_len; x += run)
  932. {
  933. /* How far do we have to look to find a value that isn't repeated? */
  934. for (run = 1; run < 127 && x+run < in_len; run++)
  935. if (in[0] != in[run])
  936. break;
  937. if (run > 1)
  938. {
  939. /* We have a run of matching bytes */
  940. out[out_len++] = 257-run;
  941. out[out_len++] = in[0];
  942. }
  943. else
  944. {
  945. /* Now copy as many literals as possible. We only
  946. * break the run at a length of 127, at the end,
  947. * or where we have 3 repeated values. */
  948. int i;
  949. /* How many literals do we need to copy? */
  950. for (; run < 127 && x+run+2 < in_len; run++)
  951. if (in[run] == in[run+1] && in[run] == in[run+2])
  952. break;
  953. /* Don't leave stragglers at the end */
  954. if (x + run + 2 >= in_len)
  955. {
  956. run = in_len - x;
  957. if (run > 127)
  958. run = 127;
  959. }
  960. out[out_len++] = run-1;
  961. for (i = 0; i < run; i++)
  962. {
  963. out[out_len++] = in[i];
  964. }
  965. }
  966. in += run;
  967. }
  968. return out_len;
  969. }
  970. /*
  971. * Mode 3 compression routine for the HP LaserJet III family.
  972. * Compresses bytecount bytes starting at current, storing the result
  973. * in compressed, comparing against and updating previous.
  974. * Returns the number of bytes stored. In the worst case,
  975. * the number of bytes is bytecount+(bytecount/8)+1.
  976. */
  977. static int
  978. mode3compress(unsigned char *out, const unsigned char *in, unsigned char *prev, int in_len)
  979. {
  980. unsigned char *compressed = out;
  981. const unsigned char *cur = in;
  982. const unsigned char *end = in + in_len;
  983. while (cur < end) { /* Detect a maximum run of unchanged bytes. */
  984. const unsigned char *run = cur;
  985. const unsigned char *diff;
  986. const unsigned char *stop;
  987. int offset, cbyte;
  988. while (cur < end && *cur == *prev) {
  989. cur++, prev++;
  990. }
  991. if (cur == end)
  992. break; /* rest of row is unchanged */
  993. /* Detect a run of up to 8 changed bytes. */
  994. /* We know that *cur != *prev. */
  995. diff = cur;
  996. stop = (end - cur > 8 ? cur + 8 : end);
  997. do
  998. {
  999. *prev++ = *cur++;
  1000. }
  1001. while (cur < stop && *cur != *prev);
  1002. /* Now [run..diff) are unchanged, and */
  1003. /* [diff..cur) are changed. */
  1004. /* Generate the command byte(s). */
  1005. offset = diff - run;
  1006. cbyte = (cur - diff - 1) << 5;
  1007. if (offset < 31)
  1008. *out++ = cbyte + offset;
  1009. else {
  1010. *out++ = cbyte + 31;
  1011. offset -= 31;
  1012. while (offset >= 255)
  1013. *out++ = 255, offset -= 255;
  1014. *out++ = offset;
  1015. }
  1016. /* Copy the changed data. */
  1017. while (diff < cur)
  1018. *out++ = *diff++;
  1019. }
  1020. return out - compressed;
  1021. }
  1022. void
  1023. fz_write_bitmap_as_pcl(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pcl_options *pcl)
  1024. {
  1025. fz_band_writer *writer;
  1026. if (!bitmap || !out)
  1027. return;
  1028. writer = fz_new_mono_pcl_band_writer(ctx, out, pcl);
  1029. fz_try(ctx)
  1030. {
  1031. fz_write_header(ctx, writer, bitmap->w, bitmap->h, 1, 0, bitmap->xres, bitmap->yres, 0, NULL, NULL);
  1032. fz_write_band(ctx, writer, bitmap->stride, bitmap->h, bitmap->samples);
  1033. fz_close_band_writer(ctx, writer);
  1034. }
  1035. fz_always(ctx)
  1036. fz_drop_band_writer(ctx, writer);
  1037. fz_catch(ctx)
  1038. fz_rethrow(ctx);
  1039. }
  1040. typedef struct mono_pcl_band_writer_s
  1041. {
  1042. fz_band_writer super;
  1043. fz_pcl_options options;
  1044. unsigned char *prev;
  1045. unsigned char *mode2buf;
  1046. unsigned char *mode3buf;
  1047. int top_of_page;
  1048. int num_blank_lines;
  1049. } mono_pcl_band_writer;
  1050. static void
  1051. mono_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, fz_colorspace *cs)
  1052. {
  1053. mono_pcl_band_writer *writer = (mono_pcl_band_writer *)writer_;
  1054. fz_output *out = writer->super.out;
  1055. int w = writer->super.w;
  1056. int h = writer->super.h;
  1057. int xres = writer->super.xres;
  1058. int yres = writer->super.yres;
  1059. int line_size;
  1060. int max_mode_2_size;
  1061. int max_mode_3_size;
  1062. if (writer->super.alpha != 0)
  1063. fz_throw(ctx, FZ_ERROR_ARGUMENT, "mono PCL cannot write alpha channel");
  1064. if (writer->super.s != 0)
  1065. fz_throw(ctx, FZ_ERROR_ARGUMENT, "mono PCL cannot write spot colors");
  1066. if (writer->super.n != 1)
  1067. fz_throw(ctx, FZ_ERROR_ARGUMENT, "mono PCL must be grayscale");
  1068. line_size = (w + 7)/8;
  1069. max_mode_2_size = line_size + (line_size/127) + 1;
  1070. max_mode_3_size = line_size + (line_size/8) + 1;
  1071. writer->prev = fz_calloc(ctx, line_size, sizeof(unsigned char));
  1072. writer->mode2buf = fz_calloc(ctx, max_mode_2_size, sizeof(unsigned char));
  1073. writer->mode3buf = fz_calloc(ctx, max_mode_3_size, sizeof(unsigned char));
  1074. writer->num_blank_lines = 0;
  1075. writer->top_of_page = 1;
  1076. guess_paper_size(&writer->options, w, h, xres, yres);
  1077. if (writer->options.features & HACK__IS_A_OCE9050)
  1078. {
  1079. /* Enter HPGL/2 mode, begin plot, Initialise (start plot), Enter PCL mode */
  1080. fz_write_string(ctx, out, "\033%1BBPIN;\033%1A");
  1081. }
  1082. pcl_header(ctx, out, &writer->options, 1, xres, yres, w, h);
  1083. }
  1084. static void
  1085. mono_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int ss, int band_start, int band_height, const unsigned char *data)
  1086. {
  1087. mono_pcl_band_writer *writer = (mono_pcl_band_writer *)writer_;
  1088. fz_output *out = writer->super.out;
  1089. int w = writer->super.w;
  1090. int yres = writer->super.yres;
  1091. const unsigned char *out_data;
  1092. int y, rmask, line_size;
  1093. int num_blank_lines;
  1094. int compression = -1;
  1095. unsigned char *prev = NULL;
  1096. unsigned char *mode2buf = NULL;
  1097. unsigned char *mode3buf = NULL;
  1098. int out_count;
  1099. const fz_pcl_options *pcl;
  1100. if (!out)
  1101. return;
  1102. num_blank_lines = writer->num_blank_lines;
  1103. rmask = ~0 << (-w & 7);
  1104. line_size = (w + 7)/8;
  1105. prev = writer->prev;
  1106. mode2buf = writer->mode2buf;
  1107. mode3buf = writer->mode3buf;
  1108. pcl = &writer->options;
  1109. /* Transfer raster graphics. */
  1110. for (y = 0; y < band_height; y++, data += ss)
  1111. {
  1112. const unsigned char *end_data = data + line_size;
  1113. if ((end_data[-1] & rmask) == 0)
  1114. {
  1115. end_data--;
  1116. while (end_data > data && end_data[-1] == 0)
  1117. end_data--;
  1118. }
  1119. if (end_data == data)
  1120. {
  1121. /* Blank line */
  1122. num_blank_lines++;
  1123. continue;
  1124. }
  1125. /* We've reached a non-blank line. */
  1126. /* Put out a spacing command if necessary. */
  1127. if (writer->top_of_page)
  1128. {
  1129. writer->top_of_page = 0;
  1130. /* We're at the top of a page. */
  1131. if (pcl->features & PCL_ANY_SPACING)
  1132. {
  1133. if (num_blank_lines > 0)
  1134. fz_write_printf(ctx, out, "\033*p+%dY", num_blank_lines);
  1135. /* Start raster graphics. */
  1136. fz_write_string(ctx, out, "\033*r1A");
  1137. }
  1138. else if (pcl->features & PCL_MODE_3_COMPRESSION)
  1139. {
  1140. /* Start raster graphics. */
  1141. fz_write_string(ctx, out, "\033*r1A");
  1142. for (; num_blank_lines; num_blank_lines--)
  1143. fz_write_string(ctx, out, "\033*b0W");
  1144. }
  1145. else
  1146. {
  1147. /* Start raster graphics. */
  1148. fz_write_string(ctx, out, "\033*r1A");
  1149. for (; num_blank_lines; num_blank_lines--)
  1150. fz_write_string(ctx, out, "\033*bW");
  1151. }
  1152. }
  1153. /* Skip blank lines if any */
  1154. else if (num_blank_lines != 0)
  1155. {
  1156. /* Moving down from current position causes head
  1157. * motion on the DeskJet, so if the number of lines
  1158. * is small, we're better off printing blanks.
  1159. *
  1160. * For Canon LBP4i and some others, <ESC>*b<n>Y
  1161. * doesn't properly clear the seed row if we are in
  1162. * compression mode 3.
  1163. */
  1164. if ((num_blank_lines < MIN_SKIP_LINES && compression != 3) ||
  1165. !(pcl->features & PCL_ANY_SPACING))
  1166. {
  1167. int mode_3ns = ((pcl->features & PCL_MODE_3_COMPRESSION) && !(pcl->features & PCL_ANY_SPACING));
  1168. if (mode_3ns && compression != 2)
  1169. {
  1170. /* Switch to mode 2 */
  1171. fz_write_string(ctx, out, from3to2);
  1172. compression = 2;
  1173. }
  1174. if (pcl->features & PCL_MODE_3_COMPRESSION)
  1175. {
  1176. /* Must clear the seed row. */
  1177. fz_write_string(ctx, out, "\033*b1Y");
  1178. num_blank_lines--;
  1179. }
  1180. if (mode_3ns)
  1181. {
  1182. for (; num_blank_lines; num_blank_lines--)
  1183. fz_write_string(ctx, out, "\033*b0W");
  1184. }
  1185. else
  1186. {
  1187. for (; num_blank_lines; num_blank_lines--)
  1188. fz_write_string(ctx, out, "\033*bW");
  1189. }
  1190. }
  1191. else if (pcl->features & PCL3_SPACING)
  1192. fz_write_printf(ctx, out, "\033*p+%dY", num_blank_lines * yres);
  1193. else
  1194. fz_write_printf(ctx, out, "\033*b%dY", num_blank_lines);
  1195. /* Clear the seed row (only matters for mode 3 compression). */
  1196. memset(prev, 0, line_size);
  1197. }
  1198. num_blank_lines = 0;
  1199. /* Choose the best compression mode for this particular line. */
  1200. if (pcl->features & PCL_MODE_3_COMPRESSION)
  1201. {
  1202. /* Compression modes 2 and 3 are both available. Try
  1203. * both and see which produces the least output data.
  1204. */
  1205. int count3 = mode3compress(mode3buf, data, prev, line_size);
  1206. int count2 = mode2compress(mode2buf, data, line_size);
  1207. int penalty3 = (compression == 3 ? 0 : penalty_from2to3);
  1208. int penalty2 = (compression == 2 ? 0 : penalty_from3to2);
  1209. if (count3 + penalty3 < count2 + penalty2)
  1210. {
  1211. if (compression != 3)
  1212. fz_write_string(ctx, out, from2to3);
  1213. compression = 3;
  1214. out_data = (unsigned char *)mode3buf;
  1215. out_count = count3;
  1216. }
  1217. else
  1218. {
  1219. if (compression != 2)
  1220. fz_write_string(ctx, out, from3to2);
  1221. compression = 2;
  1222. out_data = (unsigned char *)mode2buf;
  1223. out_count = count2;
  1224. }
  1225. }
  1226. else if (pcl->features & PCL_MODE_2_COMPRESSION)
  1227. {
  1228. out_data = mode2buf;
  1229. out_count = mode2compress(mode2buf, data, line_size);
  1230. }
  1231. else
  1232. {
  1233. out_data = data;
  1234. out_count = line_size;
  1235. }
  1236. /* Transfer the data */
  1237. fz_write_printf(ctx, out, "\033*b%dW", out_count);
  1238. fz_write_data(ctx, out, out_data, out_count);
  1239. }
  1240. writer->num_blank_lines = num_blank_lines;
  1241. }
  1242. static void
  1243. mono_pcl_write_trailer(fz_context *ctx, fz_band_writer *writer_)
  1244. {
  1245. mono_pcl_band_writer *writer = (mono_pcl_band_writer *)writer_;
  1246. fz_output *out = writer->super.out;
  1247. /* end raster graphics and eject page */
  1248. fz_write_string(ctx, out, "\033*rB\f");
  1249. if (writer->options.features & HACK__IS_A_OCE9050)
  1250. {
  1251. /* Pen up, pen select, advance full page, reset */
  1252. fz_write_string(ctx, out, "\033%1BPUSP0PG;\033E");
  1253. }
  1254. }
  1255. static void
  1256. mono_pcl_drop_band_writer(fz_context *ctx, fz_band_writer *writer_)
  1257. {
  1258. mono_pcl_band_writer *writer = (mono_pcl_band_writer *)writer_;
  1259. fz_free(ctx, writer->prev);
  1260. fz_free(ctx, writer->mode2buf);
  1261. fz_free(ctx, writer->mode3buf);
  1262. }
  1263. fz_band_writer *fz_new_mono_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options)
  1264. {
  1265. mono_pcl_band_writer *writer = fz_new_band_writer(ctx, mono_pcl_band_writer, out);
  1266. writer->super.header = mono_pcl_write_header;
  1267. writer->super.band = mono_pcl_write_band;
  1268. writer->super.trailer = mono_pcl_write_trailer;
  1269. writer->super.drop = mono_pcl_drop_band_writer;
  1270. if (options)
  1271. writer->options = *options;
  1272. else
  1273. fz_pcl_preset(ctx, &writer->options, "generic");
  1274. return &writer->super;
  1275. }
  1276. void
  1277. fz_save_pixmap_as_pcl(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pcl_options *pcl)
  1278. {
  1279. fz_output *out = fz_new_output_with_path(ctx, filename, append);
  1280. fz_try(ctx)
  1281. {
  1282. fz_write_pixmap_as_pcl(ctx, out, pixmap, pcl);
  1283. fz_close_output(ctx, out);
  1284. }
  1285. fz_always(ctx)
  1286. fz_drop_output(ctx, out);
  1287. fz_catch(ctx)
  1288. fz_rethrow(ctx);
  1289. }
  1290. void
  1291. fz_save_bitmap_as_pcl(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pcl_options *pcl)
  1292. {
  1293. fz_output *out = fz_new_output_with_path(ctx, filename, append);
  1294. fz_try(ctx)
  1295. {
  1296. fz_write_bitmap_as_pcl(ctx, out, bitmap, pcl);
  1297. fz_close_output(ctx, out);
  1298. }
  1299. fz_always(ctx)
  1300. fz_drop_output(ctx, out);
  1301. fz_catch(ctx)
  1302. fz_rethrow(ctx);
  1303. }
  1304. /* High-level document writer interface */
  1305. typedef struct
  1306. {
  1307. fz_document_writer super;
  1308. fz_draw_options draw;
  1309. fz_pcl_options pcl;
  1310. fz_pixmap *pixmap;
  1311. int mono;
  1312. fz_output *out;
  1313. } fz_pcl_writer;
  1314. static fz_device *
  1315. pcl_begin_page(fz_context *ctx, fz_document_writer *wri_, fz_rect mediabox)
  1316. {
  1317. fz_pcl_writer *wri = (fz_pcl_writer*)wri_;
  1318. return fz_new_draw_device_with_options(ctx, &wri->draw, mediabox, &wri->pixmap);
  1319. }
  1320. static void
  1321. pcl_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev)
  1322. {
  1323. fz_pcl_writer *wri = (fz_pcl_writer*)wri_;
  1324. fz_bitmap *bitmap = NULL;
  1325. fz_var(bitmap);
  1326. fz_try(ctx)
  1327. {
  1328. fz_close_device(ctx, dev);
  1329. if (wri->mono)
  1330. {
  1331. bitmap = fz_new_bitmap_from_pixmap(ctx, wri->pixmap, NULL);
  1332. fz_write_bitmap_as_pcl(ctx, wri->out, bitmap, &wri->pcl);
  1333. }
  1334. else
  1335. {
  1336. fz_write_pixmap_as_pcl(ctx, wri->out, wri->pixmap, &wri->pcl);
  1337. }
  1338. }
  1339. fz_always(ctx)
  1340. {
  1341. fz_drop_device(ctx, dev);
  1342. fz_drop_bitmap(ctx, bitmap);
  1343. fz_drop_pixmap(ctx, wri->pixmap);
  1344. wri->pixmap = NULL;
  1345. }
  1346. fz_catch(ctx)
  1347. fz_rethrow(ctx);
  1348. }
  1349. static void
  1350. pcl_close_writer(fz_context *ctx, fz_document_writer *wri_)
  1351. {
  1352. fz_pcl_writer *wri = (fz_pcl_writer*)wri_;
  1353. fz_close_output(ctx, wri->out);
  1354. }
  1355. static void
  1356. pcl_drop_writer(fz_context *ctx, fz_document_writer *wri_)
  1357. {
  1358. fz_pcl_writer *wri = (fz_pcl_writer*)wri_;
  1359. fz_drop_pixmap(ctx, wri->pixmap);
  1360. fz_drop_output(ctx, wri->out);
  1361. }
  1362. fz_document_writer *
  1363. fz_new_pcl_writer_with_output(fz_context *ctx, fz_output *out, const char *options)
  1364. {
  1365. fz_pcl_writer *wri = NULL;
  1366. const char *val;
  1367. fz_var(wri);
  1368. fz_try(ctx)
  1369. {
  1370. wri = fz_new_derived_document_writer(ctx, fz_pcl_writer, pcl_begin_page, pcl_end_page, pcl_close_writer, pcl_drop_writer);
  1371. fz_parse_draw_options(ctx, &wri->draw, options);
  1372. fz_parse_pcl_options(ctx, &wri->pcl, options);
  1373. if (fz_has_option(ctx, options, "colorspace", &val))
  1374. if (fz_option_eq(val, "mono"))
  1375. wri->mono = 1;
  1376. wri->out = out;
  1377. }
  1378. fz_catch(ctx)
  1379. {
  1380. fz_drop_output(ctx, out);
  1381. fz_free(ctx, wri);
  1382. fz_rethrow(ctx);
  1383. }
  1384. return (fz_document_writer*)wri;
  1385. }
  1386. fz_document_writer *
  1387. fz_new_pcl_writer(fz_context *ctx, const char *path, const char *options)
  1388. {
  1389. fz_output *out = fz_new_output_with_path(ctx, path ? path : "out.pcl", 0);
  1390. return fz_new_pcl_writer_with_output(ctx, out, options);
  1391. }