1/* 2 * "$Id: print-escp2-data.c,v 1.273 2010/08/04 00:33:56 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#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27#include <gutenprint/gutenprint.h> 28#include "gutenprint-internal.h" 29#include <gutenprint/gutenprint-intl-internal.h> 30#include "print-escp2.h" 31#include <limits.h> 32 33typedef struct 34{ 35 const char *attr_name; 36 short bit_shift; 37 short bit_width; 38} escp2_printer_attr_t; 39 40static const escp2_printer_attr_t escp2_printer_attrs[] = 41{ 42 { "command_mode", 0, 4 }, 43 { "zero_margin", 4, 3 }, 44 { "variable_mode", 7, 1 }, 45 { "graymode", 8, 1 }, 46 { "fast_360", 9, 1 }, 47 { "send_zero_advance", 10, 1 }, 48 { "supports_ink_change", 11, 1 }, 49 { "packet_mode", 12, 1 }, 50 { "interchangeable_ink", 13, 1 }, 51 { "envelope_landscape", 14, 1 }, 52}; 53 54static stpi_escp2_printer_t *escp2_model_capabilities; 55 56static int escp2_model_count = 0; 57 58static void 59load_model_from_file(const stp_vars_t *v, stp_mxml_node_t *xmod, int model) 60{ 61 stp_mxml_node_t *tmp = xmod->child; 62 stpi_escp2_printer_t *p = stp_escp2_get_printer(v); 63 int found_black_head_config = 0; 64 int found_fast_head_config = 0; 65 p->max_black_resolution = -1; 66 p->cd_x_offset = -1; 67 p->cd_y_offset = -1; 68 p->duplex_left_margin = SHRT_MIN; 69 p->duplex_right_margin = SHRT_MIN; 70 p->duplex_top_margin = SHRT_MIN; 71 p->duplex_bottom_margin = SHRT_MIN; 72 while (tmp) 73 { 74 if (tmp->type == STP_MXML_ELEMENT) 75 { 76 const char *name = tmp->value.element.name; 77 const char *target = stp_mxmlElementGetAttr(tmp, "src"); 78 if (target) 79 { 80 if (!strcmp(name, "media")) 81 stp_escp2_load_media(v, target); 82 else if (!strcmp(name, "inputSlots")) 83 stp_escp2_load_input_slots(v, target); 84 else if (!strcmp(name, "mediaSizes")) 85 stp_escp2_load_media_sizes(v, target); 86 else if (!strcmp(name, "printerWeaves")) 87 stp_escp2_load_printer_weaves(v, target); 88 else if (!strcmp(name, "qualityPresets")) 89 stp_escp2_load_quality_presets(v, target); 90 else if (!strcmp(name, "resolutions")) 91 stp_escp2_load_resolutions(v, target); 92 else if (!strcmp(name, "inkGroup")) 93 stp_escp2_load_inkgroup(v, target); 94 } 95 else if (tmp->child && tmp->child->type == STP_MXML_TEXT) 96 { 97 stp_mxml_node_t *child = tmp->child; 98 const char *val = child->value.text.string; 99 if (!strcmp(name, "verticalBorderlessSequence")) 100 { 101 STPI_ASSERT(!p->vertical_borderless_sequence, NULL); 102 p->vertical_borderless_sequence = stp_xmlstrtoraw(val); 103 } 104 else if (!strcmp(name, "preinitSequence")) 105 { 106 STPI_ASSERT(!p->preinit_sequence, NULL); 107 p->preinit_sequence = stp_xmlstrtoraw(val); 108 } 109 else if (!strcmp(name, "preinitRemoteSequence")) 110 { 111 STPI_ASSERT(!p->preinit_remote_sequence, NULL); 112 p->preinit_remote_sequence = stp_xmlstrtoraw(val); 113 } 114 else if (!strcmp(name, "postinitRemoteSequence")) 115 { 116 STPI_ASSERT(!p->postinit_remote_sequence, NULL); 117 p->postinit_remote_sequence = stp_xmlstrtoraw(val); 118 } 119 else if (!strcmp(name, "commandSet")) 120 { 121 if (!strcmp(val, "1998")) 122 p->flags |= MODEL_COMMAND_1998; 123 else if (!strcmp(val, "1999")) 124 p->flags |= MODEL_COMMAND_1999; 125 else if (!strcmp(val, "2000")) 126 p->flags |= MODEL_COMMAND_2000; 127 else if (!strcmp(val, "Pro")) 128 p->flags |= MODEL_COMMAND_PRO; 129 } 130 else if (!strcmp(name, "borderless")) 131 { 132 if (!strcmp(val, "No")) 133 p->flags |= MODEL_ZEROMARGIN_NO; 134 else if (!strcmp(val, "Yes")) 135 p->flags |= MODEL_ZEROMARGIN_YES; 136 else if (!strcmp(val, "Full")) 137 p->flags |= MODEL_ZEROMARGIN_FULL; 138 else if (!strcmp(val, "VerticalRestricted")) 139 p->flags |= MODEL_ZEROMARGIN_RESTR; 140 else if (!strcmp(val, "HorizontalOnly")) 141 p->flags |= MODEL_ZEROMARGIN_H_ONLY; 142 } 143 else if (!strcmp(name, "preferredEnvelopeOrientation") && 144 !strcmp(val, "Landscape")) 145 p->flags |= MODEL_ENVELOPE_LANDSCAPE_YES; 146 else if (!strcmp(name, "headConfiguration")) 147 { 148 const char *htype = stp_mxmlElementGetAttr(tmp, "type"); 149 unsigned long data[4] = { 0, 0, 0, 0 }; 150 while (child) 151 { 152 if (child->type == STP_MXML_ELEMENT && child->child && 153 child->child->type == STP_MXML_TEXT) 154 { 155 const char *cname = child->value.element.name; 156 const char *cval = child->child->value.text.string; 157 if (!strcmp(cname, "Nozzles")) 158 data[0] = stp_xmlstrtoul(cval); 159 else if (!strcmp(cname, "MinNozzles")) 160 data[1] = stp_xmlstrtoul(cval); 161 else if (!strcmp(cname, "FirstNozzle")) 162 data[2] = stp_xmlstrtoul(cval); 163 else if (!strcmp(cname, "NozzleSeparation")) 164 data[3] = stp_xmlstrtoul(cval); 165 } 166 child = child->next; 167 } 168 if (!strcmp(htype, "default")) 169 { 170 p->nozzles = data[0]; 171 p->min_nozzles = data[1]; 172 p->nozzle_start = data[2]; 173 p->nozzle_separation = data[3]; 174 if (!found_black_head_config) 175 { 176 p->black_nozzles = data[0]; 177 p->min_black_nozzles = data[1]; 178 p->black_nozzle_start = data[2]; 179 p->black_nozzle_separation = data[3]; 180 } 181 if (!found_fast_head_config) 182 { 183 p->fast_nozzles = data[0]; 184 p->min_fast_nozzles = data[1]; 185 p->fast_nozzle_start = data[2]; 186 p->fast_nozzle_separation = data[3]; 187 } 188 } 189 else if (!strcmp(htype, "black")) 190 { 191 p->black_nozzles = data[0]; 192 p->min_black_nozzles = data[1]; 193 p->black_nozzle_start = data[2]; 194 p->black_nozzle_separation = data[3]; 195 found_black_head_config = 1; 196 } 197 else if (!strcmp(htype, "fast")) 198 { 199 p->fast_nozzles = data[0]; 200 p->min_fast_nozzles = data[1]; 201 p->fast_nozzle_start = data[2]; 202 p->fast_nozzle_separation = data[3]; 203 found_fast_head_config = 1; 204 } 205 } 206 else if (!strcmp(name, "margins")) 207 { 208 const char *itype = stp_mxmlElementGetAttr(tmp, "interleave"); 209 const char *mtype = stp_mxmlElementGetAttr(tmp, "media"); 210 const char *dtype = stp_mxmlElementGetAttr(tmp, "duplex"); 211 unsigned long data[4]; 212 int i = 0; 213 while (child && i < 4) 214 { 215 if (child->type == STP_MXML_TEXT) 216 data[i++] = stp_xmlstrtoul(child->value.text.string); 217 child = child->next; 218 } 219 if (dtype && !strcmp(dtype, "duplex")) 220 { 221 p->duplex_left_margin = data[0]; 222 p->duplex_right_margin = data[1]; 223 p->duplex_top_margin = data[2]; 224 p->duplex_bottom_margin = data[3]; 225 } 226 else if (itype && !strcmp(itype, "soft") && 227 mtype && !strcmp(mtype, "sheet")) 228 { 229 p->left_margin = data[0]; 230 p->right_margin = data[1]; 231 p->top_margin = data[2]; 232 p->bottom_margin = data[3]; 233 } 234 else if (itype && !strcmp(itype, "printer") && 235 mtype && !strcmp(mtype, "sheet")) 236 { 237 p->m_left_margin = data[0]; 238 p->m_right_margin = data[1]; 239 p->m_top_margin = data[2]; 240 p->m_bottom_margin = data[3]; 241 } 242 else if (itype && !strcmp(itype, "soft") && 243 mtype && !strcmp(mtype, "roll")) 244 { 245 p->roll_left_margin = data[0]; 246 p->roll_right_margin = data[1]; 247 p->roll_top_margin = data[2]; 248 p->roll_bottom_margin = data[3]; 249 } 250 else if (itype && !strcmp(itype, "printer") && 251 mtype && !strcmp(mtype, "roll")) 252 { 253 p->m_roll_left_margin = data[0]; 254 p->m_roll_right_margin = data[1]; 255 p->m_roll_top_margin = data[2]; 256 p->m_roll_bottom_margin = data[3]; 257 } 258 } 259 else if (!strcmp(name, "physicalChannels")) 260 p->physical_channels = stp_xmlstrtoul(val); 261 else if (!strcmp(name, "baseSeparation")) 262 p->base_separation = stp_xmlstrtoul(val); 263 else if (!strcmp(name, "resolutionScale")) 264 p->resolution_scale = stp_xmlstrtoul(val); 265 else if (!strcmp(name, "maxBlackResolution")) 266 p->max_black_resolution = stp_xmlstrtoul(val); 267 else if (!strcmp(name, "minimumResolution")) 268 { 269 p->min_hres = stp_xmlstrtoul(child->value.text.string); 270 child = child->next; 271 p->min_vres = stp_xmlstrtoul(child->value.text.string); 272 } 273 else if (!strcmp(name, "maximumResolution")) 274 { 275 p->max_hres = stp_xmlstrtoul(child->value.text.string); 276 child = child->next; 277 p->max_vres = stp_xmlstrtoul(child->value.text.string); 278 } 279 else if (!strcmp(name, "extraVerticalFeed")) 280 p->extra_feed = stp_xmlstrtoul(val); 281 else if (!strcmp(name, "separationRows")) 282 p->separation_rows = stp_xmlstrtoul(val); 283 else if (!strcmp(name, "pseudoSeparationRows")) 284 p->pseudo_separation_rows = stp_xmlstrtoul(val); 285 else if (!strcmp(name, "zeroMarginOffset")) 286 p->zero_margin_offset = stp_xmlstrtoul(val); 287 else if (!strcmp(name, "microLeftMargin")) 288 p->micro_left_margin = stp_xmlstrtoul(val); 289 else if (!strcmp(name, "initialVerticalOffset")) 290 p->initial_vertical_offset = stp_xmlstrtoul(val); 291 else if (!strcmp(name, "blackInitialVerticalOffset")) 292 p->black_initial_vertical_offset = stp_xmlstrtoul(val); 293 else if (!strcmp(name, "extra720DPISeparation")) 294 p->extra_720dpi_separation = stp_xmlstrtoul(val); 295 else if (!strcmp(name, "minHorizontalAlignment")) 296 p->min_horizontal_position_alignment = stp_xmlstrtoul(val); 297 else if (!strcmp(name, "baseHorizontalAlignment")) 298 p->base_horizontal_position_alignment = stp_xmlstrtoul(val); 299 else if (!strcmp(name, "bidirectionalAutoUpperLimit")) 300 p->bidirectional_upper_limit = stp_xmlstrtoul(val); 301 else if (!strcmp(name, "minimumMediaSize")) 302 { 303 p->min_paper_width = stp_xmlstrtoul(child->value.text.string); 304 child = child->next; 305 p->min_paper_height = stp_xmlstrtoul(child->value.text.string); 306 } 307 else if (!strcmp(name, "maximumMediaSize")) 308 { 309 p->max_paper_width = stp_xmlstrtoul(child->value.text.string); 310 child = child->next; 311 p->max_paper_height = stp_xmlstrtoul(child->value.text.string); 312 } 313 else if (!strcmp(name, "maximumImageableArea")) 314 { 315 p->max_imageable_width = stp_xmlstrtoul(child->value.text.string); 316 child = child->next; 317 p->max_imageable_height = stp_xmlstrtoul(child->value.text.string); 318 } 319 else if (!strcmp(name, "CDOffset")) 320 { 321 p->cd_x_offset = stp_xmlstrtoul(child->value.text.string); 322 child = child->next; 323 p->cd_y_offset = stp_xmlstrtoul(child->value.text.string); 324 } 325 else if (!strcmp(name, "CDMediaSize")) 326 { 327 p->cd_page_width = stp_xmlstrtoul(child->value.text.string); 328 child = child->next; 329 p->cd_page_height = stp_xmlstrtoul(child->value.text.string); 330 } 331 else if (!strcmp(name, "extraBottom")) 332 p->paper_extra_bottom = stp_xmlstrtoul(val); 333 else if (!strcmp(name, "AlignmentChoices")) 334 { 335 p->alignment_passes = 336 stp_xmlstrtoul(child->value.text.string); 337 child = child->next; 338 p->alignment_choices = 339 stp_xmlstrtoul(child->value.text.string); 340 child = child->next; 341 p->alternate_alignment_passes = 342 stp_xmlstrtoul(child->value.text.string); 343 child = child->next; 344 p->alternate_alignment_choices = 345 stp_xmlstrtoul(child->value.text.string); 346 } 347 else if (!strcmp(name, "ChannelNames")) 348 { 349 p->channel_names = stp_string_list_create(); 350 while (child) 351 { 352 if (child->type == STP_MXML_ELEMENT && 353 !strcmp(child->value.element.name, "ChannelName")) 354 { 355 const char *cname = stp_mxmlElementGetAttr(child, "name"); 356 stp_string_list_add_string(p->channel_names, cname, cname); 357 } 358 child = child->next; 359 } 360 } 361 else if (!strcmp(name, "resolutions")) 362 stp_escp2_load_resolutions_from_xml(v, tmp); 363 } 364 else 365 { 366 if (!strcmp(name, "supportsVariableDropsizes")) 367 p->flags |= MODEL_VARIABLE_YES; 368 else if (!strcmp(name, "hasFastGraymode")) 369 p->flags |= MODEL_GRAYMODE_YES; 370 else if (!strcmp(name, "hasFast360DPI")) 371 p->flags |= MODEL_FAST_360_YES; 372 else if (!strcmp(name, "sendZeroAdvance")) 373 p->flags |= MODEL_SEND_ZERO_ADVANCE_YES; 374 else if (!strcmp(name, "supportsInkChange")) 375 p->flags |= MODEL_SUPPORTS_INK_CHANGE_YES; 376 else if (!strcmp(name, "supportsD4Mode")) 377 p->flags |= MODEL_PACKET_MODE_YES; 378 else if (!strcmp(name, "hasInterchangeableInkCartridges")) 379 p->flags |= MODEL_INTERCHANGEABLE_INK_YES; 380 else if (!strcmp(name, "resolutions")) 381 stp_escp2_load_resolutions_from_xml(v, tmp); 382 } 383 } 384 tmp = tmp->next; 385 } 386} 387 388void 389stp_escp2_load_model(const stp_vars_t *v, int model) 390{ 391 stp_list_t *dirlist = stpi_data_path(); 392 stp_list_item_t *item; 393 char buf[1024]; 394 int found = 0; 395 396 stp_xml_init(); 397 sprintf(buf, "escp2/model/model_%d.xml", model); 398 item = stp_list_get_start(dirlist); 399 while (item) 400 { 401 const char *dn = (const char *) stp_list_item_get_data(item); 402 char *fn = stpi_path_merge(dn, buf); 403 stp_mxml_node_t *doc = stp_mxmlLoadFromFile(NULL, fn, STP_MXML_NO_CALLBACK); 404 stp_free(fn); 405 if (doc) 406 { 407 stp_mxml_node_t *node = 408 stp_mxmlFindElement(doc, doc, "escp2:model", NULL, NULL, 409 STP_MXML_DESCEND); 410 if (node) 411 { 412 const char *stmp = stp_mxmlElementGetAttr(node, "id"); 413 STPI_ASSERT(stmp && stp_xmlstrtol(stmp) == model, v); 414 load_model_from_file(v, node, model); 415 found = 1; 416 } 417 stp_mxmlDelete(doc); 418 if (found) 419 break; 420 } 421 item = stp_list_item_next(item); 422 } 423 stp_xml_exit(); 424 stp_list_destroy(dirlist); 425 STPI_ASSERT(found, v); 426} 427 428stpi_escp2_printer_t * 429stp_escp2_get_printer(const stp_vars_t *v) 430{ 431 int model = stp_get_model_id(v); 432 STPI_ASSERT(model >= 0, v); 433 if (!escp2_model_capabilities) 434 { 435 escp2_model_capabilities = 436 stp_zalloc(sizeof(stpi_escp2_printer_t) * (model + 1)); 437 escp2_model_count = model + 1; 438 } 439 else if (model >= escp2_model_count) 440 { 441 escp2_model_capabilities = 442 stp_realloc(escp2_model_capabilities, 443 sizeof(stpi_escp2_printer_t) * (model + 1)); 444 (void) memset(escp2_model_capabilities + escp2_model_count, 0, 445 sizeof(stpi_escp2_printer_t) * (model + 1 - escp2_model_count)); 446 escp2_model_count = model + 1; 447 } 448 if (!(escp2_model_capabilities[model].active)) 449 { 450#ifdef HAVE_LOCALE_H 451 char *locale = stp_strdup(setlocale(LC_ALL, NULL)); 452 setlocale(LC_ALL, "C"); 453#endif 454 escp2_model_capabilities[model].active = 1; 455 stp_escp2_load_model(v, model); 456#ifdef HAVE_LOCALE_H 457 setlocale(LC_ALL, locale); 458 stp_free(locale); 459#endif 460 } 461 return &(escp2_model_capabilities[model]); 462} 463 464model_featureset_t 465stp_escp2_get_cap(const stp_vars_t *v, escp2_model_option_t feature) 466{ 467 stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v); 468 model_featureset_t featureset = 469 (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) << 470 escp2_printer_attrs[feature].bit_shift); 471 return printdef->flags & featureset; 472} 473 474int 475stp_escp2_has_cap(const stp_vars_t *v, escp2_model_option_t feature, 476 model_featureset_t class) 477{ 478 stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v); 479 model_featureset_t featureset = 480 (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) << 481 escp2_printer_attrs[feature].bit_shift); 482 return ((printdef->flags & featureset) == class); 483} 484