#!@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 = (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 = { 'Model' => { 'OPTCONSTRAINTS' => \&build_model_cons, 'ENUMVALS' => \&build_model_ev }, 'RenderResolution' => { '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; $colormap = { 'ijs' => { 'Grayscale' => 'DeviceGray', 'Color' => 'DeviceRGB', 'BlackAndWhite' => 'DeviceGray -dBitsPerSample=1', 'RawCMYK' => 'DeviceCMYK' } }; my $groupname_prefix = "Gimp-Print"; my @parameter_class_names = ( "Printer Features", "Output Control" ); my @parameter_level_names = ( "Common", "Extra 1", "Extra 2", "Extra 3", "Extra 4", "Extra 5" ); use Data::Dumper; open PIPE, "./printer_options|" or die "Cannot run printer_options: $!\n"; print STDERR "Loading options from ./printer_options..."; while() { #print $_; 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('', ); #print $code; close PIPE or die "Cannot run printer_margins: $!\n"; eval $code or die "Cannot run printer_margins: $!\n"; print STDERR "done.\n"; } open PIPE, "./printers|" or die "Cannot run printers: $!\n"; print STDERR "Loading options from ./printers..."; while() { #print $_; 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, $b, $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}]); } } } } #print Dumper(%ev_choices); 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}"; } } } } # Make list of needed Foomatic entries for the numerical options. If # for one and the same numerical option there are printers with # different value ranges, there must be made an extra Foomatic entry # for each value range. Therefore the filenames of numerical options # are numbered (eg. Contrast-1.xml). for $a (keys(%stp_float_values)) { for $vtmp (keys %{$stp_float_values{$a}}) { for $otmp (keys %{$stp_float_values{$a}{$vtmp}}) { my $min = $stp_float_values{$a}{'MINVAL'}{$otmp}; my $max = $stp_float_values{$a}{'MAXVAL'}{$otmp}; my $def = $stp_float_values{$a}{'DEFVAL'}{$otmp}; # Skip options with invalid values, the library contains such # options in the case when only one constant value is allowed next if (($min >= $max) || ($def < $min) || ($def > $max)); my $minmax = "${min}_${max}"; if (!$seen_fnumopt{$otmp}{$minmax}++) { if (!defined($fnums{$otmp})) { $fnums{$otmp} = 0; } $fnums{$otmp} ++; push (@floatnumopts_list, "${otmp}-$fnums{$otmp}"); $numopt_ranges{"${otmp}-$fnums{$otmp}"}{'MINVAL'} = $min; $numopt_ranges{"${otmp}-$fnums{$otmp}"}{'MAXVAL'} = $max; } } } } for $a (keys(%stp_int_values)) { for $vtmp (keys %{$stp_int_values{$a}}) { for $otmp (keys %{$stp_int_values{$a}{$vtmp}}) { my $min = $stp_int_values{$a}{'MINVAL'}{$otmp}; my $max = $stp_int_values{$a}{'MAXVAL'}{$otmp}; my $def = $stp_int_values{$a}{'DEFVAL'}{$otmp}; # Skip options with invalid values, the library contains such # options in the case when only one constant value is allowed next if (($min >= $max) || ($def < $min) || ($def > $max)); my $minmax = "${min}_${max}"; if (!$seen_inumopt{$otmp}{$minmax}++) { if (!defined($inums{$otmp})) { $inums{$otmp} = 0; } $inums{$otmp} ++; push (@intnumopts_list, "${otmp}-$inums{$otmp}"); $numopt_ranges{"${otmp}-$inums{$otmp}"}{'MINVAL'} = $min; $numopt_ranges{"${otmp}-$inums{$otmp}"}{'MAXVAL'} = $max; } } } } for $a (keys(%stp_dimension_values)) { for $vtmp (keys %{$stp_dimension_values{$a}}) { for $otmp (keys %{$stp_dimension_values{$a}{$vtmp}}) { my $min = $stp_dimension_values{$a}{'MINVAL'}{$otmp}; my $max = $stp_dimension_values{$a}{'MAXVAL'}{$otmp}; my $def = $stp_dimension_values{$a}{'DEFVAL'}{$otmp}; # Skip options with invalid values, the library contains such # options in the case when only one constant value is allowed next if (($min >= $max) || ($def < $min) || ($def > $max)); my $minmax = "${min}_${max}"; if (!$seen_inumopt{$otmp}{$minmax}++) { if (!defined($inums{$otmp})) { $inums{$otmp} = 0; } $inums{$otmp} ++; push (@dimensionnumopts_list, "${otmp}-$inums{$otmp}"); $numopt_ranges{"${otmp}-$inums{$otmp}"}{'MINVAL'} = $min; $numopt_ranges{"${otmp}-$inums{$otmp}"}{'MAXVAL'} = $max; } } } } #print join("\n", @floatnumopts_list); #print join("\n", @intnumopts_list); #print join("\n", @dimensionnumopts_list); # 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 Foomatic 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', 'PrintoutMode' => 'General', 'RenderResolution' => 'General', 'Quality' => 'General', 'Color' => 'General', 'ImageType' => 'General'}; my @numericsubs = ('MINVAL', 'MAXVAL'); my $specialoutputfilenames = { 'Resolution' => 'PrinterResolution', 'RenderResolution' => 'Resolution' }; # 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'; my $order = 1000; # opendir TDIR, "$templatedir-$drivertype" or # die "Cannot open templates directory: $!\n"; for $fooopt (sort (keys(%ev_choices), @floatnumopts_list, @dimensionnumopts_list, @intnumopts_list), "PrintoutMode", "Model", "RenderResolution", "gimp-print") { # The "PrintoutMode" option is only supported by Foomatic 2.9.x or # newer (preliminary skipped always, do not remove the # infrastructure for "PrintoutMode", it will be re-activated later # on) next if ((!$foomatic3) && ($fooopt eq "PrintoutMode")); # "x_resolution" and "y_resolution" appear in %ev_choices but are # not option names, so skip them next if $fooopt =~ /^[xy]_resolution$/; my ($num_opt, $type, $tmpl); if (member($fooopt, @floatnumopts_list)) { $num_opt = 1; $type = "float"; $tmpl = "NumericalOptions.xml"; } elsif (member($fooopt, @intnumopts_list)) { $num_opt = 1; $type = "int"; $tmpl = "NumericalOptions.xml"; } elsif (member($fooopt, @dimensionnumopts_list)) { $num_opt = 1; $type = "dimension"; $tmpl = "NumericalOptions.xml"; } else { $num_opt = 0; $type = "enum"; $tmpl = "${fooopt}.xml"; $tmpl = "OtherOptions.xml" if ! -r "$templatedir-$drivertype/$tmpl"; } # Remove number appended to the end of the file name of # numerical options my $shortname = $fooopt; $shortname =~ s!-\d+$!!; #my $stpopt = $argnamemap{$shortname}; #$stpopt = $shortname if ! defined ($stpopt); my $stpopt = $shortname; # print STDERR "Argnamemap '$fooopt' => '$stpopt'\n"; open TMPL, "$templatedir-$drivertype/$tmpl"; my @datafile = ; close TMPL; print STDERR "Processing \"$fooopt\"..."; 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 $group; if (defined($optiongroups->{$shortname})) { # Group names given by table (esp. "General" for special # Options) $group = $optiongroups->{$shortname}; } elsif (defined($param_classes{$shortname}) && defined($param_levels{$shortname}) && $parameter_class_names[$param_classes{$shortname}] && $parameter_level_names[$param_levels{$shortname}]) { # Group names given by libgimpprint $group = $groupname_prefix . " " . $parameter_class_names[$param_classes{$shortname}] . " " . $parameter_level_names[$param_levels{$shortname}]; # Remove the spaces (the name with spaces Foomatic will # generate automatically) $group =~ s! !!g; } else { # All the above did not assign a group name? Use # "Miscellaneous" (Should usually not happen) $group = "Miscellaneous"; } my $substitution = "\n " . $group . ""; $template =~ s!\@\@GROUP\@\@!$substitution!g; } else { $template =~ s!\@\@GROUP\@\@!!g; } # Now do the numeric substitutions $template =~ s!\@\@TYPE\@\@!$type!g; for $substr (@numericsubs) { my $substitution; my $substitution = $numopt_ranges{$fooopt}{$substr}; $template =~ s!\@\@$substr\@\@!$substitution!g; } # Substitutions for generic template files my $lowercaseshortname = lc($fooopt); if ($tmpl !~ /^$fooopt/) { $template =~ s!\@\@LOWERCASESHORTNAME\@\@!$lowercaseshortname!g; $template =~ s!\@\@LONGNAME\@\@!$longnames{$shortname}!g; $template =~ s!\@\@SHORTNAME\@\@!$shortname!g; $template =~ s!\@\@ORDER\@\@!$order!g; #$order += 10; $template =~ s!\@\@SPOT\@\@!B!g; $template =~ s!\@\@PROTO\@\@!$stpopt=\%s,!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; } } if ($template =~ m!\@\@OPTCONSTRAINTS\@\@!) { my $substitution = ($num_opt ? build_num_cons($fooopt) : build_cons($stpopt)); # Skip this option if there are no constraints (no printers # using this option) next if $substitution !~ m!!s; if (defined($substitution)) { $template =~ s!\@\@OPTCONSTRAINTS\@\@!$substitution!g; } } if ($template =~ m!\@\@ENUMVALS\@\@!) { my $substitution = build_ev($stpopt); # Skip this option if there are no choices (an enum option # without choices does not make sense) next if $substitution !~ m!!s; if (defined($substitution)) { $template =~ s!\@\@ENUMVALS\@\@!$substitution!g; } } # Any more? grep (m!\@\@([^\@]+)\@\@!g && do { warn " Unknown substitution $1 in $fooopt!\n"; }, split("\n",$template)); # File name for the option XML file $tmpl = "${fooopt}.xml" if $tmpl !~ /^$fooopt\.xml$/; if (my $f = $specialoutputfilenames->{$fooopt}) { $tmpl = "${f}.xml"; } # 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; } # member( $a, @b ) returns 1 if $a is in @b, 0 otherwise. sub member { my $e = shift; foreach (@_) { $e eq $_ and return 1 } 0 }; 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]; 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 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 build_num_cons { my ($foooptfile) = @_; my $drvname = "$drivernameprefix$drivertypesuffix"; my @PNCONS = (); # Do we have a float or an int option? my $type; if (member($foooptfile, @floatnumoptslist)) { $type = "float"; } elsif (member($foooptfile, @dimensionnumoptslist)) { $type = "dimension"; } else { $type = "int"; } # Name of the actual option my $stpopt = $foooptfile; $stpopt =~ s!-\d+$!!; # 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}; } # Add this printer to argument constraints? The printer must provide # this option and a default value for it. my $stpdef; if ((defined($stpdef = $stp_float_values{$stpname}{"DEFVAL"}{$stpopt})) || (defined($stpdef = $stp_int_values{$stpname}{"DEFVAL"}{$stpopt})) || (defined($stpdef = $stp_dimension_values{$stpname}{"DEFVAL"}{$stpopt}))) { # Find minimum and maximum my ($min, $max); if ($type eq "float") { $min = $stp_float_values{$stpname}{"MINVAL"}{$stpopt}; $max = $stp_float_values{$stpname}{"MAXVAL"}{$stpopt}; } elsif ($type eq "dimension") { $min = $stp_dimension_values{$stpname}{"MINVAL"}{$stpopt}; $max = $stp_dimension_values{$stpname}{"MAXVAL"}{$stpopt}; } else { $min = $stp_int_values{$stpname}{"MINVAL"}{$stpopt}; $max = $stp_int_values{$stpname}{"MAXVAL"}{$stpopt}; } # Does the range of this option with this printer match # the Foomatic option entry we are building currently? if (defined($numopt_ranges{$foooptfile}{'MINVAL'}) && defined($numopt_ranges{$foooptfile}{'MAXVAL'}) && ($min == $numopt_ranges{$foooptfile}{'MINVAL'}) && ($max == $numopt_ranges{$foooptfile}{'MAXVAL'})) { if (0) { print STDERR " Default for $stpname/$stpopt is $stpdef\n"; } my $fooname; for $fooname (@{$mapstp{$stpname}}) { if (0) { print STDERR " Printer $fooname takes option $stpopt.\n"; } push (@PNCONS, " \n", " $drvname\n", " $fooname\n", " $stpdef\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")) { $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 $make = $printer_make{$ev}; my $ev_shortname = get_ev_shortname($ev); my $ev_id = get_ev_key($ev, $drvname); my $ev_driverval; $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. 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'}})) { my ($x) = $stpdata{$stpname}{'x_resolution'}{$qual}; my ($y) = $stpdata{$stpname}{'y_resolution'}{$qual}; my $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 = "${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 = ( # HP "mono", # General "", "dpi", # Epson/Lexmark "mw", "mw2", "sw", "fol", "fol2", "fourp", "uni", "mwuni", "mw2uni", "swuni", "foluni", "fol2uni", "fourpuni", "hq", "hquni", "hq2", "hq2uni", # Canon "dmt", ); 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}; } # Unknown qualities 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 ($normalminres, $normalbestsymmetry, $normaluni, $normallowestqualstr) = (99999999, 99999999, 0, "xxx"); 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 { $xres = $stpdata{$stpprn}{'x_resolution'}; $yres = $stpdata{$stpprn}{'y_resolution'}; $qualstr = $quality; } # 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. # ImageType Text my $qualitysetting = (defined($stpdata{$stpprn}{'Quality'}) ? (defined($stpdata{$stpprn}{'Quality'}{'Draft'}) ? 'Draft' : (defined($stpdata{$stpprn}{'Quality'}{'Economy'}) ? 'Economy' : (defined($stpdata{$stpprn}{'Quality'}{'FastEconomy'}) ? 'FastEconomy' : (defined($stpdata{$stpprn}{'Quality'}{'Standard'}) ? 'Standard' : 'ERROR' )))) : ''); die ("\n\n'Quality' option without 'Draft', 'Economy', " . "'FastEconomy', and 'Standard' choices for the '$stpprn' " . "device class!\n") if $qualitysetting eq 'ERROR'; my $imagesetting = (defined($stpdata{$stpprn}{'ImageType'}) ? (defined($stpdata{$stpprn}{'ImageType'}{'Text'}) ? 'Text' : (defined($stpdata{$stpprn}{'ImageType'}{'TextGraphics'}) ? 'TextGraphics' : (defined($stpdata{$stpprn}{'ImageType'}{'LineArt'}) ? 'LineArt' : (defined($stpdata{$stpprn}{'ImageType'}{'Graphics'}) ? 'Graphics' : 'ERROR' )))) : ''); die ("\n\n'ImageType' option without 'Text', 'TextGraphics', " . "'LineArt', and 'Graphics' choices for the '$stpprn' " . "device class!\n") if $imagesetting eq 'ERROR'; if (($respersquareinch < $draftminres) || (($respersquareinch == $draftminres) && ($symmetry < $draftbestsymmetry)) || (($respersquareinch == $draftminres) && ($symmetry == $draftbestsymmetry) && (qualityorder($qualstr, $draftlowestqualstr) < 0))) { unless (($xres < 150) && # Resolution not lower than ($yres < 150)) { # 150x150, 360x120 allowed $draftbestsymmetry = $symmetry; $draftminres = $respersquareinch; $draftlowestqualstr = $qualstr; $modeinfo->{'Draft'} = { 'quality' => $qualitysetting, 'image' => $imagesetting, 'xres' => $xres, 'yres' => $yres } } } ### Mode: NORMAL # Lowest resolution which is at least 300x300 dpi (600x600 dpi # for Lexmark Z..), low quality level, unidirectional if # possible, # ImageType TextGraphics $qualitysetting = (defined($stpdata{$stpprn}{'Quality'}) ? (defined($stpdata{$stpprn}{'Quality'}{'Standard'}) ? 'Standard' : (defined($stpdata{$stpprn}{'Quality'}{'High'}) ? 'High' : (defined($stpdata{$stpprn}{'Quality'}{'Draft'}) ? 'Draft' : 'ERROR' ))) : ''); die ("\n\n'Quality' option without 'Draft', 'Standard', and " . "'High' choices for the '$stpprn' device class!\n") if $qualitysetting eq 'ERROR'; $imagesetting = (defined($stpdata{$stpprn}{'ImageType'}) ? (defined($stpdata{$stpprn}{'ImageType'}{'TextGraphics'}) ? 'TextGraphics' : (defined($stpdata{$stpprn}{'ImageType'}{'Graphics'}) ? 'Graphics' : (defined($stpdata{$stpprn}{'ImageType'}{'LineArt'}) ? 'LineArt' : (defined($stpdata{$stpprn}{'ImageType'}{'Photo'}) ? 'Photo' : 'ERROR' )))) : ''); die ("\n\n'ImageType' option without 'TextGraphics', 'Graphics', " . "'LineArt', and 'Photo' choices for the '$stpprn' " . "device class!\n") if $imagesetting eq 'ERROR'; if (($respersquareinch < $normalminres) || (($respersquareinch == $normalminres) && ($symmetry < $normalbestsymmetry)) || (($respersquareinch == $normalminres) && ($symmetry == $normalbestsymmetry) && (($qualstr =~ /uni/) > $normaluni)) || (($respersquareinch == $normalminres) && ($symmetry == $normalbestsymmetry) && (($qualstr =~ /uni/) == $normaluni) && (qualityorder($qualstr, $normallowestqualstr) < 0))) { unless ((($xres < 300) || # Resolution not lower than ($yres < 300)) || # 300x300, (600x600 on Lexmark) (($stpprn =~ /^lexmark\-z/) && (($xres < 600) || ($yres < 600)))) { $normalbestsymmetry = $symmetry; $normalminres = $respersquareinch; $normaluni = ($qualstr =~ /uni/); $normallowestqualstr = $qualstr; $modeinfo->{'Normal'} = { 'quality' => $qualitysetting, 'image' => $imagesetting, 'xres' => $xres, 'yres' => $yres } } } ### 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" # ImageType TextGraphics $qualitysetting = (defined($stpdata{$stpprn}{'Quality'}) ? (defined($stpdata{$stpprn}{'Quality'}{'High'}) ? 'High' : (defined($stpdata{$stpprn}{'Quality'}{'Best'}) ? 'Best' : (defined($stpdata{$stpprn}{'Quality'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'Quality'}{'Standard'}) ? 'Standard' : 'ERROR' )))) : ''); die ("\n\n'Quality' option without 'High', 'Best', " . "'Photo', and 'Standard' choices for the '$stpprn' " . "device class!\n") if $qualitysetting eq 'ERROR'; $imagesetting = (defined($stpdata{$stpprn}{'ImageType'}) ? (defined($stpdata{$stpprn}{'ImageType'}{'TextGraphics'}) ? 'TextGraphics' : (defined($stpdata{$stpprn}{'ImageType'}{'Graphics'}) ? 'Graphics' : (defined($stpdata{$stpprn}{'ImageType'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'ImageType'}{'LineArt'}) ? 'LineArt' : 'ERROR' )))) : ''); die ("\n\n'ImageType' option without 'TextGraphics', 'Graphics', " . "'LineArt', and 'Photo' choices for the '$stpprn' " . "device class!\n") if $imagesetting eq 'ERROR'; 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' => $qualitysetting, 'image' => $imagesetting, 'xres' => $xres, 'yres' => $yres } } } ### Mode: VERY HIGH # Use always the highest available resolution/quality, # preferrably symmetric resolutions, # On Epsons: Maximum 1440x720, not "hq2". # ImageType TextGraphics $qualitysetting = (defined($stpdata{$stpprn}{'Quality'}) ? (defined($stpdata{$stpprn}{'Quality'}{'Best'}) ? 'Best' : (defined($stpdata{$stpprn}{'Quality'}{'High'}) ? 'High' : (defined($stpdata{$stpprn}{'Quality'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'Quality'}{'Standard'}) ? 'Standard' : 'ERROR' )))) : ''); die ("\n\n'Quality' option without 'High', 'Best', " . "'Photo', and 'Standard' choices for the '$stpprn' " . "device class!\n") if $qualitysetting eq 'ERROR'; $imagesetting = (defined($stpdata{$stpprn}{'ImageType'}) ? (defined($stpdata{$stpprn}{'ImageType'}{'TextGraphics'}) ? 'TextGraphics' : (defined($stpdata{$stpprn}{'ImageType'}{'Graphics'}) ? 'Graphics' : (defined($stpdata{$stpprn}{'ImageType'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'ImageType'}{'LineArt'}) ? 'LineArt' : 'ERROR' )))) : ''); die ("\n\n'ImageType' option without 'TextGraphics', 'Graphics', " . "'LineArt', and 'Photo' choices for the '$stpprn' " . "device class!\n") if $imagesetting eq 'ERROR'; 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' => $qualitysetting, 'image' => $imagesetting, 'xres' => $xres, 'yres' => $yres } } } ### Mode: PHOTO # High: The highest resolution which is not higher than # 720x720 dpi (Lexmark Z..: 1200x1200 dpi), # unidirectional if possible, # ImageType Photographs $qualitysetting = (defined($stpdata{$stpprn}{'Quality'}) ? (defined($stpdata{$stpprn}{'Quality'}{'HighPhoto'}) ? 'HighPhoto' : (defined($stpdata{$stpprn}{'Quality'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'Quality'}{'UltraPhoto'}) ? 'UltraPhoto' : (defined($stpdata{$stpprn}{'Quality'}{'Best'}) ? 'Best' : (defined($stpdata{$stpprn}{'Quality'}{'High'}) ? 'High' : (defined($stpdata{$stpprn}{'Quality'}{'Standard'}) ? 'Standard' : 'ERROR' )))))) : ''); die ("\n\n'Quality' option without 'HighPhoto', 'Photo', " . "'UltraPhoto', 'Best', 'High', and 'Standard' choices " . "for the '$stpprn' device class!\n") if $qualitysetting eq 'ERROR'; $imagesetting = (defined($stpdata{$stpprn}{'ImageType'}) ? (defined($stpdata{$stpprn}{'ImageType'}{'Photo'}) ? 'Photo' : (defined($stpdata{$stpprn}{'ImageType'}{'Graphics'}) ? 'Graphics' : (defined($stpdata{$stpprn}{'ImageType'}{'TextGraphics'}) ? 'TextGraphics' : (defined($stpdata{$stpprn}{'ImageType'}{'LineArt'}) ? 'LineArt' : 'ERROR' )))) : ''); die ("\n\n'ImageType' option without 'TextGraphics', 'Graphics', " . "'LineArt', and 'Photo' choices for the '$stpprn' " . "device class!\n") if $imagesetting eq 'ERROR'; if (($respersquareinch > $photomaxres) || (($respersquareinch == $photomaxres) && ($symmetry < $photobestsymmetry)) || (($respersquareinch == $photomaxres) && ($symmetry == $photobestsymmetry) && (qualityorder($qualstr, $photobestqualstr) > 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 =~ /^(hq2)$/)) { # Not "hq2" $photobestsymmetry = $symmetry; $photomaxres = $respersquareinch; $photobestqualstr = $qualstr; $modeinfo->{'Photo'} = { 'quality' => $qualitysetting, 'image' => $imagesetting, 'xres' => $xres, 'yres' => $yres } } } } # 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 = (defined($stpdata{$stpprn}{'ImageType'}) ? "ImageType=$modeinfo->{$m}{'image'} " : "") . (defined($stpdata{$stpprn}{'Quality'}) ? "Quality=$modeinfo->{$m}{'quality'} " : "") . "Resolution=$modeinfo->{$m}{'xres'}x" . "$modeinfo->{$m}{'yres'}dpi"; if (defined($stpdata{$stpprn}{'Color'}{'Color'})) { # Color printer $modes->{$stpprn}{$m} = $modestr . " OutputType=Color"; if (defined($stpdata{$stpprn}{'Color'}{'Grayscale'})) { $modes->{$stpprn}{"$m.Gray"} = $modestr . " OutputType=Grayscale"; } elsif (defined($stpdata{$stpprn}{'Color'}{'BlackAndWhite'})) { $modes->{$stpprn}{"$m.Gray"} = $modestr . " OutputType=BlackAndWhite"; } # 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);