1 /*
2  *
3  *   Print plug-in EPSON ESC/P2 driver for the GIMP.
4  *
5  *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
6  *	Robert Krawitz (rlk@alum.mit.edu)
7  *
8  *   This program is free software; you can redistribute it and/or modify it
9  *   under the terms of the GNU General Public License as published by the Free
10  *   Software Foundation; either version 2 of the License, or (at your option)
11  *   any later version.
12  *
13  *   This program is distributed in the hope that it will be useful, but
14  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  *   for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 /*
23  * This file must include only standard C header files.  The core code must
24  * compile on generic platforms that don't support glib, gimp, gtk, etc.
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <gutenprint/gutenprint.h>
31 #include <gutenprint/gutenprint-intl-internal.h>
32 #include "gutenprint-internal.h"
33 #include <string.h>
34 #include "print-escp2.h"
35 
36 #ifdef __GNUC__
37 #define inline __inline__
38 #endif
39 
40 static escp2_privdata_t *
get_privdata(stp_vars_t * v)41 get_privdata(stp_vars_t *v)
42 {
43   return (escp2_privdata_t *) stp_get_component_data(v, "Driver");
44 }
45 
46 static void
escp2_reset_printer(stp_vars_t * v)47 escp2_reset_printer(stp_vars_t *v)
48 {
49   escp2_privdata_t *pd = get_privdata(v);
50   /*
51    * Magic initialization string that's needed to take printer out of
52    * packet mode.
53    */
54   if (pd->preinit_sequence)
55     stp_write_raw(pd->preinit_sequence, v);
56 
57   stp_send_command(v, "\033@", "");
58 }
59 
60 static void
print_remote_param(stp_vars_t * v,const char * param,const char * value)61 print_remote_param(stp_vars_t *v, const char *param, const char *value)
62 {
63   stp_send_command(v, "\033(R", "bcscs", '\0', param, ':',
64 		    value ? value : "NULL");
65   stp_send_command(v, "\033", "ccc", 0, 0, 0);
66 }
67 
68 static void
print_remote_int_param(stp_vars_t * v,const char * param,int value)69 print_remote_int_param(stp_vars_t *v, const char *param, int value)
70 {
71   char buf[64];
72   (void) snprintf(buf, 64, "%d", value);
73   print_remote_param(v, param, buf);
74 }
75 
76 static void
print_remote_float_param(stp_vars_t * v,const char * param,double value)77 print_remote_float_param(stp_vars_t *v, const char *param, double value)
78 {
79   char buf[64];
80   (void) snprintf(buf, 64, "%f", value);
81   print_remote_param(v, param, buf);
82 }
83 
84 static void
print_remote_dim_param(stp_vars_t * v,const char * param,double value)85 print_remote_dim_param(stp_vars_t *v, const char *param, double value)
86 {
87   print_remote_float_param(v, param, value);
88 }
89 
90 static void
print_debug_params(stp_vars_t * v)91 print_debug_params(stp_vars_t *v)
92 {
93   escp2_privdata_t *pd = get_privdata(v);
94   stp_parameter_list_t params = stp_get_parameter_list(v);
95   int count = stp_parameter_list_count(params);
96   int i;
97   print_remote_param(v, "Package", PACKAGE);
98   print_remote_param(v, "Version", VERSION);
99   print_remote_param(v, "Release Date", RELEASE_DATE);
100   print_remote_param(v, "Driver", stp_get_driver(v));
101   print_remote_dim_param(v, "Left", stp_get_left(v));
102   print_remote_dim_param(v, "Top", stp_get_top(v));
103   print_remote_dim_param(v, "Page Width", stp_get_page_width(v));
104   print_remote_dim_param(v, "Page Height", stp_get_page_height(v));
105   print_remote_int_param(v, "Model", stp_get_model_id(v));
106   print_remote_int_param(v, "Ydpi", pd->res->vres);
107   print_remote_int_param(v, "Xdpi", pd->res->hres);
108   print_remote_int_param(v, "Printed_ydpi", pd->res->printed_vres);
109   print_remote_int_param(v, "Printed_xdpi", pd->res->printed_hres);
110 /*
111   print_remote_int_param(v, "Use_softweave", pd->res->softweave);
112   print_remote_int_param(v, "Printer_weave", pd->res->printer_weave);
113 */
114   print_remote_int_param(v, "Use_printer_weave", pd->use_printer_weave);
115   print_remote_int_param(v, "Duplex", pd->duplex);
116   print_remote_dim_param(v, "Page_left", pd->page_left);
117   print_remote_dim_param(v, "Page_right", pd->page_right);
118   print_remote_dim_param(v, "Page_top", pd->page_top);
119   print_remote_dim_param(v, "Page_bottom", pd->page_bottom);
120   print_remote_dim_param(v, "Page_width", pd->page_width);
121   print_remote_dim_param(v, "Page_height", pd->page_height);
122   print_remote_dim_param(v, "Page_true_height", pd->page_true_height);
123   print_remote_dim_param(v, "Page_extra_height", pd->page_extra_height);
124   print_remote_dim_param(v, "Paper_extra_bottom", pd->paper_extra_bottom);
125   print_remote_dim_param(v, "Image_left", pd->image_left);
126   print_remote_dim_param(v, "Image_top", pd->image_top);
127   print_remote_dim_param(v, "Image_width", pd->image_width);
128   print_remote_dim_param(v, "Image_height", pd->image_height);
129   print_remote_dim_param(v, "CD_X_offset", pd->cd_x_offset);
130   print_remote_dim_param(v, "CD_Y_offset", pd->cd_y_offset);
131   print_remote_dim_param(v, "CD_inner_radius", pd->cd_inner_radius);
132   print_remote_dim_param(v, "CD_outer_radius", pd->cd_outer_radius);
133   print_remote_int_param(v, "Image_scaled_width", pd->image_scaled_width);
134   print_remote_int_param(v, "Image_scaled_height", pd->image_scaled_height);
135   print_remote_int_param(v, "Image_printed_width", pd->image_printed_width);
136   print_remote_int_param(v, "Image_printed_height", pd->image_printed_height);
137   print_remote_int_param(v, "Image_left_position", pd->image_left_position);
138   print_remote_int_param(v, "Nozzles", pd->nozzles);
139   print_remote_int_param(v, "Nozzle_separation", pd->nozzle_separation);
140   print_remote_int_param(v, "Horizontal_passes", pd->horizontal_passes);
141   print_remote_int_param(v, "Vertical_passes", pd->res->vertical_passes);
142   print_remote_int_param(v, "Physical_xdpi", pd->physical_xdpi);
143   print_remote_int_param(v, "Page_management_units", pd->page_management_units);
144   print_remote_int_param(v, "Vertical_units", pd->vertical_units);
145   print_remote_int_param(v, "Horizontal_units", pd->horizontal_units);
146   print_remote_int_param(v, "Micro_units", pd->micro_units);
147   print_remote_int_param(v, "Unit_scale", pd->unit_scale);
148   print_remote_int_param(v, "Zero_advance", pd->send_zero_pass_advance);
149   print_remote_int_param(v, "Bits", pd->bitwidth);
150   print_remote_int_param(v, "Drop Size", pd->drop_size);
151   print_remote_int_param(v, "Initial_vertical_offset", pd->initial_vertical_offset);
152   print_remote_int_param(v, "Channels_in_use", pd->channels_in_use);
153   print_remote_int_param(v, "Logical_channels", pd->logical_channels);
154   print_remote_int_param(v, "Physical_channels", pd->physical_channels);
155   print_remote_int_param(v, "Use_black_parameters", pd->use_black_parameters);
156   print_remote_int_param(v, "Use_fast_360", pd->use_fast_360);
157   print_remote_int_param(v, "Command_set", pd->command_set);
158   print_remote_int_param(v, "Variable_dots", pd->variable_dots);
159   print_remote_int_param(v, "Has_graymode", pd->has_graymode);
160   print_remote_int_param(v, "Base_separation", pd->base_separation);
161   print_remote_int_param(v, "Resolution_scale", pd->resolution_scale);
162 #if 0
163   print_remote_int_param(v, "Printing_resolution", pd->printing_resolution);
164 #endif
165   print_remote_int_param(v, "Separation_rows", pd->separation_rows);
166   print_remote_int_param(v, "Pseudo_separation_rows", pd->pseudo_separation_rows);
167   print_remote_int_param(v, "Extra_720dpi_separation", pd->extra_720dpi_separation);
168   print_remote_int_param(v, "Use_aux_channels", pd->use_aux_channels);
169   print_remote_param(v, "Ink name", pd->inkname->name);
170   print_remote_int_param(v, "  channels", pd->inkname->channel_count);
171   print_remote_int_param(v, "  inkset", pd->inkname->inkset);
172   for (i = 0; i < count; i++)
173     {
174       const stp_parameter_t *p = stp_parameter_list_param(params, i);
175       switch (p->p_type)
176 	{
177 	case STP_PARAMETER_TYPE_DOUBLE:
178 	  if (stp_check_float_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
179 	    print_remote_float_param(v, p->name,
180 				     stp_get_float_parameter(v, p->name));
181 	  break;
182 	case STP_PARAMETER_TYPE_INT:
183 	  if (stp_check_int_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
184 	    print_remote_int_param(v, p->name,
185 				   stp_get_int_parameter(v, p->name));
186 	  break;
187 	case STP_PARAMETER_TYPE_DIMENSION:
188 	  if (stp_check_dimension_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
189 	    print_remote_int_param(v, p->name,
190 				   stp_get_dimension_parameter(v, p->name));
191 	  break;
192 	case STP_PARAMETER_TYPE_BOOLEAN:
193 	  if (stp_check_boolean_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
194 	    print_remote_int_param(v, p->name,
195 				   stp_get_boolean_parameter(v, p->name));
196 	  break;
197 	case STP_PARAMETER_TYPE_STRING_LIST:
198 	  if (stp_check_string_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
199 	    print_remote_param(v, p->name,
200 			       stp_get_string_parameter(v, p->name));
201 	  break;
202 	case STP_PARAMETER_TYPE_CURVE:
203 	  if (stp_check_curve_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
204 	    {
205 	      char *curve =
206 		stp_curve_write_string(stp_get_curve_parameter(v, p->name));
207 	      print_remote_param(v, p->name, curve);
208 	      stp_free(curve);
209 	    }
210 	  break;
211 	default:
212 	  break;
213 	}
214     }
215   stp_parameter_list_destroy(params);
216   stp_send_command(v, "\033", "ccc", 0, 0, 0);
217 }
218 
219 static void
escp2_set_remote_sequence(stp_vars_t * v)220 escp2_set_remote_sequence(stp_vars_t *v)
221 {
222   /* Magic remote mode commands, whatever they do */
223   escp2_privdata_t *pd = get_privdata(v);
224   const stp_vars_t *pv = pd->media_settings;
225 
226   if (stp_get_debug_level() & STP_DBG_MARK_FILE)
227     print_debug_params(v);
228   if (pd->advanced_command_set || pd->input_slot)
229     {
230       /* Enter remote mode */
231       stp_send_command(v, "\033(R", "bcs", 0, "REMOTE1");
232       /* Per the manual, job setup comes first, then SN command */
233       if (pd->input_slot &&
234 	  pd->input_slot->roll_feed_cut_flags == ROLL_FEED_CUT_ALL)
235 	      stp_send_command(v, "JS", "bh", 0);
236       if (pd->preinit_remote_sequence)
237 	stp_write_raw(pd->preinit_remote_sequence, v);
238       if (stp_check_int_parameter(pv, "FeedAdjustment", STP_PARAMETER_ACTIVE))
239 	stp_send_command(v, "SN", "bccc", 0, 4,
240 			 stp_get_int_parameter(pv, "FeedAdjustment"));
241       if (stp_check_int_parameter(pv, "VacuumIntensity", STP_PARAMETER_ACTIVE))
242 	stp_send_command(v, "SN", "bccc", 0, 5,
243 			 stp_get_int_parameter(pv, "VacuumIntensity"));
244       if (stp_check_float_parameter(pv, "ScanDryTime", STP_PARAMETER_ACTIVE))
245 	stp_send_command(v, "DR", "bcch", 0, 0,
246 			 (int) (stp_get_float_parameter(pv, "ScanDryTime") * 1000));
247       if (stp_check_float_parameter(pv, "ScanMinDryTime", STP_PARAMETER_ACTIVE))
248 	stp_send_command(v, "DR", "bcch", 0, 0x40,
249 			 (int) (stp_get_float_parameter(pv, "ScanMinDryTime") * 1000));
250       if (stp_check_float_parameter(pv, "PageDryTime", STP_PARAMETER_ACTIVE))
251 	stp_send_command(v, "DR", "bcch", 0, 1,
252 			 (int) stp_get_float_parameter(pv, "PageDryTime"));
253       /* Next comes paper path */
254       if (pd->input_slot)
255 	{
256 	  int divisor = pd->base_separation / 360;
257 	  int height = pd->page_true_height * 5 / divisor;
258 	  if (pd->input_slot->init_sequence)
259 	    stp_write_raw(pd->input_slot->init_sequence, v);
260 	  switch (pd->input_slot->roll_feed_cut_flags)
261 	    {
262 	    case ROLL_FEED_CUT_ALL:
263 	      stp_send_command(v, "CO", "bccccl", 0, 0, 1, 0, 0);
264 	      stp_send_command(v, "CO", "bccccl", 0, 0, 0, 0, height);
265 	      break;
266 	    case ROLL_FEED_CUT_LAST:
267 	      stp_send_command(v, "CO", "bccccl", 0, 0, 1, 0, 0);
268 	      stp_send_command(v, "CO", "bccccl", 0, 0, 2, 0, height);
269 	      break;
270 	    default:
271 	      break;
272 	    }
273 	}
274       if (stp_check_int_parameter(pv, "PaperMedia", STP_PARAMETER_ACTIVE))
275 	stp_send_command(v, "MI", "bcccc", 0, 1,
276 			 stp_get_int_parameter(pv, "PaperMedia"),
277 			 (stp_check_int_parameter(pv, "PaperMediaSize", STP_PARAMETER_ACTIVE) ?
278 			  stp_get_int_parameter(pv, "PaperMediaSize") :
279 			  99));	/* User-defined size (for now!) */
280       if (pd->duplex)
281 	{
282 	  /* If there's ever duplex no tumble, we'll need to special
283 	     case it, too */
284 	  if (pd->duplex == DUPLEX_TUMBLE && pd->input_slot && (pd->input_slot->duplex & DUPLEX_TUMBLE))
285 	    stp_send_command(v, "DP", "bcc", 0, 2); /* Auto duplex */
286 	  else
287 	    stp_send_command(v, "DP", "bcc", 0, 2); /* Auto duplex */
288 	}
289       if (stp_check_int_parameter(pv, "PaperThickness", STP_PARAMETER_ACTIVE))
290 	stp_send_command(v, "PH", "bcc", 0,
291 			 stp_get_int_parameter(pv, "PaperThickness"));
292       if (stp_check_int_parameter(pv, "FeedSequence", STP_PARAMETER_ACTIVE))
293 	stp_send_command(v, "SN", "bccc", 0, 0,
294 			 stp_get_int_parameter(pv, "FeedSequence"));
295       if (stp_check_int_parameter(pv, "PlatenGap", STP_PARAMETER_ACTIVE))
296 	stp_send_command(v, "US", "bccc", 0, 1,
297 			 stp_get_int_parameter(pv, "PlatenGap"));
298       if (stp_get_boolean_parameter(v, "FullBleed"))
299 	{
300 	  stp_send_command(v, "FP", "bch", 0,
301 			   (unsigned short) -pd->zero_margin_offset);
302 	  if (pd->borderless_sequence)
303 	    stp_write_raw(pd->borderless_sequence, v);
304 	}
305       if (pd->inkname->init_sequence)
306 	stp_write_raw(pd->inkname->init_sequence, v);
307       /* Exit remote mode */
308 
309       stp_send_command(v, "\033", "ccc", 0, 0, 0);
310     }
311 }
312 
313 static void
escp2_set_graphics_mode(stp_vars_t * v)314 escp2_set_graphics_mode(stp_vars_t *v)
315 {
316   stp_send_command(v, "\033(G", "bc", 1);
317 }
318 
319 static void
escp2_set_resolution(stp_vars_t * v)320 escp2_set_resolution(stp_vars_t *v)
321 {
322   escp2_privdata_t *pd = get_privdata(v);
323   if (pd->use_extended_commands)
324     stp_send_command(v, "\033(U", "bccch",
325 		     pd->unit_scale / pd->page_management_units,
326 		     pd->unit_scale / pd->vertical_units,
327 		     pd->unit_scale / pd->horizontal_units,
328 		     pd->unit_scale);
329   else
330     stp_send_command(v, "\033(U", "bc",
331 		     pd->unit_scale / pd->page_management_units);
332 }
333 
334 static void
escp2_set_color(stp_vars_t * v)335 escp2_set_color(stp_vars_t *v)
336 {
337   escp2_privdata_t *pd = get_privdata(v);
338   if (pd->use_fast_360)
339     stp_send_command(v, "\033(K", "bcc", 0, 3);
340   else if (pd->has_graymode)
341     stp_send_command(v, "\033(K", "bcc", 0,
342 		     (pd->use_black_parameters ? 1 : 2));
343 }
344 
345 static void
escp2_set_printer_weave(stp_vars_t * v)346 escp2_set_printer_weave(stp_vars_t *v)
347 {
348   escp2_privdata_t *pd = get_privdata(v);
349   if (pd->printer_weave)
350     stp_write_raw(pd->printer_weave, v);
351   else
352     stp_send_command(v, "\033(i", "bc", 0);
353 }
354 
355 static void
escp2_set_printhead_speed(stp_vars_t * v)356 escp2_set_printhead_speed(stp_vars_t *v)
357 {
358   escp2_privdata_t *pd = get_privdata(v);
359   const char *direction = stp_get_string_parameter(v, "PrintingDirection");
360   int unidirectional = -1;
361   if (direction && strcmp(direction, "Unidirectional") == 0)
362     unidirectional = 1;
363   else if (direction && strcmp(direction, "Bidirectional") == 0)
364     unidirectional = 0;
365   else if (pd->bidirectional_upper_limit >= 0 &&
366 	   pd->res->printed_hres * pd->res->printed_vres *
367 	   pd->res->vertical_passes >= pd->bidirectional_upper_limit)
368     {
369       stp_dprintf(STP_DBG_ESCP2, v,
370 		  "Setting unidirectional: hres %d vres %d passes %d total %d limit %d\n",
371 		  pd->res->printed_hres, pd->res->printed_vres,
372 		  pd->res->vertical_passes,
373 		  (pd->res->printed_hres * pd->res->printed_vres *
374 		   pd->res->vertical_passes),
375 		  pd->bidirectional_upper_limit);
376       unidirectional = 1;
377     }
378   else if (pd->bidirectional_upper_limit >= 0)
379     {
380       stp_dprintf(STP_DBG_ESCP2, v,
381 		  "Setting bidirectional: hres %d vres %d passes %d total %d limit %d\n",
382 		  pd->res->printed_hres, pd->res->printed_vres,
383 		  pd->res->vertical_passes,
384 		  (pd->res->printed_hres * pd->res->printed_vres *
385 		   pd->res->vertical_passes),
386 		  pd->bidirectional_upper_limit);
387       unidirectional = 0;
388     }
389   if (unidirectional == 1)
390     {
391       stp_send_command(v, "\033U", "c", 1);
392       if (pd->res->hres > pd->physical_xdpi)
393 	stp_send_command(v, "\033(s", "bc", 2);
394     }
395   else if (unidirectional == 0)
396     stp_send_command(v, "\033U", "c", 0);
397 }
398 
399 static void
escp2_set_dot_size(stp_vars_t * v)400 escp2_set_dot_size(stp_vars_t *v)
401 {
402   escp2_privdata_t *pd = get_privdata(v);
403   /* Dot size */
404   if (pd->drop_size >= 0)
405     stp_send_command(v, "\033(e", "bcc", 0, pd->drop_size);
406 }
407 
408 static void
escp2_set_page_height(stp_vars_t * v)409 escp2_set_page_height(stp_vars_t *v)
410 {
411   escp2_privdata_t *pd = get_privdata(v);
412   int l = (pd->page_true_height + pd->paper_extra_bottom) *
413     pd->page_management_units / 72;
414   if (pd->use_extended_commands)
415     stp_send_command(v, "\033(C", "bl", l);
416   else
417     stp_send_command(v, "\033(C", "bh", l);
418 }
419 
420 static void
escp2_set_margins(stp_vars_t * v)421 escp2_set_margins(stp_vars_t *v)
422 {
423   escp2_privdata_t *pd = get_privdata(v);
424   int bot = pd->page_management_units * pd->page_bottom / 72;
425   int top = pd->page_management_units * pd->page_top / 72;
426 
427   top += pd->initial_vertical_offset;
428   top -= pd->page_extra_height;
429   bot += pd->page_extra_height;
430   if (pd->use_extended_commands &&
431       (pd->command_set == MODEL_COMMAND_2000 ||
432        pd->command_set == MODEL_COMMAND_PRO))
433     stp_send_command(v, "\033(c", "bll", top, bot);
434   else
435     stp_send_command(v, "\033(c", "bhh", top, bot);
436 }
437 
438 static void
escp2_set_paper_dimensions(stp_vars_t * v)439 escp2_set_paper_dimensions(stp_vars_t *v)
440 {
441   escp2_privdata_t *pd = get_privdata(v);
442   if (pd->advanced_command_set)
443     {
444       const stp_vars_t *pv = pd->media_settings;
445       int w = pd->page_true_width * pd->page_management_units / 72;
446       int h = (pd->page_true_height + pd->paper_extra_bottom) *
447 	pd->page_management_units / 72;
448       stp_send_command(v, "\033(S", "bll", w, h);
449       if (stp_check_int_parameter(pv, "PrintMethod", STP_PARAMETER_ACTIVE))
450 	stp_send_command(v, "\033(m", "bc",
451 			 stp_get_int_parameter(pv, "PrintMethod"));
452     }
453 }
454 
455 static void
escp2_set_printhead_resolution(stp_vars_t * v)456 escp2_set_printhead_resolution(stp_vars_t *v)
457 {
458   escp2_privdata_t *pd = get_privdata(v);
459   if (pd->use_extended_commands)
460     {
461       int xres;
462       int yres = pd->resolution_scale;
463 
464       xres = pd->resolution_scale / pd->physical_xdpi;
465 
466       if (pd->command_set == MODEL_COMMAND_PRO && pd->printer_weave)
467 	yres = yres /  pd->res->vres;
468       else if (pd->split_channel_count > 1)
469 	yres = yres * pd->nozzle_separation / pd->base_separation *
470 	  pd->split_channel_count;
471       else
472 	yres = yres * pd->nozzle_separation / pd->base_separation;
473 
474       /* Magic resolution cookie */
475       stp_send_command(v, "\033(D", "bhcc", pd->resolution_scale, yres, xres);
476     }
477 }
478 
479 static void
set_vertical_position(stp_vars_t * v,stp_pass_t * pass)480 set_vertical_position(stp_vars_t *v, stp_pass_t *pass)
481 {
482   escp2_privdata_t *pd = get_privdata(v);
483   int advance = pass->logicalpassstart - pd->last_pass_offset -
484     (pd->separation_rows - 1);
485   advance = advance * pd->vertical_units / pd->res->printed_vres;
486   if (pass->logicalpassstart > pd->last_pass_offset ||
487       (pd->send_zero_pass_advance && pass->pass > pd->last_pass) ||
488       pd->printing_initial_vertical_offset != 0)
489     {
490       advance += pd->printing_initial_vertical_offset;
491       pd->printing_initial_vertical_offset = 0;
492       if (pd->use_extended_commands)
493 	stp_send_command(v, "\033(v", "bl", advance);
494       else
495 	stp_send_command(v, "\033(v", "bh", advance);
496       pd->last_pass_offset = pass->logicalpassstart;
497       pd->last_pass = pass->pass;
498     }
499 }
500 
501 static void
set_color(stp_vars_t * v,stp_pass_t * pass,int color)502 set_color(stp_vars_t *v, stp_pass_t *pass, int color)
503 {
504   escp2_privdata_t *pd = get_privdata(v);
505   if (pd->last_color != color && ! pd->use_extended_commands)
506     {
507       int ncolor = pd->channels[color]->color;
508       int subchannel = pd->channels[color]->subchannel;
509       if (subchannel >= 0)
510 	stp_send_command(v, "\033(r", "bcc", subchannel, ncolor);
511       else
512 	stp_send_command(v, "\033r", "c", ncolor);
513       pd->last_color = color;
514     }
515 }
516 
517 static void
set_horizontal_position(stp_vars_t * v,stp_pass_t * pass,int vertical_subpass)518 set_horizontal_position(stp_vars_t *v, stp_pass_t *pass, int vertical_subpass)
519 {
520   escp2_privdata_t *pd = get_privdata(v);
521   int microoffset = (vertical_subpass & (pd->horizontal_passes - 1)) *
522     pd->image_scaled_width / pd->image_printed_width;
523   int pos = pd->image_left_position + microoffset;
524 
525   if (pos != 0)
526     {
527       if (pd->command_set == MODEL_COMMAND_PRO || pd->variable_dots)
528 	stp_send_command(v, "\033($", "bl", pos);
529       else if (pd->advanced_command_set || pd->res->hres > 720)
530 	stp_send_command(v, "\033(\\", "bhh", pd->micro_units, pos);
531       else
532 	stp_send_command(v, "\033\\", "h", pos);
533     }
534 }
535 
536 static void
send_print_command(stp_vars_t * v,stp_pass_t * pass,int ncolor,int nlines)537 send_print_command(stp_vars_t *v, stp_pass_t *pass, int ncolor, int nlines)
538 {
539   escp2_privdata_t *pd = get_privdata(v);
540   int lwidth = (pd->image_printed_width + (pd->horizontal_passes - 1)) /
541     pd->horizontal_passes;
542   if (pd->command_set == MODEL_COMMAND_PRO || pd->variable_dots)
543     {
544       int nwidth = pd->bitwidth * ((lwidth + 7) / 8);
545       stp_send_command(v, "\033i", "ccchh", ncolor,
546 		       (stp_get_debug_level() & STP_DBG_NO_COMPRESSION) ? 0 : 1,
547 		       pd->bitwidth, nwidth, nlines);
548     }
549   else
550     {
551       int ygap = 3600 / pd->vertical_units;
552       int xgap = 3600 / pd->physical_xdpi;
553       if (pd->nozzles == 1)
554 	{
555 	  if (pd->vertical_units == 720 && pd->extra_720dpi_separation)
556 	    ygap *= pd->extra_720dpi_separation;
557 	}
558       else if (pd->extra_720dpi_separation)
559 	ygap *= pd->extra_720dpi_separation;
560       else if (pd->pseudo_separation_rows > 0)
561 	ygap *= pd->pseudo_separation_rows;
562       else
563 	ygap *= pd->separation_rows;
564       stp_send_command(v, "\033.", "cccch",
565 		       (stp_get_debug_level() & STP_DBG_NO_COMPRESSION) ? 0 : 1,
566 		       ygap, xgap, nlines, lwidth);
567     }
568 }
569 
570 static void
send_extra_data(stp_vars_t * v,int extralines)571 send_extra_data(stp_vars_t *v, int extralines)
572 {
573   escp2_privdata_t *pd = get_privdata(v);
574   int lwidth = (pd->image_printed_width + (pd->horizontal_passes - 1)) /
575     pd->horizontal_passes;
576   if (stp_get_debug_level() & STP_DBG_NO_COMPRESSION)
577     {
578       int i, k;
579       for (k = 0; k < extralines; k++)
580 	for (i = 0; i < pd->bitwidth * (lwidth + 7) / 8; i++)
581 	  stp_putc(0, v);
582     }
583   else
584     {
585       int k, l;
586       int bytes_to_fill = pd->bitwidth * ((lwidth + 7) / 8);
587       int full_blocks = bytes_to_fill / 128;
588       int leftover = bytes_to_fill % 128;
589       int total_bytes = extralines * (full_blocks + 1) * 2;
590       unsigned char *buf = stp_malloc(total_bytes);
591       total_bytes = 0;
592       for (k = 0; k < extralines; k++)
593 	{
594 	  for (l = 0; l < full_blocks; l++)
595 	    {
596 	      buf[total_bytes++] = 129;
597 	      buf[total_bytes++] = 0;
598 	    }
599 	  if (leftover == 1)
600 	    {
601 	      buf[total_bytes++] = 1;
602 	      buf[total_bytes++] = 0;
603 	    }
604 	  else if (leftover > 0)
605 	    {
606 	      buf[total_bytes++] = 257 - leftover;
607 	      buf[total_bytes++] = 0;
608 	    }
609 	}
610       stp_zfwrite((const char *) buf, total_bytes, 1, v);
611       stp_free(buf);
612     }
613 }
614 
615 void
stpi_escp2_init_printer(stp_vars_t * v)616 stpi_escp2_init_printer(stp_vars_t *v)
617 {
618   escp2_reset_printer(v);
619   escp2_set_remote_sequence(v);
620   escp2_set_graphics_mode(v);
621   escp2_set_resolution(v);
622   escp2_set_color(v);
623   escp2_set_printer_weave(v);
624   escp2_set_printhead_speed(v);
625   escp2_set_dot_size(v);
626   escp2_set_printhead_resolution(v);
627   escp2_set_page_height(v);
628   escp2_set_margins(v);
629   escp2_set_paper_dimensions(v);
630 }
631 
632 void
stpi_escp2_deinit_printer(stp_vars_t * v)633 stpi_escp2_deinit_printer(stp_vars_t *v)
634 {
635   escp2_privdata_t *pd = get_privdata(v);
636   stp_puts("\033@", v);	/* ESC/P2 reset */
637   if (pd->advanced_command_set || pd->input_slot)
638     {
639       stp_send_command(v, "\033(R", "bcs", 0, "REMOTE1");
640       if (pd->inkname->deinit_sequence)
641 	stp_write_raw(pd->inkname->deinit_sequence, v);
642       if (pd->input_slot && pd->input_slot->deinit_sequence)
643 	stp_write_raw(pd->input_slot->deinit_sequence, v);
644       /* Load settings from NVRAM */
645       stp_send_command(v, "LD", "b");
646 
647       /* Magic deinit sequence reported by Simone Falsini */
648       if (pd->deinit_remote_sequence)
649 	stp_write_raw(pd->deinit_remote_sequence, v);
650       /* Exit remote mode */
651       stp_send_command(v, "\033", "ccc", 0, 0, 0);
652     }
653 }
654 
655 void
stpi_escp2_flush_pass(stp_vars_t * v,int passno,int vertical_subpass)656 stpi_escp2_flush_pass(stp_vars_t *v, int passno, int vertical_subpass)
657 {
658   int j;
659   escp2_privdata_t *pd = get_privdata(v);
660   stp_lineoff_t *lineoffs = stp_get_lineoffsets_by_pass(v, passno);
661   stp_lineactive_t *lineactive = stp_get_lineactive_by_pass(v, passno);
662   const stp_linebufs_t *bufs = stp_get_linebases_by_pass(v, passno);
663   stp_pass_t *pass = stp_get_pass_by_pass(v, passno);
664   stp_linecount_t *linecount = stp_get_linecount_by_pass(v, passno);
665   int minlines = pd->min_nozzles;
666   int nozzle_start = pd->nozzle_start;
667 
668   for (j = 0; j < pd->channels_in_use; j++)
669     {
670       if (lineactive->v[j] > 0)
671 	{
672 	  int ncolor = pd->channels[j]->color;
673 	  int subchannel = pd->channels[j]->subchannel;
674 	  int nlines = linecount->v[j];
675 	  int extralines = 0;
676 	  set_vertical_position(v, pass);
677 	  set_color(v, pass, j);
678 	  if (subchannel >= 0)
679 	    ncolor |= (subchannel << 4);
680 
681 	  if (pd->split_channels)
682 	    {
683 	      int sc = pd->split_channel_count;
684 	      int k, l;
685 	      int minlines_lo, nozzle_start_lo;
686 	      minlines /= sc;
687 	      nozzle_start /= sc;
688 	      minlines_lo = pd->min_nozzles - (minlines * sc);
689 	      nozzle_start_lo = pd->nozzle_start - (nozzle_start * sc);
690 	      for (k = 0; k < sc; k++)
691 		{
692 		  int ml = minlines + (k < minlines_lo ? 1 : 0);
693 		  int ns = nozzle_start + (k < nozzle_start_lo ? 1 : 0);
694 		  int lc = ((nlines + (sc - k - 1)) / sc);
695 		  int base = (pd->nozzle_start + k) % sc;
696 		  if (lc < ml)
697 		    extralines = ml - lc;
698 		  else
699 		    extralines = 0;
700 		  extralines -= ns;
701 		  if (extralines < 0)
702 		    extralines = 0;
703 		  if (lc + extralines > 0)
704 		    {
705 		      int sc_off = k + j * sc;
706 		      set_horizontal_position(v, pass, vertical_subpass);
707 		      send_print_command(v, pass, pd->split_channels[sc_off],
708 					 lc + extralines + ns);
709 		      if (ns > 0)
710 			send_extra_data(v, ns);
711 		      for (l = 0; l < lc; l++)
712 			{
713 			  int sp = (l * sc) + base;
714 			  unsigned long offset = sp * pd->split_channel_width;
715 			  if (!(stp_get_debug_level() & STP_DBG_NO_COMPRESSION))
716 			    {
717 			      unsigned char *comp_ptr;
718 			      stp_pack_tiff(v, bufs->v[j] + offset,
719 					    pd->split_channel_width,
720 					    pd->comp_buf, &comp_ptr, NULL, NULL);
721 			      stp_zfwrite((const char *) pd->comp_buf,
722 					  comp_ptr - pd->comp_buf, 1, v);
723 			    }
724 			  else
725 			    stp_zfwrite((const char *) bufs->v[j] + offset,
726 					pd->split_channel_width, 1, v);
727 			}
728 		      if (extralines > 0)
729 			send_extra_data(v, extralines);
730 		      stp_send_command(v, "\r", "");
731 		    }
732 		}
733 	    }
734 	  else
735 	    {
736 	      set_horizontal_position(v, pass, vertical_subpass);
737 	      if (nlines < minlines)
738 		{
739 		  extralines = minlines - nlines;
740 		  nlines = minlines;
741 		}
742 	      send_print_command(v, pass, ncolor, nlines);
743 	      extralines -= nozzle_start;
744 	      /*
745 	       * Send the data
746 	       */
747 	      if (nozzle_start)
748 		send_extra_data(v, nozzle_start);
749 	      stp_zfwrite((const char *)bufs->v[j], lineoffs->v[j], 1, v);
750 	      if (extralines > 0)
751 		send_extra_data(v, extralines);
752 	      stp_send_command(v, "\r", "");
753 	    }
754 	  pd->printed_something = 1;
755 	}
756       lineoffs->v[j] = 0;
757       linecount->v[j] = 0;
758     }
759 }
760 
761 void
stpi_escp2_terminate_page(stp_vars_t * v)762 stpi_escp2_terminate_page(stp_vars_t *v)
763 {
764   escp2_privdata_t *pd = get_privdata(v);
765   if (!pd->input_slot ||
766       !(pd->input_slot->roll_feed_cut_flags & ROLL_FEED_DONT_EJECT))
767     {
768       if (!pd->printed_something)
769 	stp_send_command(v, "\n", "");
770       stp_send_command(v, "\f", "");	/* Eject page */
771     }
772 }
773