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