/*
*
* Print plug-in EPSON ESC/P2 driver for the GIMP.
*
* Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
* Robert Krawitz (rlk@alum.mit.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "gutenprint-internal.h"
#include
#include "print-escp2.h"
#include
#include
typedef struct
{
const char *attr_name;
short bit_shift;
short bit_width;
} escp2_printer_attr_t;
static const escp2_printer_attr_t escp2_printer_attrs[] =
{
{ "command_mode", 0, 4 },
{ "zero_margin", 4, 3 },
{ "variable_mode", 7, 1 },
{ "graymode", 8, 1 },
{ "fast_360", 9, 1 },
{ "send_zero_advance", 10, 1 },
{ "supports_ink_change", 11, 1 },
{ "packet_mode", 12, 1 },
{ "interchangeable_ink", 13, 1 },
{ "envelope_landscape", 14, 1 },
};
static stpi_escp2_printer_t *escp2_model_capabilities;
static int escp2_model_count = 0;
static int
load_model_from_file(const stp_vars_t *v, const char *filename, int depth)
{
int model = -1;
stp_mxml_node_t *xmod =
stp_xml_parse_file_from_path_uncached_safe(filename, "escp2Model", NULL);
const char *id = stp_mxmlElementGetAttr(xmod, "id");
stp_mxml_node_t *tmp = xmod->child;
stpi_escp2_printer_t *p = stpi_escp2_get_printer(v);
const char *stmp = stp_mxmlElementGetAttr(xmod, "base");
if (id)
model = stp_xmlstrtol(id);
if (depth == 0)
{
p->max_black_resolution = -1;
p->cd_x_offset = -1;
p->cd_y_offset = -1;
p->duplex_left_margin = SHRT_MIN;
p->duplex_right_margin = SHRT_MIN;
p->duplex_top_margin = SHRT_MIN;
p->duplex_bottom_margin = SHRT_MIN;
}
/* Allow recursive definitions */
if (stmp)
{
load_model_from_file(v, stmp, depth + 1);
}
while (tmp)
{
if (tmp->type == STP_MXML_ELEMENT)
{
const char *name = tmp->value.element.name;
const char *target = stp_mxmlElementGetAttr(tmp, "src");
if (target)
{
/* FIXME need to allow override of these! */
if (!strcmp(name, "media"))
stpi_escp2_load_media(v, target);
else if (!strcmp(name, "inputSlots"))
stpi_escp2_load_input_slots(v, target);
else if (!strcmp(name, "mediaSizes"))
stpi_escp2_load_media_sizes(v, target);
else if (!strcmp(name, "printerWeaves"))
stpi_escp2_load_printer_weaves(v, target);
else if (!strcmp(name, "qualityPresets"))
stpi_escp2_load_quality_presets(v, target);
else if (!strcmp(name, "resolutions"))
stpi_escp2_load_resolutions(v, target, NULL);
else if (!strcmp(name, "inkGroup"))
stpi_escp2_load_inkgroup(v, target);
}
else if (tmp->child && tmp->child->type == STP_MXML_TEXT)
{
stp_mxml_node_t *child = tmp->child;
const char *val = child->value.text.string;
if (!strcmp(name, "verticalBorderlessSequence"))
{
STPI_ASSERT(!p->vertical_borderless_sequence, NULL);
p->vertical_borderless_sequence = stp_xmlstrtoraw(val);
}
else if (!strcmp(name, "preinitSequence"))
{
STPI_ASSERT(!p->preinit_sequence, NULL);
p->preinit_sequence = stp_xmlstrtoraw(val);
}
else if (!strcmp(name, "preinitRemoteSequence"))
{
STPI_ASSERT(!p->preinit_remote_sequence, NULL);
p->preinit_remote_sequence = stp_xmlstrtoraw(val);
}
else if (!strcmp(name, "postinitRemoteSequence"))
{
STPI_ASSERT(!p->postinit_remote_sequence, NULL);
p->postinit_remote_sequence = stp_xmlstrtoraw(val);
}
else if (!strcmp(name, "commandSet"))
{
if (!strcmp(val, "1998"))
p->flags |= MODEL_COMMAND_1998;
else if (!strcmp(val, "1999"))
p->flags |= MODEL_COMMAND_1999;
else if (!strcmp(val, "2000"))
p->flags |= MODEL_COMMAND_2000;
else if (!strcmp(val, "Pro"))
p->flags |= MODEL_COMMAND_PRO;
}
else if (!strcmp(name, "borderless"))
{
if (!strcmp(val, "No"))
p->flags |= MODEL_ZEROMARGIN_NO;
else if (!strcmp(val, "Yes"))
p->flags |= MODEL_ZEROMARGIN_YES;
else if (!strcmp(val, "Full"))
p->flags |= MODEL_ZEROMARGIN_FULL;
else if (!strcmp(val, "VerticalRestricted"))
p->flags |= MODEL_ZEROMARGIN_RESTR;
else if (!strcmp(val, "HorizontalOnly"))
p->flags |= MODEL_ZEROMARGIN_H_ONLY;
}
else if (!strcmp(name, "preferredEnvelopeOrientation") &&
!strcmp(val, "Landscape"))
p->flags |= MODEL_ENVELOPE_LANDSCAPE_YES;
else if (!strcmp(name, "headConfiguration"))
{
const char *htype = stp_mxmlElementGetAttr(tmp, "type");
unsigned long data[4] = { 0, 0, 0, 0 };
while (child)
{
if (child->type == STP_MXML_ELEMENT && child->child &&
child->child->type == STP_MXML_TEXT)
{
const char *cname = child->value.element.name;
const char *cval = child->child->value.text.string;
if (!strcmp(cname, "Nozzles"))
data[0] = stp_xmlstrtoul(cval);
else if (!strcmp(cname, "MinNozzles"))
data[1] = stp_xmlstrtoul(cval);
else if (!strcmp(cname, "FirstNozzle"))
data[2] = stp_xmlstrtoul(cval);
else if (!strcmp(cname, "NozzleSeparation"))
data[3] = stp_xmlstrtoul(cval);
}
child = child->next;
}
if (!strcmp(htype, "default"))
{
p->nozzles = data[0];
p->min_nozzles = data[1];
p->nozzle_start = data[2];
p->nozzle_separation = data[3];
if (p->black_nozzles == 0)
{
p->black_nozzles = data[0];
p->min_black_nozzles = data[1];
p->black_nozzle_start = data[2];
p->black_nozzle_separation = data[3];
}
if (p->fast_nozzles == 0)
{
p->fast_nozzles = data[0];
p->min_fast_nozzles = data[1];
p->fast_nozzle_start = data[2];
p->fast_nozzle_separation = data[3];
}
}
else if (!strcmp(htype, "black"))
{
p->black_nozzles = data[0];
p->min_black_nozzles = data[1];
p->black_nozzle_start = data[2];
p->black_nozzle_separation = data[3];
}
else if (!strcmp(htype, "fast"))
{
p->fast_nozzles = data[0];
p->min_fast_nozzles = data[1];
p->fast_nozzle_start = data[2];
p->fast_nozzle_separation = data[3];
}
}
else if (!strcmp(name, "margins"))
{
const char *itype = stp_mxmlElementGetAttr(tmp, "interleave");
const char *mtype = stp_mxmlElementGetAttr(tmp, "media");
const char *dtype = stp_mxmlElementGetAttr(tmp, "duplex");
unsigned long data[4];
int i = 0;
while (child && i < 4)
{
if (child->type == STP_MXML_TEXT)
data[i++] = stp_xmlstrtodim(child->value.text.string);
child = child->next;
}
if (dtype && !strcmp(dtype, "duplex"))
{
p->duplex_left_margin = data[0];
p->duplex_right_margin = data[1];
p->duplex_top_margin = data[2];
p->duplex_bottom_margin = data[3];
}
else if (itype && !strcmp(itype, "soft") &&
mtype && !strcmp(mtype, "sheet"))
{
p->left_margin = data[0];
p->right_margin = data[1];
p->top_margin = data[2];
p->bottom_margin = data[3];
}
else if (itype && !strcmp(itype, "printer") &&
mtype && !strcmp(mtype, "sheet"))
{
p->m_left_margin = data[0];
p->m_right_margin = data[1];
p->m_top_margin = data[2];
p->m_bottom_margin = data[3];
}
else if (itype && !strcmp(itype, "soft") &&
mtype && !strcmp(mtype, "roll"))
{
p->roll_left_margin = data[0];
p->roll_right_margin = data[1];
p->roll_top_margin = data[2];
p->roll_bottom_margin = data[3];
}
else if (itype && !strcmp(itype, "printer") &&
mtype && !strcmp(mtype, "roll"))
{
p->m_roll_left_margin = data[0];
p->m_roll_right_margin = data[1];
p->m_roll_top_margin = data[2];
p->m_roll_bottom_margin = data[3];
}
}
else if (!strcmp(name, "physicalChannels"))
p->physical_channels = stp_xmlstrtoul(val);
else if (!strcmp(name, "baseSeparation"))
p->base_separation = stp_xmlstrtoul(val);
else if (!strcmp(name, "resolutionScale"))
p->resolution_scale = stp_xmlstrtoul(val);
else if (!strcmp(name, "maxBlackResolution"))
p->max_black_resolution = stp_xmlstrtoul(val);
else if (!strcmp(name, "minimumResolution"))
{
p->min_hres = stp_xmlstrtoul(child->value.text.string);
child = child->next;
p->min_vres = stp_xmlstrtoul(child->value.text.string);
}
else if (!strcmp(name, "maximumResolution"))
{
p->max_hres = stp_xmlstrtoul(child->value.text.string);
child = child->next;
p->max_vres = stp_xmlstrtoul(child->value.text.string);
}
else if (!strcmp(name, "extraVerticalFeed"))
p->extra_feed = stp_xmlstrtoul(val);
else if (!strcmp(name, "separationRows"))
p->separation_rows = stp_xmlstrtoul(val);
else if (!strcmp(name, "pseudoSeparationRows"))
p->pseudo_separation_rows = stp_xmlstrtoul(val);
else if (!strcmp(name, "zeroMarginOffset"))
p->zero_margin_offset = stp_xmlstrtoul(val);
else if (!strcmp(name, "microLeftMargin"))
p->micro_left_margin = stp_xmlstrtoul(val);
else if (!strcmp(name, "initialVerticalOffset"))
p->initial_vertical_offset = stp_xmlstrtoul(val);
else if (!strcmp(name, "blackInitialVerticalOffset"))
p->black_initial_vertical_offset = stp_xmlstrtoul(val);
else if (!strcmp(name, "extra720DPISeparation"))
p->extra_720dpi_separation = stp_xmlstrtoul(val);
else if (!strcmp(name, "minHorizontalAlignment"))
p->min_horizontal_position_alignment = stp_xmlstrtoul(val);
else if (!strcmp(name, "baseHorizontalAlignment"))
p->base_horizontal_position_alignment = stp_xmlstrtoul(val);
else if (!strcmp(name, "bidirectionalAutoUpperLimit"))
p->bidirectional_upper_limit = stp_xmlstrtoul(val);
else if (!strcmp(name, "minimumMediaSize"))
{
p->min_paper_width = stp_xmlstrtodim(child->value.text.string);
child = child->next;
p->min_paper_height = stp_xmlstrtodim(child->value.text.string);
}
else if (!strcmp(name, "maximumMediaSize"))
{
p->max_paper_width = stp_xmlstrtodim(child->value.text.string);
child = child->next;
p->max_paper_height = stp_xmlstrtodim(child->value.text.string);
}
else if (!strcmp(name, "maximumImageableArea"))
{
p->max_imageable_width = stp_xmlstrtodim(child->value.text.string);
child = child->next;
p->max_imageable_height = stp_xmlstrtodim(child->value.text.string);
}
else if (!strcmp(name, "CDOffset"))
{
p->cd_x_offset = stp_xmlstrtodim(child->value.text.string);
child = child->next;
p->cd_y_offset = stp_xmlstrtodim(child->value.text.string);
}
else if (!strcmp(name, "CDMediaSize"))
{
p->cd_page_width = stp_xmlstrtodim(child->value.text.string);
child = child->next;
p->cd_page_height = stp_xmlstrtodim(child->value.text.string);
}
else if (!strcmp(name, "extraBottom"))
p->paper_extra_bottom = stp_xmlstrtodim(val);
else if (!strcmp(name, "AlignmentChoices"))
{
p->alignment_passes =
stp_xmlstrtoul(child->value.text.string);
child = child->next;
p->alignment_choices =
stp_xmlstrtoul(child->value.text.string);
child = child->next;
p->alternate_alignment_passes =
stp_xmlstrtoul(child->value.text.string);
child = child->next;
p->alternate_alignment_choices =
stp_xmlstrtoul(child->value.text.string);
}
else if (!strcmp(name, "ChannelNames"))
{
p->channel_names = stp_string_list_create();
while (child)
{
if (child->type == STP_MXML_ELEMENT &&
!strcmp(child->value.element.name, "ChannelName"))
{
const char *cname = stp_mxmlElementGetAttr(child, "name");
const char *ctext = stp_mxmlElementGetAttr(child, "text");
stp_string_list_add_string(p->channel_names, cname, ctext);
}
child = child->next;
}
}
else if (!strcmp(name, "resolutions"))
{
stpi_escp2_load_resolutions(v, filename, tmp);
}
}
else
{
if (!strcmp(name, "supportsVariableDropsizes"))
p->flags |= MODEL_VARIABLE_YES;
else if (!strcmp(name, "hasFastGraymode"))
p->flags |= MODEL_GRAYMODE_YES;
else if (!strcmp(name, "hasFast360DPI"))
p->flags |= MODEL_FAST_360_YES;
else if (!strcmp(name, "sendZeroAdvance"))
p->flags |= MODEL_SEND_ZERO_ADVANCE_YES;
else if (!strcmp(name, "supportsInkChange"))
p->flags |= MODEL_SUPPORTS_INK_CHANGE_YES;
else if (!strcmp(name, "supportsD4Mode"))
p->flags |= MODEL_PACKET_MODE_YES;
else if (!strcmp(name, "hasInterchangeableInkCartridges"))
p->flags |= MODEL_INTERCHANGEABLE_INK_YES;
else if (!strcmp(name, "resolutions"))
stpi_escp2_load_resolutions(v, filename, tmp);
}
}
tmp = tmp->next;
}
stp_xml_free_parsed_file(xmod);
return model;
}
void
stpi_escp2_load_model(const stp_vars_t *v, int model)
{
char buf[MAXPATHLEN+1];
stp_xml_init();
snprintf(buf, MAXPATHLEN, "escp2/model/model_%d.xml", model);
int model_id_from_file = load_model_from_file(v, buf, 0);
stp_xml_exit();
STPI_ASSERT(model_id_from_file == model, v);
}
stpi_escp2_printer_t *
stpi_escp2_get_printer(const stp_vars_t *v)
{
int model = stp_get_model_id(v);
STPI_ASSERT(model >= 0, v);
if (!escp2_model_capabilities)
{
escp2_model_capabilities =
stp_zalloc(sizeof(stpi_escp2_printer_t) * (model + 1));
escp2_model_count = model + 1;
}
else if (model >= escp2_model_count)
{
escp2_model_capabilities =
stp_realloc(escp2_model_capabilities,
sizeof(stpi_escp2_printer_t) * (model + 1));
(void) memset(escp2_model_capabilities + escp2_model_count, 0,
sizeof(stpi_escp2_printer_t) * (model + 1 - escp2_model_count));
escp2_model_count = model + 1;
}
if (!(escp2_model_capabilities[model].active))
{
stp_xml_init();
escp2_model_capabilities[model].active = 1;
stpi_escp2_load_model(v, model);
stp_xml_exit();
}
return &(escp2_model_capabilities[model]);
}
model_featureset_t
stpi_escp2_get_cap(const stp_vars_t *v, escp2_model_option_t feature)
{
const stpi_escp2_printer_t *printdef = stpi_escp2_get_printer(v);
model_featureset_t featureset =
(((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
escp2_printer_attrs[feature].bit_shift);
return printdef->flags & featureset;
}
int
stpi_escp2_has_cap(const stp_vars_t *v, escp2_model_option_t feature,
model_featureset_t class)
{
const stpi_escp2_printer_t *printdef = stpi_escp2_get_printer(v);
model_featureset_t featureset =
(((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
escp2_printer_attrs[feature].bit_shift);
return ((printdef->flags & featureset) == class);
}