diff options
Diffstat (limited to 'src/foomatic/foomatic-generator.in')
-rw-r--r-- | src/foomatic/foomatic-generator.in | 909 |
1 files changed, 810 insertions, 99 deletions
diff --git a/src/foomatic/foomatic-generator.in b/src/foomatic/foomatic-generator.in index 57950aa..b5b3f7a 100644 --- a/src/foomatic/foomatic-generator.in +++ b/src/foomatic/foomatic-generator.in @@ -1,10 +1,48 @@ #!@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 + "o" => \$opt_o, # Old Foomatic IDs + "d=s" => \@opt_d); # which Drivers? + # Wherever we put it... my $mapfile; # $mapfile = "../main/printers.xml"; -$mapfile = "foomatic-printermap"; +$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') @@ -39,6 +77,10 @@ my $funcs = { 'InputSlot' => { '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, @@ -50,9 +92,15 @@ my $debug = 0; # Foomatic name => Gimp-print name %argnamemap = ('Quality' => 'Resolution'); -%colormap = ('Grayscale' => 0, - 'Color' => 1, - 'BlackAndWhite' => 2); +$colormap = { 'gs' => { 'Grayscale' => '0', + 'Color' => '1', + 'BlackAndWhite' => '2' }, + 'ijs' => { 'Grayscale' => 'DeviceGray', + 'Color' => 'DeviceRGB', + 'BlackAndWhite' => + 'DeviceGray -dBitsPerSample=1', + 'RawCMYK' => 'DeviceCMYK' } + }; use Data::Dumper; @@ -65,6 +113,15 @@ while(<PIPE>) { 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('', <PIPE>); + 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(<PIPE>) { @@ -83,6 +140,24 @@ while(<PIPE>) { close PIPE or die "Cannot run printers: $!\n"; print STDERR "done.\n"; +my %oldid; +if ($opt_o) { + # Load table to translate the Foomatic IDs to the old (numerical) ones + print STDERR + "Loading printer ID translation table from @srcdir@/oldprinterids..."; + my $translation_table = "@srcdir@/oldprinterids"; + open TRTAB, "< $translation_table" or + die "Cannot read printer ID translation table: $!\n"; + while (<TRTAB>) { + chomp; + if (/^\s*(\S+)\s+(\S+)\s*$/) { + $oldid{"printer/$2"} = "printer/$1"; + } + } + close TRTAB; + 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 ]; @@ -98,6 +173,31 @@ for $a (keys(%stpdata)) { } } +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 "<ev_driverval>". 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 @@ -106,9 +206,16 @@ for $a (keys(%stpdata)) { open PRINTERS, $mapfile or die "Cannot open mapfile $mapfile: $!\n"; for (<PRINTERS>) { - if (m!^#\s*gptofoo\s+([^\s]+)\s+([^\s]+)!) { - push (@{$mapstp{$1}}, $2); - $mapfoo{$2} = $1; # do we need? + if (m!^\#\s*gptofoo\s+([^\s]+)\s+([^\s]+)!) { + my $foomaticid = $2; + my $deviceclass = $1; + if ($opt_o) { + # Translate the Foomatic IDs to the old (numerical) ones + $foomaticid = $oldid{$foomaticid} + if defined($oldid{$foomaticid}); + } + push (@{$mapstp{$deviceclass}}, $foomaticid); + $mapfoo{$foomaticid} = $deviceclass; # do we need? } } @@ -122,6 +229,13 @@ for (keys(%stpdata)) { } } +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"; } @@ -131,7 +245,6 @@ open PIPE, "./gimp-print-version|" or die "Cannot run gimp-print-version: $!\n"; my $stpvers = <PIPE>; close PIPE or die "Cannot run gimp-print-version: $!\n"; chomp $stpvers; -print STDERR "Using drivername gimp-print\n"; # Build <printers> clause... my @printerlist = (); @@ -139,96 +252,215 @@ push (@printerlist, " <printers>\n"); my $p1; for $p1 (keys(%mapstp)) { push (@printerlist, " <!-- gimp-print driver: $p1 -->\n"); - for (@{$mapstp{$p1}}) { - push(@printerlist, " <printer><id>$_</id></printer>\n"); + for my $id (@{$mapstp{$p1}}) { + if ($foomatic3) { + # Add unprintable margins (only Foonmatic 2.9.x) + push(@printerlist, " <printer>\n"); + push(@printerlist, " <id>$id</id>\n"); + push(@printerlist, " <margins>\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, " <general>\n"); + push(@printerlist, " <relative />\n"); + push(@printerlist, " <left>$cleft</left>\n"); + push(@printerlist, " <right>$cright</right>\n"); + push(@printerlist, " <top>$ctop</top>\n"); + push(@printerlist, " <bottom>$cbottom</bottom>\n"); + push(@printerlist, " </general>\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 <general> section serves for this paper size, + # do not define an <exception> + next if ((defined($cleft)) && + ($left == $cleft) && + ($right == $width - $cright) && + ($top == $height - $ctop) && + ($bottom == $cbottom)); + push(@printerlist, " <exception PageSize=\"$ps\">\n"); + push(@printerlist, " <absolute />\n"); + if ($left != $cleft) { + push(@printerlist, " <left>$left</left>\n"); + } + if ($right != $width - $cright) { + push(@printerlist, " <right>$right</right>\n"); + } + if ($top != $height - $ctop) { + push(@printerlist, " <top>$top</top>\n"); + } + if ($bottom != $cbottom) { + push(@printerlist, " <bottom>$bottom" . + "</bottom>\n"); + } + push(@printerlist, " </exception>\n"); + } + push(@printerlist, " </margins>\n"); + push(@printerlist, " </printer>\n"); + } else { + # Printer IDs only + push(@printerlist, " <printer><id>$id</id></printer>\n"); + } } } push (@printerlist, " </printers>\n"); +$drivernameprefix = "gimp-print"; +print STDERR "Using driver name prefix \"$drivernameprefix\"\n"; + my $generalsubs = { 'STPVER' => $stpvers, - 'DRVNAME' => "gimp-print", + 'DRVNAME' => $drivernameprefix, 'STPRINTERS' => join('', @printerlist) }; -my @numericsubs = ('MINVAL', 'MAXVAL', 'DEFVAL'); +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' }; -opendir TDIR, "foomatic-templates" or die "Cannot open templates directory: $!\n"; +my @numericsubs = ('MINVAL', 'MAXVAL', 'DEFVAL'); -# OK, make the db heirarchy alongside the templates one... -mkdir 'foomatic-db', 0755 or die "Cannot create directory foomatic-db: $!\n" - unless -d 'foomatic-db'; -mkdir 'foomatic-db/opt', 0755 or die "Cannot create directory foomatic-db/opt: $!\n" - unless -d 'foomatic-db/opt'; -mkdir 'foomatic-db/driver', 0755 or die "Cannot create directory foomatic-db/driver: $!\n" - unless -d 'foomatic-db/driver'; +# 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; -while ($tmpl=readdir(TDIR)) { - next if ($tmpl !~ m!.+\.xml$!); - - my $fooopt = $tmpl; - $fooopt =~ s!\.xml$!!; - my $stpopt = $argnamemap{$fooopt}; - $stpopt = $fooopt if ! defined ($stpopt); - -# print STDERR "Argnamemap '$fooopt' => '$stpopt'\n"; +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 = <TMPL>; + 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; + } - open TMPL, "foomatic-templates/$tmpl"; - my @datafile = <TMPL>; - close TMPL; + # Put the options into PPD groups (Foomatic >= 2.9) - print STDERR "Processing $tmpl..."; + if ($foomatic3) { + my $substitution = "\n <arg_group>" . + $optiongroups->{$fooopt} . "</arg_group>"; + $template =~ s!\@\@GROUP\@\@!$substitution!g; + } else { + $template =~ s!\@\@GROUP\@\@!!g; + } - my $template = join('',@datafile); + # Now do the numeric substitutions - # First, do the generic substitutions. + for $substr (@numericsubs) { + my $substitution = $stp_values{$substr}{$stpopt}; + $template =~ s!\@\@$substr\@\@!$substitution!g; + } - my ($substr); - for $substr (keys(%$generalsubs)) { - my $substitution = $generalsubs->{$substr}; - $template =~ s!\@\@$substr\@\@!$substitution!g; - } + # Now do special-purpose substitutions - # Now do the numeric substitutions + for $substr (keys(%{$funcs->{$fooopt}})) { + my $substitution = &{$funcs->{$fooopt}{$substr}}($stpopt); + if (defined($substitution)) { + $template =~ s!\@\@$substr\@\@!$substitution!g; + } + } - for $substr (@numericsubs) { - my $substitution = $stp_values{$substr}{$stpopt}; - $template =~ s!\@\@$substr\@\@!$substitution!g; - } + # Any more? + grep (m!\@\@([^\@]+)\@\@!g + && do { warn " Unknown substitution $1 in $tmpl!\n"; }, + split("\n",$template)); - # Now do special-purpose substitutions + # Finally, write out the new file - for $substr (keys(%{$funcs->{$fooopt}})) { - my $substitution = &{$funcs->{$fooopt}{$substr}}($stpopt); - if (defined($substitution)) { - $template =~ s!\@\@$substr\@\@!$substitution!g; - } - } + # Options are under opt/ + my $dbfilename = lc("foomatic-db/$drvname/opt/$drvname-$tmpl"); - # Any more? - grep (m!\@\@([^\@]+)\@\@!g - && do { warn " Unknown substitution $1 in $tmpl!\n"; }, - split("\n",$template)); + # Special case the actual driver file under driver/ + $dbfilename = "foomatic-db/$drvname/driver/$drvname.xml" + if ($tmpl eq 'gimp-print.xml'); - # Finally, write out the new file + open NEWF, "> $dbfilename" or die "Cannot create $dbfilename: $!"; + print STDERR "writing $dbfilename..."; + print NEWF $template; + print STDERR "done.\n"; + close NEWF; - # Options are under opt/ - my $dbfilename = lc("foomatic-db/opt/gimp-print-$tmpl"); + } - # Special case the actual driver file under driver/ - $dbfilename = "foomatic-db/driver/gimp-print.xml" - if ($tmpl eq 'gimp-print.xml'); + closedir TDIR; - open NEWF, "> $dbfilename" or die "Cannot create $dbfilename: $!"; - print STDERR "writing $dbfilename..."; - print NEWF $template; - print STDERR "done.\n"; - close NEWF; + # 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; @@ -244,7 +476,7 @@ sub get_ev_key { sub build_ev { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + my $drvname = "$drivernameprefix$drivertypesuffix"; my @vals = (); @@ -254,6 +486,11 @@ sub build_ev { # 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; @@ -266,6 +503,8 @@ sub build_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, " <enum_val id='$ev_id'>\n", " <ev_longname><en>$ev_longname</en></ev_longname>\n", @@ -277,13 +516,13 @@ sub build_ev { " <driver>$drvname</driver>\n", " </constraint>\n"); - # Build constraints for this particular ev + # 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 enum + # OK, this choice applies to this printer push (@vals, " <constraint sense='true'>\n", " <!-- $fooprn == $stpprn -->\n", @@ -309,7 +548,7 @@ sub build_cons { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + my $drvname = "$drivernameprefix$drivertypesuffix"; my @PNCONS = (); @@ -352,7 +591,7 @@ sub build_cons { push (@PNCONS, " <constraint sense='true'>\n", - " <driver>gimp-print</driver>\n", + " <driver>$drvname</driver>\n", " <printer>$fooname</printer><!-- gimp-print name: $stpname -->\n", " <arg_defval>$foodefval</arg_defval>\n", " </constraint>\n"); @@ -377,10 +616,15 @@ sub optmap_pagesize { chomp; $_ =~ m!^\s*(.+\S)\s+([0-9]+)\s+([0-9]+)\s*$!; my ($name, $width, $height) = ($1, $2, $3); - if ($width >= 0 and $height >= 0) { - $pagemap->{$name} = "$width $height"; + 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; } @@ -390,8 +634,8 @@ sub optmap_pagesize { sub optmap_color { my ($value) = @_; - if (defined $colormap{$value}) { - return $colormap{$value}; + if (defined $colormap->{$drivertype}{$value}) { + return $colormap->{$drivertype}{$value}; } else { die "Cannot map output type '$value'\n"; } @@ -399,15 +643,15 @@ sub optmap_color { sub build_model_cons { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + 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 choices with only one option; they just - # select that option. So we don't bother to make pretty option + # 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() @@ -445,7 +689,7 @@ sub build_model_cons { # See build_model_cons, above. sub build_model_ev { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + my $drvname = "$drivernameprefix$drivertypesuffix"; my @vals = (); @@ -457,8 +701,24 @@ sub build_model_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 = $ev; - + 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, " <enum_val id='$ev_id'>\n", " <ev_longname><en>$ev_longname</en></ev_longname>\n", @@ -507,11 +767,15 @@ sub build_model_ev { # - What are the legal resolutions? Sort of parse and compute these # from the Resolution values. # -# The driverval is "x y", and gets passedin a /HWResolution ps clause +# 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 = (); @@ -524,15 +788,24 @@ sub compute_resolutions { my ($x, $y) = ($1, $3); $y = $x if !defined($y); - my $r = {'x' => $x, - 'y' => $y, - 'driverval' => "$x $y", - 'ev_key' => get_ev_key("res-$x-$y", "gimp-print") - }; + 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", "gimp-print") + $defval = get_ev_key("res-$x-$y", $drvname) if ($qual eq $defaults{$stpname}{'Resolution'}); # Note that this resolution value exists @@ -547,9 +820,6 @@ sub compute_resolutions { $rescache{$stpname}{'list'} = \@reslist; $rescache{$stpname}{'defval'} = $defval; $rescache{$stpname}{'takesit'} = \%hash; - - die "No default gsResolution found for printer $stpname!?\n" - if ! defined($defval); } return $rescache{$stpname}; @@ -564,7 +834,7 @@ sub do_all_res { sub build_resolution_ev { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + my $drvname = "$drivernameprefix$drivertypesuffix"; my @vals = (); @@ -580,7 +850,12 @@ sub build_resolution_ev { 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 = "$x $y"; + my $ev_driverval; + if ($drivertype eq "gs") { + $ev_driverval = "$x $y"; + } else { + $ev_driverval = "${x}x${y}"; + } push (@vals, " <enum_val id='$ev_id'>\n", @@ -633,7 +908,7 @@ sub build_resolution_ev { sub build_resolution_cons { my ($stpopt) = @_; - my $drvname = $generalsubs->{'DRVNAME'}; + my $drvname = "$drivernameprefix$drivertypesuffix"; my @PNCONS = (); @@ -666,6 +941,442 @@ sub build_resolution_cons { " </constraints>\n"); } +sub build_printoutmode_ev { + my ($stpopt) = @_; + my $drvname = "$drivernameprefix$drivertypesuffix"; -exit(0); + my @vals = (); + + # OK, now for each choice ("Draft", "Normal", ...) ... + my $choice; + for $choice (keys %modes) { + # ... and each possible "<ev_driverval>" 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, + " <enum_val id='$ev_id'>\n", + " <ev_longname><en>$ev_longname</en></ev_longname>\n", + " <ev_shortname><en>$ev_shortname</en></ev_shortname>\n", + " <ev_driverval>$ev_driverval</ev_driverval>\n", + " <constraints>\n", + " <!-- Assume the option doesn't apply... -->\n", + " <constraint sense='false'>\n", + " <driver>$drvname</driver>\n", + " </constraint>\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, + " <constraint sense='true'>\n", + " <!-- $fooprn == $stpprn -->\n", + " <driver>$drvname</driver>\n", + " <printer>$fooprn</printer>\n", + " </constraint>\n"); + } + } + } + + push (@vals, + " </constraints>\n", + " </enum_val>\n"); + } + } + + return join('', + "<enum_vals>\n", + @vals, + " </enum_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, + " <constraint sense='true'>\n", + " <driver>$drvname</driver>\n", + " <printer>$fooname</printer>\n", + " <arg_defval>$foodefval</arg_defval>\n", + " </constraint>\n"); + } + } + + return join('', + "<constraints>\n", + @PNCONS, + " </constraints>\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); |