#!@PERL@
# Get command line options
use Getopt::Long;
Getopt::Long::Configure("no_ignore_case", "pass_through");
GetOptions("m=s" => \$opt_m, # Map file
"t=s" => \$opt_t, # Template directory
"f=s" => \$opt_f, # Foomatic version
"d=s" => \@opt_d); # which Drivers?
# Wherever we put it...
my $mapfile;
# $mapfile = "../main/printers.xml";
$mapfile = $opt_m;
my $templatedir;
$templatedir = $opt_t;
my @drivertypes = ();
for my $d (@opt_d) {
if (lc($d) eq "gs") {
push (@drivertypes, "gs");
}
if (lc($d) eq "ijs") {
push (@drivertypes, "ijs");
}
if (lc($d) eq "nogs") {
@drivertypes = ("ijs");
}
if (lc($d) eq "noijs") {
@drivertypes = ("gs");
}
if (lc($d) eq "all") {
@drivertypes = ("gs", "ijs");
}
if (lc($d) eq "both") {
@drivertypes = ("gs", "ijs");
}
}
exit 0 if ($#drivertypes < 0); # Nothing to be done, exit silently
# Do we have Foomatic 2.9 or newer
my $foomatic3 = ((defined($opt_f)) && ($opt_f >= 2.9));
# The following substitutions happen to the template XML files:
# @@STPVER@@ - the version number (ie '4.1.5')
# @@DRVNAME@@ - driver name (ie gimp-print)
# @@STPRINTERS@@ - ... clause for the driver
# @@OPTCONSTRAINTS@@ - ... object for the option
# @@ENUMVALS@@ - ... section for the enum option
# @@MINVAL@@ - minimum value for numeric setting
# @@MAXVAL@@ - maximum value for numeric setting
# @@DEFVAL@@ - default value for numeric setting
# For some things, there are option-specific root-around-n-writer
# functions. So we have a dispatch table:
#
# function arguments are: ('StpDriverOptionName')
my $funcs = { 'InputSlot' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev, },
'InkType' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'MediaType' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'Model' => { 'OPTCONSTRAINTS' => \&build_model_cons,
'ENUMVALS' => \&build_model_ev },
'PageSize' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'Quality' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'Dither' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'Color' => { 'OPTCONSTRAINTS' => \&build_cons,
'ENUMVALS' => \&build_ev },
'Resolution' => { 'OPTCONSTRAINTS' => \&build_resolution_cons,
'ENUMVALS' => \&build_resolution_ev },
'PrintoutMode' => { 'OPTCONSTRAINTS' =>
\&build_printoutmode_cons,
'ENUMVALS' =>
\&build_printoutmode_ev },
};
my $drivervals = { 'PageSize' => \&optmap_pagesize,
'Color' => \&optmap_color
};
my $debug = 0;
# Foomatic name => Gimp-print name
%argnamemap = ('Quality' => 'Resolution');
$colormap = { 'gs' => { 'Grayscale' => '0',
'Color' => '1',
'BlackAndWhite' => '2' },
'ijs' => { 'Grayscale' => 'DeviceGray',
'Color' => 'DeviceRGB',
'BlackAndWhite' =>
'DeviceGray -dBitsPerSample=1',
'RawCMYK' => 'DeviceCMYK' }
};
use Data::Dumper;
open PIPE, "./printer_options|" or die "Cannot run printer_options: $!\n";
print STDERR "Loading options from ./printer_options...";
while() {
next if m!^#!;
eval $_;
}
close PIPE or die "Cannot run printer_options: $!\n";
print STDERR "done.\n";
if ($foomatic3) {
open PIPE, "./printer_margins|" or die "Cannot run printer_margins: $!\n";
print STDERR "Loading margins from ./printer_margins...";
$code = join('', );
close PIPE or die "Cannot run printer_margins: $!\n";
eval $code or die "Cannot run printer_margins: $!\n";
print STDERR "done.\n";
}
open PIPE, "./stp_limits|" or die "Cannot run stp_limits: $!\n";
print STDERR "Loading options from ./stp_limits...";
while() {
next if m!^#!;
eval $_;
}
close PIPE or die "Cannot run stp_limits: $!\n";
print STDERR "done.\n";
open PIPE, "./printers|" or die "Cannot run printers: $!\n";
print STDERR "Loading options from ./printers...";
while() {
next if m!^#!;
eval $_;
}
close PIPE or die "Cannot run printers: $!\n";
print STDERR "done.\n";
# OK, now %stpdata is a big honking thing, and %defaults is in there, too.
# Invert, to build %bar{$optionname} = [ choice1, choice2 ];
my ($a, $otmp, $vtmp);
for $a (keys(%stpdata)) {
for $otmp (keys %{$stpdata{$a}}) {
for $vtmp (keys (%{$stpdata{$a}{$otmp}})) {
if (!$seen_evchoice{$otmp}{$vtmp}++) {
push (@{$ev_choices{$otmp}}, [ $vtmp,
$stpdata{$a}{$otmp}{$vtmp}]);
}
}
}
}
if ($foomatic3) {
# Generate data for "PrintoutMode" option, only needed for
# Foomatic 2.9.x or newer
print STDERR "Generating data for \"PrintoutMode\" option...";
($printoutmode, $printoutmodechoices) = getprintoutmode();
print STDERR "done.\n";
# Foomatic >= 2.9: Make a list of all choice entries needed in the
# "PrintoutMode" option XML file. Note: every choice ("Draft",
# "Normal", ...) will appear several times, but with different
# strings in "". Constraints will make only the
# right choices getting into the PPD file. Assign a unique ID to
# each entry.
for $a (keys(%{$printoutmode})) {
for $vtmp (keys %{$printoutmode->{$a}}) {
my $mode = $printoutmode->{$a}{$vtmp};
if (!$seen_modes{$vtmp}{$mode}++) {
if (!defined($nums{$vtmp})) {
$nums{$vtmp} = 0;
}
$nums{$vtmp} ++;
$modes{$vtmp}{$mode} = "$vtmp-$nums{$vtmp}";
}
}
}
}
# Step 1: construct a map from Model= values to Foomatic model id's
# this map is %mapstp. The inverse from model to Model is %mapdb
#
# Foomatic is supposed to be a superset, so
open PRINTERS, $mapfile or die "Cannot open mapfile $mapfile: $!\n";
for () {
if (m!^#\s*gptofoo\s+([^\s]+)\s+([^\s]+)!) {
push (@{$mapstp{$1}}, $2);
$mapfoo{$2} = $1; # do we need?
}
}
$missing_drivers = 0;
# Are we missing any stp printers?
for (keys(%stpdata)) {
if (!defined($mapstp{$_})) {
$missing_drivers = 1;
warn "No foomatic printer IDs for gimp-print printer $_.\n";
}
}
for (keys(%mapstp)) {
if (!defined($stpdata{$_})) {
$missing_drivers = 1;
warn "No gimp-print printer for foomatic ID $_.\n";
}
}
if ($missing_drivers) {
die "Cannot continue\n";
}
# Figure out version etc
open PIPE, "./gimp-print-version|" or die "Cannot run gimp-print-version: $!\n";
my $stpvers = ;
close PIPE or die "Cannot run gimp-print-version: $!\n";
chomp $stpvers;
# Build clause...
my @printerlist = ();
push (@printerlist, " \n");
my $p1;
for $p1 (keys(%mapstp)) {
push (@printerlist, " \n");
for my $id (@{$mapstp{$p1}}) {
if ($foomatic3) {
# Add unprintable margins (only Foonmatic 2.9.x)
push(@printerlist, " \n");
push(@printerlist, " $id\n");
push(@printerlist, " \n");
my ($cleft, $cright, $ctop, $cbottom) =
(undef, undef, undef, undef);
if (defined($imageableareas{$p1}{'Custom'})) {
$cleft = $imageableareas{$p1}{'Custom'}{'left'};
$cright = $imageableareas{$p1}{'Custom'}{'right'};
$ctop = $imageableareas{$p1}{'Custom'}{'top'};
$cbottom = $imageableareas{$p1}{'Custom'}{'bottom'};
push(@printerlist, " \n");
push(@printerlist, " \n");
push(@printerlist, " $cleft\n");
push(@printerlist, " $cright\n");
push(@printerlist, " $ctop\n");
push(@printerlist, " $cbottom\n");
push(@printerlist, " \n");
}
for my $ps (keys %{$imageableareas{$p1}}) {
next if $ps eq 'Custom'; # We have done "Custom" already
my ($left, $right, $top, $bottom, $width, $height);
$left = $imageableareas{$p1}{$ps}{'left'};
$right = $imageableareas{$p1}{$ps}{'right'};
$top = $imageableareas{$p1}{$ps}{'top'};
$bottom = $imageableareas{$p1}{$ps}{'bottom'};
$width = $imageableareas{$p1}{$ps}{'width'};
$height = $imageableareas{$p1}{$ps}{'height'};
# If the section serves for this paper size,
# do not define an
next if ((defined($cleft)) &&
($left == $cleft) &&
($right == $width - $cright) &&
($top == $height - $ctop) &&
($bottom == $cbottom));
push(@printerlist, " \n");
push(@printerlist, " \n");
if ($left != $cleft) {
push(@printerlist, " $left\n");
}
if ($right != $width - $cright) {
push(@printerlist, " $right\n");
}
if ($top != $height - $ctop) {
push(@printerlist, " $top\n");
}
if ($bottom != $cbottom) {
push(@printerlist, " $bottom" .
"\n");
}
push(@printerlist, " \n");
}
push(@printerlist, " \n");
push(@printerlist, " \n");
} else {
# Printer IDs only
push(@printerlist, " $id\n");
}
}
}
push (@printerlist, " \n");
$drivernameprefix = "gimp-print";
print STDERR "Using driver name prefix \"$drivernameprefix\"\n";
my $generalsubs = { 'STPVER' => $stpvers,
'DRVNAME' => $drivernameprefix,
'STPRINTERS' => join('', @printerlist) };
my $optiongroups = { 'PageSize' => 'General',
'InputSlot' => 'General',
'MediaType' => 'General',
'InkType' => 'General',
'PrintoutMode' => 'General',
'Resolution' => 'PrintoutMode',
'Quality' => 'PrintoutMode',
'Color' => 'PrintoutMode',
'ImageType' => 'PrintoutMode',
'Dither' => 'PrintoutMode',
'Gamma' => 'Adjustment',
'Density' => 'Adjustment',
'Brightness' => 'Adjustment',
'Contrast' => 'Adjustment',
'Saturation' => 'Adjustment',
'Cyan' => 'Adjustment',
'Magenta' => 'Adjustment',
'Yellow' => 'Adjustment' };
my @numericsubs = ('MINVAL', 'MAXVAL', 'DEFVAL');
# OK, make the db directory...
mkdir "foomatic-db", 0755 or
die "Cannot create directory foomatic-db: $!\n"
unless -d "foomatic-db";
# Now do stuff, already. Do the substitution into each file...
my $tmpl;
for $drivertype (@drivertypes) {
$drivertypesuffix = "-$drivertype";
$drivertypesuffix =~ s/-gs//;
my $drvname = "$drivernameprefix$drivertypesuffix";
$generalsubs->{'DRVNAME'} = $drvname;
print "Generating Foomatic data for driver \"$drvname\"...\n";
# OK, make the db heirarchy alongside the templates one...
mkdir "foomatic-db/$drvname", 0755 or
die "Cannot create directory foomatic-db/$drvname: $!\n"
unless -d "foomatic-db/$drvname";
mkdir "foomatic-db/$drvname/opt", 0755 or
die "Cannot create directory foomatic-db/$drvname/opt: $!\n"
unless -d "foomatic-db/$drvname/opt";
mkdir "foomatic-db/$drvname/driver", 0755 or
die "Cannot create directory foomatic-db/$drvname/driver: $!\n"
unless -d 'foomatic-db/$drvname/driver';
opendir TDIR, "$templatedir-$drivertype" or
die "Cannot open templates directory: $!\n";
while ($tmpl=readdir(TDIR)) {
# Only XML files
next if ($tmpl !~ m!.+\.xml$!);
# The "PrintoutMode" option is only supported by Foomatic 2.9.x or
# newer
next if ((!$foomatic3) && ($tmpl eq "PrintoutMode.xml"));
my $fooopt = $tmpl;
$fooopt =~ s!\.xml$!!;
my $stpopt = $argnamemap{$fooopt};
$stpopt = $fooopt if ! defined ($stpopt);
# print STDERR "Argnamemap '$fooopt' => '$stpopt'\n";
open TMPL, "$templatedir-$drivertype/$tmpl";
my @datafile = ;
close TMPL;
print STDERR "Processing $tmpl...";
my $template = join('',@datafile);
# First, do the generic substitutions.
my ($substr);
for $substr (keys(%$generalsubs)) {
my $substitution = $generalsubs->{$substr};
$template =~ s!\@\@$substr\@\@!$substitution!g;
}
# Put the options into PPD groups (Foomatic >= 2.9)
if ($foomatic3) {
my $substitution = "\n " .
$optiongroups->{$fooopt} . "";
$template =~ s!\@\@GROUP\@\@!$substitution!g;
} else {
$template =~ s!\@\@GROUP\@\@!!g;
}
# Now do the numeric substitutions
for $substr (@numericsubs) {
my $substitution = $stp_values{$substr}{$stpopt};
$template =~ s!\@\@$substr\@\@!$substitution!g;
}
# Now do special-purpose substitutions
for $substr (keys(%{$funcs->{$fooopt}})) {
my $substitution = &{$funcs->{$fooopt}{$substr}}($stpopt);
if (defined($substitution)) {
$template =~ s!\@\@$substr\@\@!$substitution!g;
}
}
# Any more?
grep (m!\@\@([^\@]+)\@\@!g
&& do { warn " Unknown substitution $1 in $tmpl!\n"; },
split("\n",$template));
# Finally, write out the new file
# Options are under opt/
my $dbfilename = lc("foomatic-db/$drvname/opt/$drvname-$tmpl");
# Special case the actual driver file under driver/
$dbfilename = "foomatic-db/$drvname/driver/$drvname.xml"
if ($tmpl eq 'gimp-print.xml');
open NEWF, "> $dbfilename" or die "Cannot create $dbfilename: $!";
print STDERR "writing $dbfilename...";
print NEWF $template;
print STDERR "done.\n";
close NEWF;
}
closedir TDIR;
# The paper size and resolution maps must be regenerated for the next
# driver, because the "driverval"s are different for the different
# drivers. So delete the caches.
undef $pagemap;
undef %rescache;
}
sub get_ev_shortname {
my ($val) = @_;
$val =~ s/ //g;
$val =~ s/\///g;
$val =~ s/\://g;
return $val;
}
sub get_ev_key {
my ($val, $drv) = @_;
return ("ev/$drv-" . get_ev_shortname($val));
}
sub build_ev {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @vals = ();
# OK, now for each enum_val
my $ev;
for $ev (@{$ev_choices{$stpopt}}) {
# Put in the basic choice info: ev names, etc
my $ev_longname = @$ev[1];
my $ev_shortname = @$ev[0];
# The GhostScript driver has no "RawCMYK" output type setting
next if (($drivertype eq "gs") && ($stpopt eq "Color") &&
($ev_shortname eq "RawCMYK"));
my $ev_id = get_ev_key($ev_shortname, $drvname);
my $ev_driverval;
# Either call a per-option function to get the driverval, or
# just use the string choice name.
if (defined($drivervals->{$stpopt})) {
$ev_driverval = &{$drivervals->{$stpopt}}($ev_shortname);
die "Undefined driverval for option $stpopt value $ev_shortname!\n"
if (! defined($ev));
} else {
$ev_driverval = $ev_shortname;
}
# Remove "Roll" paper sizes, user has to use "Custom" instead.
next if (($stpopt eq "PageSize") && ($ev_driverval eq ""));
push (@vals,
" \n",
" $ev_longname\n",
" $ev_shortname\n",
" $ev_driverval\n",
" \n",
" \n",
" \n",
" $drvname\n",
" \n");
# Build constraints for this particular choice
my $stpprn;
for $stpprn (keys(%stpdata)) {
my $fooprn;
for $fooprn (@{$mapstp{$stpprn}}) {
if ($stpdata{$stpprn}{$stpopt}{$ev_shortname}) {
# OK, this choice applies to this printer
push (@vals,
" \n",
" \n",
" $drvname\n",
" $fooprn\n",
" \n");
}
}
}
push (@vals,
" \n",
" \n");
}
return join('',
"\n",
@vals,
" \n");
}
sub build_cons {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @PNCONS = ();
# For each stp printer...
my $stpname;
for $stpname (keys(%stpdata)) {
if (0) {
print STDERR " Processing gimp-print printer $stpname...\n";
print STDERR
" There are no foomatic printers mapped to $stpname!?\n"
if !$mapstp{$stpname};
print STDERR " \%stpdata key is {$stpname}{$stpopt}\n";
}
# Add to this printer to argument constraints?
if ($stpdata{$stpname}{$stpopt}) {
# What's the default value?
my $stpdef = $defaults{$stpname}{$stpopt};
# If there's no default, then this option doesn't apply to
# this printer.
if (defined($stpdef)) {
my $foodefval = get_ev_key($stpdef, $drvname);
if (0) {
print STDERR
" Default for $stpname/$stpopt is $stpdef aka $foodefval\n";
}
my $fooname;
for $fooname (@{$mapstp{$stpname}}) {
if (0) {
print STDERR
" Printer $fooname takes option $stpopt.\n";
}
push (@PNCONS,
" \n",
" $drvname\n",
" $fooname\n",
" $foodefval\n",
" \n");
}
}
}
}
return join('',
"\n",
@PNCONS,
" \n");
}
sub optmap_pagesize {
my ($value) = @_;
if (!defined $pagemap) {
open PUTIL, "./paper_sizes |" or die "Cannot run paper_sizes: $!\n";
while () {
chomp;
$_ =~ m!^\s*(.+\S)\s+([0-9]+)\s+([0-9]+)\s*$!;
my ($name, $width, $height) = ($1, $2, $3);
if (($width > 0 and $height > 0) or
($name eq "Custom")) {
if ($drivertype eq "gs") {
$pagemap->{$name} = "$width $height";
} else {
$pagemap->{$name} = "-dDEVICEWIDTHPOINTS=$width -dDEVICEHEIGHTPOINTS=$height";
}
# print STDERR "PageSize '$name' driverval '$width $height'\n";
}
}
close PUTIL;
}
return $pagemap->{$value}
}
sub optmap_color {
my ($value) = @_;
if (defined $colormap->{$drivertype}{$value}) {
return $colormap->{$drivertype}{$value};
} else {
die "Cannot map output type '$value'\n";
}
}
sub build_model_cons {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
# OK, this is funky. For each stp model, we have a choice. That
# choice is valid for only the foo printers that correspond. For
# any given foo printer, there is *exactly one* available choice.
# The defval is the one available choice. Backends and
# applications do not show options with only one choice; they just
# select that choice. So we don't bother to make pretty option
# names or anything.
#
# See also build_model_ev()
my @PNCONS = ();
# For each stp printer...
my $stpname;
for $stpname (keys(%mapstp)) {
# For each possible foo name
my $fooname;
for $fooname (@{$mapstp{$stpname}}) {
# What's the default value?
my $foodefval = get_ev_key($stpname, $drvname);
push (@PNCONS,
" \n",
" $drvname\n",
" $fooname\n",
" $foodefval\n",
" \n");
}
}
return join('',
"\n",
@PNCONS,
" \n");
}
# See build_model_cons, above.
sub build_model_ev {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @vals = ();
# OK, now for each enum_val
my $ev;
for $ev (keys(%mapstp)) {
# Put in the basic choice info: ev names, etc
my $ev_shortname = $ev;
my $ev_longname = $printer_name{$ev};
my $ev_shortname = get_ev_shortname($ev);
my $ev_id = get_ev_key($ev, $drvname);
my $ev_driverval;
if ($drivertype eq "gs") {
$ev_driverval = $ev;
} else {
my $make;
if ($ev =~ /^escp2/) {
$make = "EPSON";
} elsif ($ev =~ /^bjc/) {
$make = "CANON";
} elsif ($ev =~ /^pcl/) {
$make = "HEWLETT-PACKARD";
} elsif ($ev =~ /^lexmark/) {
$make = "LEXMARK";
} else {
die "Could not determine printer manufacturer from \"$ev\"!\n";
}
$ev_driverval = "-sDeviceManufacturer=$make -sDeviceModel=$ev";
}
push (@vals,
" \n",
" $ev_longname\n",
" $ev_shortname\n",
" $ev_driverval\n",
" \n",
" \n",
" \n",
" $drvname\n",
" \n",
" \n",
);
# This stp Model value applies only to mapped foo printers
my $fooprn;
for $fooprn (@{$mapstp{$ev}}) {
# OK, this choice applies to this enum
push (@vals,
" \n",
" \n",
" $drvname\n",
" $fooprn\n",
" \n");
}
push (@vals,
" \n",
" \n");
}
return join('',
"\n",
@vals,
" \n");
}
# Stuff for Resolution.
#
# printer_options gives us Quality information. We examine this to
# determine what to do for the gs resolution argument:
#
# - Is this a 180/360/720 printer or a 150/300/600 printer?
#
# - What are the legal resolutions? Sort of parse and compute these
# from the Resolution values.
#
# In the case of the GhostScript driver The driverval is "X Y", and gets
# passed in a /HWResolution ps clause, for the IJS driver it is "XxY" and
# gets passed via the "-r" command line option of GhostScript.
sub compute_resolutions {
my ($stpname) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
if (!defined($rescache{$stpname})) {
my @reslist = ();
my %hash;
my $defval;
my $qual;
for $qual (keys(%{$stpdata{$stpname}{'Resolution'}})) {
$qual =~ m!(\d+)\s*(x\s*(\d+))?!;
my ($x, $y) = ($1, $3);
$y = $x if !defined($y);
my $r;
if ($drivertype eq "gs") {
$r = {'x' => $x,
'y' => $y,
'driverval' => "$x $y",
'ev_key' => get_ev_key("res-$x-$y", $drvname)
};
} else {
$r = {'x' => $x,
'y' => $y,
'driverval' => "${x}x${y}",
'ev_key' => get_ev_key("res-$x-$y", $drvname)
};
}
push (@reslist, $r);
# Default?
$defval = get_ev_key("res-$x-$y", $drvname)
if ($qual eq $defaults{$stpname}{'Resolution'});
# Note that this resolution value exists
$resolutions{"$x $y"} = { 'x' => $x,
'y' => $y };
# Note that this printer takes this resolution
$hash{$x}{$y} = 1;
}
$rescache{$stpname}{'list'} = \@reslist;
$rescache{$stpname}{'defval'} = $defval;
$rescache{$stpname}{'takesit'} = \%hash;
}
return $rescache{$stpname};
}
sub do_all_res {
my $n;
for $n (keys(%mapstp)) {
compute_resolutions($n);
}
}
sub build_resolution_ev {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @vals = ();
do_all_res();
# OK, now for each possible resolution...
my $ev;
for $ev (keys(%resolutions)) {
my ($x, $y) = ($resolutions{$ev}{'x'}, $resolutions{$ev}{'y'});
# Put in the basic choice info: ev names, etc
my $ev_longname = "$x x $y DPI";
my $ev_shortname = get_ev_shortname($ev_longname);
my $ev_id = get_ev_key("res-$x-$y", $drvname);
my $ev_driverval;
if ($drivertype eq "gs") {
$ev_driverval = "$x $y";
} else {
$ev_driverval = "${x}x${y}";
}
push (@vals,
" \n",
" $ev_longname\n",
" $ev_shortname\n",
" $ev_driverval\n",
" \n",
" \n",
" \n",
" $drvname\n",
" \n",
" \n",
);
# Now, for each printer, put in a constraint if this
# resolution makes sense or not...
my $stpprn;
for $stpprn (keys(%mapstp)) {
my $resobj = compute_resolutions($stpprn);
my $takesit = $resobj->{'takesit'}{$x}{$y};
if ($takesit) {
my $fooprn;
for $fooprn (@{$mapstp{$stpprn}}) {
# print STDERR "Printer $fooprn $stpprn uses ${x}x$y\n";
# OK, this choice applies to this enum
push (@vals,
" \n",
" $drvname\n",
" $fooprn\n",
" \n");
}
}
}
push (@vals,
" \n",
" \n");
}
return join('',
"\n",
@vals,
" \n");
}
sub build_resolution_cons {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @PNCONS = ();
# For each stp printer...
my $stpname;
for $stpname (keys(%mapstp)) {
# Get some resolution info
my $r = compute_resolutions($stpname);
# For each possible foo name
my $fooname;
for $fooname (@{$mapstp{$stpname}}) {
# What's the default value?
my $foodefval = $r->{'defval'};
push (@PNCONS,
" \n",
" $drvname\n",
" $fooname\n",
" $foodefval\n",
" \n");
}
}
return join('',
"\n",
@PNCONS,
" \n");
}
sub build_printoutmode_ev {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @vals = ();
# OK, now for each choice ("Draft", "Normal", ...) ...
my $choice;
for $choice (keys %modes) {
# ... and each possible "" for it
my $ev_driverval;
for $ev_driverval (keys %{$modes{$choice}}) {
# Put in the basic choice info: ev names, etc
my $ev_longname = $printoutmodechoices->{$choice};
my $ev_shortname = $choice;
my $ev_id =
get_ev_key($modes{$choice}{$ev_driverval}, $drvname);
push (@vals,
" \n",
" $ev_longname\n",
" $ev_shortname\n",
" $ev_driverval\n",
" \n",
" \n",
" \n",
" $drvname\n",
" \n");
# Build constraints for this particular ev_driverval
my $stpprn;
for $stpprn (keys(%stpdata)) {
my $fooprn;
for $fooprn (@{$mapstp{$stpprn}}) {
if ($printoutmode->{$stpprn}{$choice} eq
$ev_driverval) {
# OK, this choice applies to this printer
push (@vals,
" \n",
" \n",
" $drvname\n",
" $fooprn\n",
" \n");
}
}
}
push (@vals,
" \n",
" \n");
}
}
return join('',
"\n",
@vals,
" \n");
}
sub build_printoutmode_cons {
my ($stpopt) = @_;
my $drvname = "$drivernameprefix$drivertypesuffix";
my @PNCONS = ();
# For each stp printer...
my $stpname;
for $stpname (keys(%mapstp)) {
# For each possible foo name
my $fooname;
for $fooname (@{$mapstp{$stpname}}) {
# What's the default value (always the "Normal" mode)?
my $normalmode = $printoutmode->{$stpname}{'Normal'};
my $foodefval = get_ev_key($modes{'Normal'}{$normalmode},
$drvname);
push (@PNCONS,
" \n",
" $drvname\n",
" $fooname\n",
" $foodefval\n",
" \n");
}
}
return join('',
"\n",
@PNCONS,
" \n");
}
sub qualityorder {
# List of suffixes of the Quality choices
my @suffixes = (
# General
"",
"dpi",
# Epson/Lexmark
"mw",
"mw2",
"sw",
"fol",
"fol2",
"fourp",
"uni",
"mwuni",
"mw2uni",
"swuni",
"foluni",
"fol2uni",
"fourpuni",
"hq",
"hquni",
"hq2",
"hq2uni",
# Canon
"dmt",
# HP
"mono",
);
my ($a, $b) = @_;
# Bring the suffixes to lower case
my $first = lc($a);
my $second = lc($b);
# Check whether they are in the @suffixes list
my $i;
for ($i = 0; $i <= $#suffixes; $i++) {
my $firstinlist = ($first eq $suffixes[$i]);
my $secondinlist = ($second eq $suffixes[$i]);
if (($firstinlist) && (!$secondinlist)) {return -1};
if (($secondinlist) && (!$firstinlist)) {return 1};
if (($firstinlist) && ($secondinlist)) {return 0};
}
# Equal quality
die "The quality choice suffixes $a and $b are unknown!\n";
return 0;
}
sub getprintoutmode {
my $choicelongnames = {
'Draft' => 'Draft (Economy)',
'Draft.Gray' => 'Draft Grayscale (Economy)',
'Normal' => 'Normal',
'Normal.Gray' => 'Normal Grayscale',
'High' => 'High Quality',
'High.Gray' => 'High Quality Grayscale',
'VeryHigh' => 'Very High Quality',
'VeryHigh.Gray' => 'Very High Quality Grayscale',
'Photo' => 'Photo',
'Photo.Gray' => 'Photo Grayscale',
};
### BASIC RULES
# See mode-specific rules below
# There must be always a "Normal" mode, this will be the default.
# On black-and-white printers there are no modes with ".Gray"
# specifier, the standard modes are already grayscale.
# No "Photo" mode on laser printers.
# If on a PCL printer "600mono" is the chose quality, it will be
# replaced by "300dpi" in color mode (This can lead to a mode being
# removed by the following two rules).
# If "VeryHigh" has exactly the same settings as "High", "VeryHigh"
# is left out.
# If "High" has exactly the same settings as "Normal", "High"
# is left out.
# If nothing is found for a certain mode, this mode is left out.
my $modes = {};
# Treat all printers
my $stpprn;
for $stpprn (keys(%stpdata)) {
my $modeinfo = {};
my ($draftminres, $draftbestsymmetry, $draftlowestqualstr) =
(99999999, 99999999, "xxx");
my $normaldefaultqual = $defaults{$stpprn}{'Resolution'};
my ($highmaxres, $highbestsymmetry, $highbestqualstr) =
(0, 99999999, "");
my ($veryhighmaxres, $veryhighbestsymmetry, $veryhighbestqualstr) =
(0, 99999999, "");
my ($photomaxres, $photobestsymmetry, $photobestqualstr) =
(0, 99999999, "");
# Go through all choices of the "Quality" option and find the
# best values for the "PrintoutMode" option
my $quality;
for $quality (keys(%{$stpdata{$stpprn}{'Resolution'}})) {
my ($xres, $yres, $qualstr);
if ($quality =~ /^(\d+)x(\d+)(\D.*)$/) {
$xres = $1;
$yres = $2;
$qualstr = $3;
} elsif ($quality =~ /^(\d+)(\D.*)$/) {
$xres = $1;
$yres = $1;
$qualstr = $2;
} else {
die "Invalid quality: $quality\n";
}
# Resolution in dots per square inch
my $respersquareinch = $xres * $yres;
# Symmetry: Shows how far from symmetric a resolution is,
# the smaller, the more symmetric, symmetric resolutions (as
# 300x300 dpi) give zero.
my $symmetry = abs(log($yres/$xres));
### Mode: DRAFT
# Use always the lowest available resolution/quality,
# preferrably symmetric resolutions,
# Do not use resolutions with less than 150 dpi in both
# demensions.
# VeryFast dithering, ImageType LineArt
if (($respersquareinch < $draftminres) ||
(($respersquareinch == $draftminres) &&
($symmetry < $draftbestsymmetry)) ||
(($respersquareinch == $draftminres) &&
($symmetry == $draftbestsymmetry) &&
(qualityorder($qualstr, $draftlowestqualstr) < 0))) {
$draftbestsymmetry = $symmetry;
$draftminres = $respersquareinch;
$draftlowestqualstr = $qualstr;
next if (($xres < 150) && # Resolution not lower than
($yres < 150)); # 150x150, 360x120 allowed
$modeinfo->{'Draft'} = {
'quality' => $quality,
'xres' => $xres,
'yres' => $yres,
'dither' => 'VeryFast',
'image' => 'LineArt'
}
}
### Mode: NORMAL
# Default resolution/quality of GIMP-Print, upgrade to
# unidirectional if possible, use 600x600 dpi for
# Lexmark Z..
# Adaptive Hybrid dithering, ImageType Photographs
if ((($stpprn =~ /^lexmark\-z/) &&
($xres == 600) && ($yres == 600) && ($qualstr eq "uni")) ||
(($stpprn !~ /^lexmark\-z/) &&
(($quality eq "${normaldefaultqual}uni") ||
(($quality eq $normaldefaultqual) &&
(!defined($normal->{'quality'})))))) {
$modeinfo->{'Normal'} = {
'quality' => $quality,
'xres' => $xres,
'yres' => $yres,
'dither' => 'Adaptive',
'image' => 'Photographs'
}
}
### Mode: HIGH
# High: The highest resolution which is not higher than
# 720x720 dpi (Lexmark Z..: 1200x1200 dpi),
# unidirectional if possible,
# not "fol", "fourp", "hq", "hq2"
# Adaptive Hybrid dithering, ImageType Photographs
if (($respersquareinch > $highmaxres) ||
(($respersquareinch == $highmaxres) &&
($symmetry < $highbestsymmetry)) ||
(($respersquareinch == $highmaxres) &&
($symmetry == $highbestsymmetry) &&
(qualityorder($qualstr, $highbestqualstr) > 0))) {
unless ((($stpprn !~ /^lexmark\-z/) &&
(($xres > 720) || # Resolution not higher than
($yres > 720))) || # 720x720 for non Lexmark
($xres > 1200) || # not bigger than 1200x1200
($yres > 1200) || # in general
($qualstr =~ /^(hq.*|fo.*)$/)) { # Not "hq", "hq2",
# "fol", "fourp"
$highbestsymmetry = $symmetry;
$highmaxres = $respersquareinch;
$highbestqualstr = $qualstr;
$modeinfo->{'High'} = {
'quality' => $quality,
'xres' => $xres,
'yres' => $yres,
'dither' => 'Adaptive',
'image' => 'Photographs'
}
}
}
### Mode: VERY HIGH
# Use always the highest available resolution/quality,
# preferrably symmetric resolutions,
# On Epsons: Maximum 1440x720, not "hq2".
# Adaptive Hybrid dithering, ImageType Photographs
if (($respersquareinch > $veryhighmaxres) ||
(($respersquareinch == $veryhighmaxres) &&
($symmetry < $veryhighbestsymmetry)) ||
(($respersquareinch == $veryhighmaxres) &&
($symmetry == $veryhighbestsymmetry) &&
(qualityorder($qualstr, $veryhighbestqualstr) > 0))) {
unless (($stpprn =~ /^escp2/) && # Epson
(($xres > 1440) || # Resolution not higher than
($yres > 720) || # 1440x720
($qualstr eq "hq2"))) { # Not "hq2"
$veryhighbestsymmetry = $symmetry;
$veryhighmaxres = $respersquareinch;
$veryhighbestqualstr = $qualstr;
$modeinfo->{'VeryHigh'} = {
'quality' => $quality,
'xres' => $xres,
'yres' => $yres,
'dither' => 'Adaptive',
'image' => 'Photographs'
}
}
}
### Mode: PHOTO
# Use always the highest available resolution/quality,
# preferrably symmetric resolutions,
# On Epsons: Maximum 2880x720
# EvenTone dithering, ImageType Photographs
if (($respersquareinch > $photomaxres) ||
(($respersquareinch == $photomaxres) &&
($symmetry < $photobestsymmetry)) ||
(($respersquareinch == $photomaxres) &&
($symmetry == $photobestsymmetry) &&
(qualityorder($qualstr, $photobestqualstr) > 0))) {
unless (($stpprn =~ /^escp2/) && # Epson
(($xres > 2880) || # Resolution not higher than
($yres > 720))) { # 2880x720
$photobestsymmetry = $symmetry;
$photomaxres = $respersquareinch;
$photobestqualstr = $qualstr;
$modeinfo->{'Photo'} = {
'quality' => $quality,
'xres' => $xres,
'yres' => $yres,
'dither' => 'EvenTone',
'image' => 'Photographs'
}
}
}
}
# We must have a "Normal" mode for every printer.
if (!defined($modeinfo->{'Normal'}{'quality'})) {
die "No 'Normal' mode for $stpprn!\n";
}
# Build the strings with the settings for the "PrintoutMode"
# option
for my $m (keys(%{$modeinfo})) {
# If we didn't find anything for a certain mode, skip this
# mode
next if (!defined($modeinfo->{$m}{'quality'}));
my $modestr =
"GSResolution=$modeinfo->{$m}{'xres'}x" .
"$modeinfo->{$m}{'yres'}DPI " .
"Quality=$modeinfo->{$m}{'quality'} " .
"Dither=$modeinfo->{$m}{'dither'} " .
"ImageType=$modeinfo->{$m}{'image'}";
if (defined($stpdata{$stpprn}{'Color'}{'Color'})) {
# Color printer
$modes->{$stpprn}{$m} = $modestr . " OutputType=Color";
$modes->{$stpprn}{"$m.Gray"} =
$modestr . " OutputType=Grayscale";
# Some HP inkjets have a "600mono" quality mode which
# is only available in Grayscale, replace this mode by
# "300dpi" in the settings for color printing
if ($modes->{$stpprn}{$m} =~ /600mono/) {
if(!defined($stpdata{$stpprn}{'Resolution'}{'300dpi'})){
die "No '300dpi' mode for $stpprn!";
}
$modes->{$stpprn}{$m} =~ s/600x600DPI/300x300DPI/;
$modes->{$stpprn}{$m} =~ s/600mono/300dpi/;
}
} else {
# bw printer
if ($stpprn =~ /^pcl\-[2-6][vls]?i?$/) { # Laser printer
# No 'Photo' mode on laser printers
next if ($m eq 'Photo');
# Always "VeryFast" dithering on laser printers
$modestr =~ s/(Dither=)\S+/$1VeryFast/;
}
$modes->{$stpprn}{$m} = $modestr . " OutputType=Grayscale";
}
}
# Remove 'VeryHigh' and 'High' if they are identical to lower
# quality modes
if ($modes->{$stpprn}{'VeryHigh'} eq
$modes->{$stpprn}{'High'}) {
delete($modes->{$stpprn}{'VeryHigh'});
}
if ($modes->{$stpprn}{'High'} eq
$modes->{$stpprn}{'Normal'}) {
delete($modes->{$stpprn}{'High'});
}
if (defined($stpdata{$stpprn}{'Color'}{'Color'})) {
# Color printer
if ($modes->{$stpprn}{'VeryHigh.Gray'} eq
$modes->{$stpprn}{'High.Gray'}) {
delete($modes->{$stpprn}{'VeryHigh.Gray'});
}
if ($modes->{$stpprn}{'High.Gray'} eq
$modes->{$stpprn}{'Normal.Gray'}) {
delete($modes->{$stpprn}{'High.Gray'});
}
}
}
return ($modes, $choicelongnames)
}
exit(0);