libgimpprint API Reference: src/main/print-escp2.c Source File

Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

# src/main/print-escp2.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: print-escp2_8c-source.html,v 1.1.1.2 2004/12/22 23:49:07 jlovell Exp $"
    00003  *
    00004  *   Print plug-in EPSON ESC/P2 driver for the GIMP.
    00005  *
    00006  *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
    00007  *      Robert Krawitz (rlk@alum.mit.edu)
    00008  *
    00009  *   This program is free software; you can redistribute it and/or modify it
    00010  *   under the terms of the GNU General Public License as published by the Free
    00011  *   Software Foundation; either version 2 of the License, or (at your option)
    00012  *   any later version.
    00013  *
    00014  *   This program is distributed in the hope that it will be useful, but
    00015  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    00016  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    00017  *   for more details.
    00018  *
    00019  *   You should have received a copy of the GNU General Public License
    00020  *   along with this program; if not, write to the Free Software
    00021  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    00022  */
    00023
    00024 /*
    00025  * This file must include only standard C header files.  The core code must
    00026  * compile on generic platforms that don't support glib, gimp, gtk, etc.
    00027  */
    00028
    00029 #ifdef HAVE_CONFIG_H
    00030 #include <config.h>
    00031 #endif
    00032 #include <gimp-print/gimp-print.h>
    00033 #include <gimp-print/gimp-print-intl-internal.h>
    00034 #include "gimp-print-internal.h"
    00035 #include <string.h>
    00036 #include <assert.h>
    00037 #include <math.h>
    00038 #include "print-escp2.h"
    00039
    00040 #ifdef __GNUC__
    00041 #define inline __inline__
    00042 #endif
    00043
    00044 #define OP_JOB_START 1
    00045 #define OP_JOB_PRINT 2
    00046 #define OP_JOB_END   4
    00047
    00048 #define MAX(a, b) ((a) > (b) ? (a) : (b))
    00049
    00050 typedef struct
    00051 {
    00052   const char *attr_name;
    00053   short bit_shift;
    00054   short bit_width;
    00055 } escp2_printer_attr_t;
    00056
    00057 static const escp2_printer_attr_t escp2_printer_attrs[] =
    00058 {
    00059   { "command_mode",             0, 4 },
    00060   { "horizontal_zero_margin",   4, 1 },
    00061   { "rollfeed",                 5, 1 },
    00062   { "variable_mode",            6, 1 },
    00063   { "graymode",                 7, 1 },
    00064   { "vacuum",                   8, 1 },
    00065   { "fast_360",                 9, 1 },
    00066   { "send_zero_advance",       10, 1 },
    00067   { "supports_ink_change",     11, 1 },
    00068   { "packet_mode",             12, 1 },
    00069   { "print_to_cd",             13, 1 },
    00070 };
    00071
    00072 typedef struct
    00073 {
    00074   unsigned count;
    00075   const char *name;
    00076 } channel_count_t;
    00077
    00078 static const channel_count_t escp2_channel_counts[] =
    00079 {
    00080   { 1,  "1" },
    00081   { 2,  "2" },
    00082   { 3,  "3" },
    00083   { 4,  "4" },
    00084   { 5,  "5" },
    00085   { 6,  "6" },
    00086   { 7,  "7" },
    00087   { 8,  "8" },
    00088   { 9,  "9" },
    00089   { 10, "10" },
    00090   { 11, "11" },
    00091   { 12, "12" },
    00092   { 13, "13" },
    00093   { 14, "14" },
    00094   { 15, "15" },
    00095   { 16, "16" },
    00096   { 17, "17" },
    00097   { 18, "18" },
    00098   { 19, "19" },
    00099   { 20, "20" },
    00100   { 21, "21" },
    00101   { 22, "22" },
    00102   { 23, "23" },
    00103   { 24, "24" },
    00104   { 25, "25" },
    00105   { 26, "26" },
    00106   { 27, "27" },
    00107   { 28, "28" },
    00108   { 29, "29" },
    00109   { 30, "30" },
    00110   { 31, "31" },
    00111   { 32, "32" },
    00112 };
    00113
    00114 static int escp2_channel_counts_count =
    00115 sizeof(escp2_channel_counts) / sizeof(channel_count_t);
    00116
    00117 static const double ink_darknesses[] =
    00118 {
    00119   1.0, 0.31 / .4, 0.61 / .96, 0.08, 0.31 * 0.33 / .4, 0.61 * 0.33 / .96, 0.33, 1.0
    00120 };
    00121
    00122 #define INCH(x)         (72 * x)
    00123
    00124 static const res_t *escp2_find_resolution(const stp_vars_t *v);
    00125
    00126 #define PARAMETER_INT(s)                                                \
    00127 {                                                                       \
    00128   "escp2_" #s, "escp2_" #s, N_("Advanced Printer Functionality"), NULL, \
    00129   STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,                  \
    00130   STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 0                          \
    00131 }
    00132
    00133 #define PARAMETER_INT_RO(s)                                             \
    00134 {                                                                       \
    00135   "escp2_" #s, "escp2_" #s, N_("Advanced Printer Functionality"), NULL, \
    00136   STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,                  \
    00137   STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 1                          \
    00138 }
    00139
    00140 #define PARAMETER_RAW(s)                                                \
    00141 {                                                                       \
    00142   "escp2_" #s, "escp2_" #s, N_("Advanced Printer Functionality"), NULL, \
    00143   STP_PARAMETER_TYPE_RAW, STP_PARAMETER_CLASS_FEATURE,                  \
    00144   STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 0                          \
    00145 }
    00146
    00147 typedef struct
    00148 {
    00149   const stp_parameter_t param;
    00150   double min;
    00151   double max;
    00152   double defval;
    00153   int color_only;
    00154 } float_param_t;
    00155
    00156 static const stp_parameter_t the_parameters[] =
    00157 {
    00158 #if 0
    00159   {
    00160     "AutoMode", N_("Automatic Printing Mode"), N_("Basic Output Adjustment"),
    00161     N_("Automatic printing mode"),
    00162     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00163     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00164   },
    00165 #endif
    00166   /*
    00167    * Don't check this parameter.  We may offer different settings for
    00168    * different papers, but we need to be able to handle settings from PPD
    00169    * files that don't have constraints set up.
    00170    */
    00171   {
    00172     "Quality", N_("Print Quality"), N_("Basic Output Adjustment"),
    00173     N_("Print Quality"),
    00174     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00175     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 0, 0
    00176   },
    00177   {
    00178     "PageSize", N_("Page Size"), N_("Basic Printer Setup"),
    00179     N_("Size of the paper being printed to"),
    00180     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
    00181     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00182   },
    00183   {
    00184     "MediaType", N_("Media Type"), N_("Basic Printer Setup"),
    00185     N_("Type of media (plain paper, photo paper, etc.)"),
    00186     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00187     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00188   },
    00189   {
    00190     "InputSlot", N_("Media Source"), N_("Basic Printer Setup"),
    00191     N_("Source (input slot) of the media"),
    00192     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00193     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00194   },
    00195   {
    00196     "CDInnerRadius", N_("CD Hub Size"), N_("Basic Printer Setup"),
    00197     N_("Print only outside of the hub of the CD, or all the way to the hole"),
    00198     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00199     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00200   },
    00201   {
    00202     "CDXAdjustment", N_("CD Horizontal Fine Adjustment"), N_("Advanced Printer Setup"),
    00203     N_("Fine adjustment to horizontal position for CD printing"),
    00204     STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
    00205     STP_PARAMETER_LEVEL_ADVANCED, 1, 1, -1, 1, 0
    00206   },
    00207   {
    00208     "CDYAdjustment", N_("CD Vertical Fine Adjustment"), N_("Advanced Printer Setup"),
    00209     N_("Fine adjustment to horizontal position for CD printing"),
    00210     STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
    00211     STP_PARAMETER_LEVEL_ADVANCED, 1, 1, -1, 1, 0
    00212   },
    00213   {
    00214     "Resolution", N_("Resolution"), N_("Basic Printer Setup"),
    00215     N_("Resolution of the print"),
    00216     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00217     STP_PARAMETER_LEVEL_ADVANCED, 1, 1, -1, 1, 0
    00218   },
    00219   /*
    00220    * Don't check this parameter.  We may offer different settings for
    00221    * different ink sets, but we need to be able to handle settings from PPD
    00222    * files that don't have constraints set up.
    00223    */
    00224   {
    00225     "InkType", N_("Ink Type"), N_("Advanced Printer Setup"),
    00226     N_("Type of ink in the printer"),
    00227     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00228     STP_PARAMETER_LEVEL_ADVANCED2, 1, 1, -1, 0, 0
    00229   },
    00230   {
    00231     "InkSet", N_("Ink Set"), N_("Advanced Printer Setup"),
    00232     N_("Type of ink in the printer"),
    00233     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00234     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00235   },
    00236   {
    00237     "PrintingDirection", N_("Printing Direction"), N_("Advanced Output Adjustment"),
    00238     N_("Printing direction (unidirectional is higher quality, but slower)"),
    00239     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00240     STP_PARAMETER_LEVEL_ADVANCED1, 1, 1, -1, 1, 0
    00241   },
    00242   {
    00243     "FullBleed", N_("Borderless"), N_("Basic Printer Setup"),
    00244     N_("Print without borders"),
    00245     STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE,
    00246     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00247   },
    00248   {
    00249     "Weave", N_("Interleave Method"), N_("Advanced Output Adjustment"),
    00250     N_("Interleave pattern to use"),
    00251     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00252     STP_PARAMETER_LEVEL_ADVANCED1, 1, 1, -1, 1, 0
    00253   },
    00254   {
    00255     "AdjustDotsize", N_("Adjust dot size as necessary"), N_("Advanced Printer Setup"),
    00256     N_("Adjust dot size as necessary to achieve desired density"),
    00257     STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE,
    00258     STP_PARAMETER_LEVEL_ADVANCED4, 1, 1, -1, 1, 0
    00259   },
    00260   {
    00261     "OutputOrder", N_("Output Order"), N_("Basic Printer Setup"),
    00262     N_("Output Order"),
    00263     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
    00264     STP_PARAMETER_LEVEL_BASIC, 0, 0, -1, 0, 0
    00265   },
    00266   {
    00267     "AlignmentPasses", N_("Alignment Passes"), N_("Advanced Printer Functionality"),
    00268     N_("Alignment Passes"),
    00269     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00270     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00271   },
    00272   {
    00273     "AlignmentChoices", N_("Alignment Choices"), N_("Advanced Printer Functionality"),
    00274     N_("Alignment Choices"),
    00275     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00276     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00277   },
    00278   {
    00279     "InkChange", N_("Ink change command"), N_("Advanced Printer Functionality"),
    00280     N_("Ink change command"),
    00281     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00282     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00283   },
    00284   {
    00285     "AlternateAlignmentPasses", N_("Alternate Alignment Passes"), N_("Advanced Printer Functionality"),
    00286     N_("Alternate Alignment Passes"),
    00287     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00288     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00289   },
    00290   {
    00291     "AlternateAlignmentChoices", N_("Alternate Alignment Choices"), N_("Advanced Printer Functionality"),
    00292     N_("Alternate Alignment Choices"),
    00293     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00294     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00295   },
    00296   {
    00297     "SupportsPacketMode", N_("Supports Packet Mode"), N_("Advanced Printer Functionality"),
    00298     N_("Alternate Alignment Choices"),
    00299     STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE,
    00300     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00301   },
    00302   {
    00303     "InkChannels", N_("Ink Channels"), N_("Advanced Printer Functionality"),
    00304     N_("Ink Channels"),
    00305     STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
    00306     STP_PARAMETER_LEVEL_INTERNAL, 0, 0, -1, 0, 0
    00307   },
    00308   {
    00309     "PrintingMode", N_("Printing Mode"), N_("Core Parameter"),
    00310     N_("Printing Output Mode"),
    00311     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
    00312     STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
    00313   },
    00314   {
    00315     "RawChannels", N_("Raw Channels"), N_("Core Parameter"),
    00316     N_("Raw Channel Count"),
    00317     STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
    00318     STP_PARAMETER_LEVEL_BASIC, 0, 1, -1, 1, 0
    00319   },
    00320   PARAMETER_INT(max_hres),
    00321   PARAMETER_INT(max_vres),
    00322   PARAMETER_INT(min_hres),
    00323   PARAMETER_INT(min_vres),
    00324   PARAMETER_INT(nozzles),
    00325   PARAMETER_INT(black_nozzles),
    00326   PARAMETER_INT(fast_nozzles),
    00327   PARAMETER_INT(min_nozzles),
    00328   PARAMETER_INT(min_black_nozzles),
    00329   PARAMETER_INT(min_fast_nozzles),
    00330   PARAMETER_INT(nozzle_separation),
    00331   PARAMETER_INT(black_nozzle_separation),
    00332   PARAMETER_INT(fast_nozzle_separation),
    00333   PARAMETER_INT(separation_rows),
    00334   PARAMETER_INT(max_paper_width),
    00335   PARAMETER_INT(max_paper_height),
    00336   PARAMETER_INT(min_paper_width),
    00337   PARAMETER_INT(min_paper_height),
    00338   PARAMETER_INT(extra_feed),
    00339   PARAMETER_INT(pseudo_separation_rows),
    00340   PARAMETER_INT(base_separation),
    00341   PARAMETER_INT(resolution_scale),
    00342   PARAMETER_INT(initial_vertical_offset),
    00343   PARAMETER_INT(black_initial_vertical_offset),
    00344   PARAMETER_INT(max_black_resolution),
    00345   PARAMETER_INT(zero_margin_offset),
    00346   PARAMETER_INT(extra_720dpi_separation),
    00347   PARAMETER_INT(physical_channels),
    00348   PARAMETER_INT(left_margin),
    00349   PARAMETER_INT(right_margin),
    00350   PARAMETER_INT(top_margin),
    00351   PARAMETER_INT(bottom_margin),
    00352   PARAMETER_INT_RO(alignment_passes),
    00353   PARAMETER_INT_RO(alignment_choices),
    00354   PARAMETER_INT_RO(alternate_alignment_passes),
    00355   PARAMETER_INT_RO(alternate_alignment_choices),
    00356   PARAMETER_INT(cd_x_offset),
    00357   PARAMETER_INT(cd_y_offset),
    00358   PARAMETER_INT(cd_page_width),
    00359   PARAMETER_INT(cd_page_height),
    00360   PARAMETER_RAW(preinit_sequence),
    00361   PARAMETER_RAW(postinit_remote_sequence)
    00362 };
    00363
    00364 static const int the_parameter_count =
    00365 sizeof(the_parameters) / sizeof(const stp_parameter_t);
    00366
    00367 static const float_param_t float_parameters[] =
    00368 {
    00369   {
    00370     {
    00371       "CyanDensity", N_("Cyan Balance"), N_("Output Level Adjustment"),
    00372       N_("Adjust the cyan balance"),
    00373       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00374       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 1, 1, 0
    00375     }, 0.0, 2.0, 1.0, 1
    00376   },
    00377   {
    00378     {
    00379       "MagentaDensity", N_("Magenta Balance"), N_("Output Level Adjustment"),
    00380       N_("Adjust the magenta balance"),
    00381       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00382       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 2, 1, 0
    00383     }, 0.0, 2.0, 1.0, 1
    00384   },
    00385   {
    00386     {
    00387       "YellowDensity", N_("Yellow Balance"), N_("Output Level Adjustment"),
    00388       N_("Adjust the yellow balance"),
    00389       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00390       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 3, 1, 0
    00391     }, 0.0, 2.0, 1.0, 1
    00392   },
    00393   {
    00394     {
    00395       "BlackDensity", N_("Black Balance"), N_("Output Level Adjustment"),
    00396       N_("Adjust the black balance"),
    00397       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00398       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 0, 1, 0
    00399     }, 0.0, 2.0, 1.0, 1
    00400   },
    00401   {
    00402     {
    00403       "RedDensity", N_("Red Balance"), N_("Output Level Adjustment"),
    00404       N_("Adjust the red balance"),
    00405       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00406       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 4, 1, 0
    00407     }, 0.0, 2.0, 1.0, 1
    00408   },
    00409   {
    00410     {
    00411       "BlueDensity", N_("Blue Balance"), N_("Output Level Adjustment"),
    00412       N_("Adjust the blue balance"),
    00413       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00414       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 5, 1, 0
    00415     }, 0.0, 2.0, 1.0, 1
    00416   },
    00417   {
    00418     {
    00419       "GlossDensity", N_("Gloss Balance"), N_("Output Level Adjustment"),
    00420       N_("Adjust the gloss balance"),
    00421       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00422       STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 6, 1, 0
    00423     }, 0.0, 2.0, 1.0, 1
    00424   },
    00425   {
    00426     {
    00427       "LightCyanTransition", N_("Light Cyan Transition"), N_("Advanced Ink Adjustment"),
    00428       N_("Light Cyan Transition"),
    00429       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00430       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00431     }, 0.0, 5.0, 1.0, 1
    00432   },
    00433   {
    00434     {
    00435       "LightMagentaTransition", N_("Light Magenta Transition"), N_("Advanced Ink Adjustment"),
    00436       N_("Light Magenta Transition"),
    00437       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00438       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00439     }, 0.0, 5.0, 1.0, 1
    00440   },
    00441   {
    00442     {
    00443       "DarkYellowTransition", N_("Dark Yellow Transition"), N_("Advanced Ink Adjustment"),
    00444       N_("Dark Yellow Transition"),
    00445       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00446       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00447     }, 0.0, 5.0, 1.0, 1
    00448   },
    00449   {
    00450     {
    00451       "GrayTransition", N_("Gray Transition"), N_("Advanced Ink Adjustment"),
    00452       N_("Gray Transition"),
    00453       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00454       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00455     }, 0.0, 5.0, 1.0, 1
    00456   },
    00457   {
    00458     {
    00459       "Gray3Transition", N_("Dark Gray Transition"), N_("Advanced Ink Adjustment"),
    00460       N_("Dark Gray Transition"),
    00461       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00462       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00463     }, 0.0, 5.0, 1.0, 1
    00464   },
    00465   {
    00466     {
    00467       "Gray2Transition", N_("Mid Gray Transition"), N_("Advanced Ink Adjustment"),
    00468       N_("Medium Gray Transition"),
    00469       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00470       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00471     }, 0.0, 5.0, 1.0, 1
    00472   },
    00473   {
    00474     {
    00475       "Gray1Transition", N_("Light Gray Transition"), N_("Advanced Ink Adjustment"),
    00476       N_("Light Gray Transition"),
    00477       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
    00478       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0
    00479     }, 0.0, 5.0, 1.0, 1
    00480   },
    00481 };
    00482
    00483 static const int float_parameter_count =
    00484 sizeof(float_parameters) / sizeof(const float_param_t);
    00485
    00486
    00487 static escp2_privdata_t *
    00488 get_privdata(stp_vars_t *v)
    00489 {
    00490   return (escp2_privdata_t *) stp_get_component_data(v, "Driver");
    00491 }
    00492
    00493 static model_featureset_t
    00494 escp2_get_cap(const stp_vars_t *v, escp2_model_option_t feature)
    00495 {
    00496   int model = stp_get_model_id(v);
    00497   if (feature < 0 || feature >= MODEL_LIMIT)
    00498     return (model_featureset_t) -1;
    00499   else
    00500     {
    00501       model_featureset_t featureset =
    00502         (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
    00503          escp2_printer_attrs[feature].bit_shift);
    00504       return stpi_escp2_model_capabilities[model].flags & featureset;
    00505     }
    00506 }
    00507
    00508 static int
    00509 escp2_has_cap(const stp_vars_t *v, escp2_model_option_t feature,
    00510               model_featureset_t class)
    00511 {
    00512   int model = stp_get_model_id(v);
    00513   if (feature < 0 || feature >= MODEL_LIMIT)
    00514     return -1;
    00515   else
    00516     {
    00517       model_featureset_t featureset =
    00518         (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
    00519          escp2_printer_attrs[feature].bit_shift);
    00520       if ((stpi_escp2_model_capabilities[model].flags & featureset) == class)
    00521         return 1;
    00522       else
    00523         return 0;
    00524     }
    00525 }
    00526
    00527 #define DEF_SIMPLE_ACCESSOR(f, t)                                       \
    00528 static inline t                                                         \
    00529 escp2_##f(const stp_vars_t *v)                                          \
    00530 {                                                                       \
    00531   if (stp_check_int_parameter(v, "escp2_" #f, STP_PARAMETER_ACTIVE))    \
    00532     return stp_get_int_parameter(v, "escp2_" #f);                       \
    00533   else                                                                  \
    00534     {                                                                   \
    00535       int model = stp_get_model_id(v);                                  \
    00536       return (stpi_escp2_model_capabilities[model].f);                  \
    00537     }                                                                   \
    00538 }
    00539
    00540 #define DEF_RAW_ACCESSOR(f, t)                                          \
    00541 static inline t                                                         \
    00542 escp2_##f(const stp_vars_t *v)                                          \
    00543 {                                                                       \
    00544   if (stp_check_raw_parameter(v, "escp2_" #f, STP_PARAMETER_ACTIVE))    \
    00545     return stp_get_raw_parameter(v, "escp2_" #f);                       \
    00546   else                                                                  \
    00547     {                                                                   \
    00548       int model = stp_get_model_id(v);                                  \
    00549       return (stpi_escp2_model_capabilities[model].f);                  \
    00550     }                                                                   \
    00551 }
    00552
    00553 #define DEF_COMPOSITE_ACCESSOR(f, t)                    \
    00554 static inline t                                         \
    00555 escp2_##f(const stp_vars_t *v)                          \
    00556 {                                                       \
    00557   int model = stp_get_model_id(v);                      \
    00558   return (stpi_escp2_model_capabilities[model].f);      \
    00559 }
    00560
    00561 #define DEF_ROLL_ACCESSOR(f, t)                                         \
    00562 static inline t                                                         \
    00563 escp2_##f(const stp_vars_t *v, int rollfeed)                            \
    00564 {                                                                       \
    00565   if (stp_check_int_parameter(v, "escp2_" #f, STP_PARAMETER_ACTIVE))    \
    00566     return stp_get_int_parameter(v, "escp2_" #f);                       \
    00567   else                                                                  \
    00568     {                                                                   \
    00569       int model = stp_get_model_id(v);                                  \
    00570       const res_t *res = escp2_find_resolution(v);                      \
    00571       if (res && !(res->softweave))                                     \
    00572         {                                                               \
    00573           if (rollfeed)                                                 \
    00574             return (stpi_escp2_model_capabilities[model].m_roll_##f);   \
    00575           else                                                          \
    00576             return (stpi_escp2_model_capabilities[model].m_##f);        \
    00577         }                                                               \
    00578       else                                                              \
    00579         {                                                               \
    00580           if (rollfeed)                                                 \
    00581             return (stpi_escp2_model_capabilities[model].roll_##f);     \
    00582           else                                                          \
    00583             return (stpi_escp2_model_capabilities[model].f);            \
    00584         }                                                               \
    00585     }                                                                   \
    00586 }
    00587
    00588 DEF_SIMPLE_ACCESSOR(max_hres, int)
    00589 DEF_SIMPLE_ACCESSOR(max_vres, int)
    00590 DEF_SIMPLE_ACCESSOR(min_hres, int)
    00591 DEF_SIMPLE_ACCESSOR(min_vres, int)
    00592 DEF_SIMPLE_ACCESSOR(nozzles, unsigned)
    00593 DEF_SIMPLE_ACCESSOR(black_nozzles, unsigned)
    00594 DEF_SIMPLE_ACCESSOR(fast_nozzles, unsigned)
    00595 DEF_SIMPLE_ACCESSOR(min_nozzles, unsigned)
    00596 DEF_SIMPLE_ACCESSOR(min_black_nozzles, unsigned)
    00597 DEF_SIMPLE_ACCESSOR(min_fast_nozzles, unsigned)
    00598 DEF_SIMPLE_ACCESSOR(nozzle_separation, unsigned)
    00599 DEF_SIMPLE_ACCESSOR(black_nozzle_separation, unsigned)
    00600 DEF_SIMPLE_ACCESSOR(fast_nozzle_separation, unsigned)
    00601 DEF_SIMPLE_ACCESSOR(separation_rows, unsigned)
    00602 DEF_SIMPLE_ACCESSOR(max_paper_width, unsigned)
    00603 DEF_SIMPLE_ACCESSOR(max_paper_height, unsigned)
    00604 DEF_SIMPLE_ACCESSOR(min_paper_width, unsigned)
    00605 DEF_SIMPLE_ACCESSOR(min_paper_height, unsigned)
    00606 DEF_SIMPLE_ACCESSOR(cd_x_offset, int)
    00607 DEF_SIMPLE_ACCESSOR(cd_y_offset, int)
    00608 DEF_SIMPLE_ACCESSOR(cd_page_width, int)
    00609 DEF_SIMPLE_ACCESSOR(cd_page_height, int)
    00610 DEF_SIMPLE_ACCESSOR(extra_feed, unsigned)
    00611 DEF_SIMPLE_ACCESSOR(pseudo_separation_rows, int)
    00612 DEF_SIMPLE_ACCESSOR(base_separation, int)
    00613 DEF_SIMPLE_ACCESSOR(resolution_scale, int)
    00614 DEF_SIMPLE_ACCESSOR(initial_vertical_offset, int)
    00615 DEF_SIMPLE_ACCESSOR(black_initial_vertical_offset, int)
    00616 DEF_SIMPLE_ACCESSOR(max_black_resolution, int)
    00617 DEF_SIMPLE_ACCESSOR(zero_margin_offset, int)
    00618 DEF_SIMPLE_ACCESSOR(extra_720dpi_separation, int)
    00619 DEF_SIMPLE_ACCESSOR(physical_channels, int)
    00620 DEF_SIMPLE_ACCESSOR(alignment_passes, int)
    00621 DEF_SIMPLE_ACCESSOR(alignment_choices, int)
    00622 DEF_SIMPLE_ACCESSOR(alternate_alignment_passes, int)
    00623 DEF_SIMPLE_ACCESSOR(alternate_alignment_choices, int)
    00624 DEF_COMPOSITE_ACCESSOR(printer_weaves, const printer_weave_list_t *)
    00625
    00626 DEF_ROLL_ACCESSOR(left_margin, unsigned)
    00627 DEF_ROLL_ACCESSOR(right_margin, unsigned)
    00628 DEF_ROLL_ACCESSOR(top_margin, unsigned)
    00629 DEF_ROLL_ACCESSOR(bottom_margin, unsigned)
    00630
    00631 DEF_RAW_ACCESSOR(preinit_sequence, const stp_raw_t *)
    00632 DEF_RAW_ACCESSOR(postinit_remote_sequence, const stp_raw_t *)
    00633
    00634 DEF_COMPOSITE_ACCESSOR(reslist, const res_t *const *)
    00635 DEF_COMPOSITE_ACCESSOR(inkgroup, const inkgroup_t *)
    00636 DEF_COMPOSITE_ACCESSOR(input_slots, const input_slot_list_t *)
    00637 DEF_COMPOSITE_ACCESSOR(quality_list, const quality_list_t *)
    00638
    00639 static const channel_count_t *
    00640 get_channel_count_by_name(const char *name)
    00641 {
    00642   int i;
    00643   for (i = 0; i < escp2_channel_counts_count; i++)
    00644     if (strcmp(name, escp2_channel_counts[i].name) == 0)
    00645       return &(escp2_channel_counts[i]);
    00646   return NULL;
    00647 }
    00648
    00649 static const channel_count_t *
    00650 get_channel_count_by_number(unsigned count)
    00651 {
    00652   int i;
    00653   for (i = 0; i < escp2_channel_counts_count; i++)
    00654     if (count == escp2_channel_counts[i].count)
    00655       return &(escp2_channel_counts[i]);
    00656   return NULL;
    00657 }
    00658
    00659 static int
    00660 escp2_ink_type(const stp_vars_t *v, int resid)
    00661 {
    00662   if (stp_check_int_parameter(v, "escp2_ink_type", STP_PARAMETER_ACTIVE))
    00663     return stp_get_int_parameter(v, "escp2_ink_type");
    00664   else
    00665     {
    00666       int model = stp_get_model_id(v);
    00667       return stpi_escp2_model_capabilities[model].dot_sizes[resid];
    00668     }
    00669 }
    00670
    00671 static double
    00672 escp2_density(const stp_vars_t *v, int resid)
    00673 {
    00674   if (stp_check_float_parameter(v, "escp2_density", STP_PARAMETER_ACTIVE))
    00675     return stp_get_float_parameter(v, "escp2_density");
    00676   else
    00677     {
    00678       int model = stp_get_model_id(v);
    00679       return stpi_escp2_model_capabilities[model].densities[resid];
    00680     }
    00681 }
    00682
    00683 static int
    00684 escp2_bits(const stp_vars_t *v, int resid)
    00685 {
    00686   if (stp_check_int_parameter(v, "escp2_bits", STP_PARAMETER_ACTIVE))
    00687     return stp_get_int_parameter(v, "escp2_bits");
    00688   else
    00689     {
    00690       int model = stp_get_model_id(v);
    00691       return stpi_escp2_model_capabilities[model].bits[resid];
    00692     }
    00693 }
    00694
    00695 static double
    00696 escp2_base_res(const stp_vars_t *v, int resid)
    00697 {
    00698   if (stp_check_float_parameter(v, "escp2_base_res", STP_PARAMETER_ACTIVE))
    00699     return stp_get_float_parameter(v, "escp2_base_res");
    00700   else
    00701     {
    00702       int model = stp_get_model_id(v);
    00703       return stpi_escp2_model_capabilities[model].base_resolutions[resid];
    00704     }
    00705 }
    00706
    00707 static const escp2_dropsize_t *
    00708 escp2_dropsizes(const stp_vars_t *v, int resid)
    00709 {
    00710   int model = stp_get_model_id(v);
    00711   const escp2_drop_list_t *drops = stpi_escp2_model_capabilities[model].drops;
    00712   return (*drops)[resid];
    00713 }
    00714
    00715 static const inklist_t *
    00716 escp2_inklist(const stp_vars_t *v)
    00717 {
    00718   int model = stp_get_model_id(v);
    00719   int i;
    00720   const char *ink_list_name = NULL;
    00721   const inkgroup_t *inkgroup = stpi_escp2_model_capabilities[model].inkgroup;
    00722
    00723   if (stp_check_string_parameter(v, "InkSet", STP_PARAMETER_ACTIVE))
    00724     ink_list_name = stp_get_string_parameter(v, "InkSet");
    00725   if (ink_list_name)
    00726     {
    00727       for (i = 0; i < inkgroup->n_inklists; i++)
    00728         {
    00729           if (strcmp(ink_list_name, inkgroup->inklists[i]->name) == 0)
    00730             return inkgroup->inklists[i];
    00731         }
    00732     }
    00733   return inkgroup->inklists[0];
    00734 }
    00735
    00736 static const shade_t *
    00737 escp2_shades(const stp_vars_t *v, int channel)
    00738 {
    00739   const inklist_t *inklist = escp2_inklist(v);
    00740   return &((*inklist->shades)[channel]);
    00741 }
    00742
    00743 static const paperlist_t *
    00744 escp2_paperlist(const stp_vars_t *v)
    00745 {
    00746   const inklist_t *inklist = escp2_inklist(v);
    00747   if (inklist)
    00748     return inklist->papers;
    00749   else
    00750     return NULL;
    00751 }
    00752
    00753 static int
    00754 using_automatic_settings(const stp_vars_t *v, auto_mode_t mode)
    00755 {
    00756   int is_raw = 0;
    00757   if (stp_get_string_parameter(v, "InputImageType") &&
    00758       strcmp(stp_get_string_parameter(v, "InputImageType"), "Raw") == 0)
    00759     is_raw = 1;
    00760   switch (mode)
    00761     {
    00762     case AUTO_MODE_QUALITY:
    00763       if (stp_check_string_parameter(v, "Quality", STP_PARAMETER_ACTIVE) &&
    00764           strcmp(stp_get_string_parameter(v, "Quality"), "None") != 0 &&
    00765           !is_raw)
    00766         return 1;
    00767       else
    00768         return 0;
    00769 #if 0
    00770     case AUTO_MODE_FULL_AUTO:
    00771       if (stp_check_string_parameter(v, "AutoMode", STP_PARAMETER_ACTIVE) &&
    00772           strcmp(stp_get_string_parameter(v, "AutoMode"), "None") != 0 &&
    00773           !is_raw)
    00774         return 1;
    00775       else
    00776         return 0;
    00777 #endif
    00778     case AUTO_MODE_MANUAL:
    00779       if (!stp_check_string_parameter(v, "Quality", STP_PARAMETER_ACTIVE) ||
    00780           strcmp(stp_get_string_parameter(v, "Quality"), "None") == 0 ||
    00781           is_raw)
    00782         return 1;
    00783       else
    00784         return 0;
    00785     }
    00786   return 0;
    00787 }
    00788
    00789 static int
    00790 compute_internal_resid(int hres, int vres)
    00791 {
    00792   static const int resolutions[RES_N] =
    00793     {
    00794       0,
    00795       360 * 360,
    00796       720 * 360,
    00797       720 * 720,
    00798       1440 * 720,
    00799       1440 * 1440,
    00800       2880 * 1440,
    00801       2880 * 2880,
    00802     };
    00803   int total_resolution = hres * vres;
    00804   int i;
    00805   for (i = 0; i < RES_N; i++)
    00806     {
    00807       if (total_resolution < resolutions[i])
    00808         return i - 1;
    00809     }
    00810   return RES_N - 1;
    00811 }
    00812
    00813 static int
    00814 compute_resid(const res_t *res)
    00815 {
    00816   return compute_internal_resid(res->hres, res->vres);
    00817 }
    00818
    00819 static int
    00820 compute_printed_resid(const res_t *res)
    00821 {
    00822   return compute_internal_resid(res->printed_hres, res->printed_vres);
    00823 }
    00824
    00825
    00826 static const input_slot_t *
    00827 get_input_slot(const stp_vars_t *v)
    00828 {
    00829   int i;
    00830   const char *input_slot = stp_get_string_parameter(v, "InputSlot");
    00831   if (input_slot && strlen(input_slot) > 0)
    00832     {
    00833       const input_slot_list_t *slots = escp2_input_slots(v);
    00834       if (slots)
    00835         {
    00836           for (i = 0; i < slots->n_input_slots; i++)
    00837             {
    00838               if (slots->slots[i].name &&
    00839                   strcmp(input_slot, slots->slots[i].name) == 0)
    00840                 {
    00841                   return &(slots->slots[i]);
    00842                   break;
    00843                 }
    00844             }
    00845         }
    00846     }
    00847   return NULL;
    00848 }
    00849
    00850 static const printer_weave_t *
    00851 get_printer_weave(const stp_vars_t *v)
    00852 {
    00853   int i;
    00854   const printer_weave_list_t *p = escp2_printer_weaves(v);
    00855   if (p)
    00856     {
    00857       const char *name = stp_get_string_parameter(v, "Weave");
    00858       int printer_weave_count = p->n_printer_weaves;
    00859       if (name)
    00860         {
    00861           for (i = 0; i < printer_weave_count; i++)
    00862             {
    00863               if (!strcmp(name, p->printer_weaves[i].name))
    00864                 return &(p->printer_weaves[i]);
    00865             }
    00866         }
    00867     }
    00868   return NULL;
    00869 }
    00870
    00871 static int
    00872 use_printer_weave(const stp_vars_t *v)
    00873 {
    00874   const res_t *res = escp2_find_resolution(v);
    00875   if (!res)
    00876     return 1;
    00877   else if (!(res->softweave))
    00878     return 1;
    00879   else if (res->printer_weave)
    00880     return 1;
    00881   else
    00882     return 0;
    00883 }
    00884
    00885
    00886 static const paper_t *
    00887 get_media_type(const stp_vars_t *v)
    00888 {
    00889   int i;
    00890   const paperlist_t *p = escp2_paperlist(v);
    00891   if (p)
    00892     {
    00893       const char *name = stp_get_string_parameter(v, "MediaType");
    00894       int paper_type_count = p->paper_count;
    00895       if (name)
    00896         {
    00897           for (i = 0; i < paper_type_count; i++)
    00898             {
    00899               if (!strcmp(name, p->papers[i].name))
    00900                 return &(p->papers[i]);
    00901             }
    00902         }
    00903     }
    00904   return NULL;
    00905 }
    00906
    00907 static int
    00908 verify_resolution_by_paper_type(const stp_vars_t *v, const res_t *res)
    00909 {
    00910   const paper_t *paper = get_media_type(v);
    00911   if (paper)
    00912     {
    00913       switch (paper->paper_class)
    00914         {
    00915         case PAPER_PLAIN:
    00916           if (res->printed_vres > 720 || res->hres > 720)
    00917             return 0;
    00918           break;
    00919         case PAPER_GOOD:
    00920           if (res->printed_vres < 180 || res->hres < 360 ||
    00921               res->printed_vres > 720 || res->hres > 1440)
    00922             return 0;
    00923           break;
    00924         case PAPER_PHOTO:
    00925           if (res->printed_vres < 360 ||
    00926               (res->hres < 720 && res->hres < escp2_max_hres(v)))
    00927             return 0;
    00928           break;
    00929         case PAPER_PREMIUM_PHOTO:
    00930           if (res->printed_vres < 720 ||
    00931               (res->hres < 720 && res->hres < escp2_max_hres(v)))
    00932             return 0;
    00933           break;
    00934         case PAPER_TRANSPARENCY:
    00935           if (res->printed_vres < 360 || res->hres < 360 ||
    00936               res->printed_vres > 720 || res->hres > 720)
    00937             return 0;
    00938           break;
    00939         }
    00940     }
    00941   return 1;
    00942 }
    00943
    00944 static int
    00945 verify_resolution(const stp_vars_t *v, const res_t *res)
    00946 {
    00947   int nozzle_width =
    00948     (escp2_base_separation(v) / escp2_nozzle_separation(v));
    00949   int nozzles = escp2_nozzles(v);
    00950   if (escp2_ink_type(v, compute_printed_resid(res)) != -1 &&
    00951       res->vres <= escp2_max_vres(v) &&
    00952       res->hres <= escp2_max_hres(v) &&
    00953       res->vres >= escp2_min_vres(v) &&
    00954       res->hres >= escp2_min_hres(v) &&
    00955       (nozzles == 1 ||
    00956        ((res->vres / nozzle_width) * nozzle_width) == res->vres))
    00957     {
    00958       int xdpi = res->hres;
    00959       int physical_xdpi = escp2_base_res(v, compute_resid(res));
    00960       int horizontal_passes, oversample;
    00961       if (physical_xdpi > xdpi)
    00962         physical_xdpi = xdpi;
    00963       horizontal_passes = xdpi / physical_xdpi;
    00964       oversample = horizontal_passes * res->vertical_passes;
    00965       if (horizontal_passes < 1)
    00966         horizontal_passes = 1;
    00967       if (oversample < 1)
    00968         oversample = 1;
    00969       if (((horizontal_passes * res->vertical_passes) <= 8) &&
    00970           (! res->softweave || (nozzles > 1 && nozzles > oversample)))
    00971         return 1;
    00972     }
    00973   return 0;
    00974 }
    00975
    00976 static int
    00977 verify_papersize(const stp_vars_t *v, const stp_papersize_t *pt)
    00978 {
    00979   unsigned int height_limit, width_limit;
    00980   unsigned int min_height_limit, min_width_limit;
    00981   width_limit = escp2_max_paper_width(v);
    00982   height_limit = escp2_max_paper_height(v);
    00983   min_width_limit = escp2_min_paper_width(v);
    00984   min_height_limit = escp2_min_paper_height(v);
    00985   if (strlen(pt->name) > 0 &&
    00986       pt->width <= width_limit && pt->height <= height_limit &&
    00987       (pt->height >= min_height_limit || pt->height == 0) &&
    00988       (pt->width >= min_width_limit || pt->width == 0) &&
    00989       (pt->width == 0 || pt->height > 0 ||
    00990        escp2_has_cap(v, MODEL_ROLLFEED, MODEL_ROLLFEED_YES)))
    00991     return 1;
    00992   else
    00993     return 0;
    00994 }
    00995
    00996 static int
    00997 verify_inktype(const stp_vars_t *v, const escp2_inkname_t *inks)
    00998 {
    00999   if (inks->inkset == INKSET_EXTENDED)
    01000     return 0;
    01001   else
    01002     return 1;
    01003 }
    01004
    01005 static const char *
    01006 get_default_inktype(const stp_vars_t *v)
    01007 {
    01008   const inklist_t *ink_list = escp2_inklist(v);
    01009   const paper_t *paper_type = get_media_type(v);
    01010   if (!ink_list)
    01011     return NULL;
    01012   if (!paper_type)
    01013     {
    01014       const paperlist_t *p = escp2_paperlist(v);
    01015       if (p)
    01016         paper_type = &(p->papers[0]);
    01017     }
    01018   if (paper_type && paper_type->preferred_ink_type)
    01019     return paper_type->preferred_ink_type;
    01020   else if (escp2_has_cap(v, MODEL_FAST_360, MODEL_FAST_360_YES) &&
    01021            stp_check_string_parameter(v, "Resolution", STP_PARAMETER_ACTIVE))
    01022     {
    01023       const res_t *res = escp2_find_resolution(v);
    01024       if (res)
    01025         {
    01026           int resid = compute_printed_resid(res);
    01027           if (res->vres == 360 && res->hres == escp2_base_res(v, resid))
    01028             {
    01029               int i;
    01030               for (i = 0; i < ink_list->n_inks; i++)
    01031                 if (strcmp(ink_list->inknames[i]->name, "CMYK") == 0)
    01032                   return ink_list->inknames[i]->name;
    01033             }
    01034         }
    01035     }
    01036   return ink_list->inknames[0]->name;
    01037 }
    01038
    01039
    01040 static const escp2_inkname_t *
    01041 get_inktype(const stp_vars_t *v)
    01042 {
    01043   const char    *ink_type = stp_get_string_parameter(v, "InkType");
    01044   const inklist_t *ink_list = escp2_inklist(v);
    01045   int i;
    01046
    01047   if (!ink_type || strcmp(ink_type, "None") == 0 ||
    01048       (ink_list && ink_list->n_inks == 1) ||
    01049       !using_automatic_settings(v, AUTO_MODE_MANUAL))
    01050     ink_type = get_default_inktype(v);
    01051
    01052   if (ink_type && ink_list)
    01053     {
    01054       for (i = 0; i < ink_list->n_inks; i++)
    01055         {
    01056           if (strcmp(ink_type, ink_list->inknames[i]->name) == 0)
    01057             return ink_list->inknames[i];
    01058         }
    01059     }
    01060   /*
    01061    * If we couldn't find anything, try again with the default ink type.
    01062    * This may mean duplicate work, but that's cheap enough.
    01063    */
    01064   ink_type = get_default_inktype(v);
    01065   for (i = 0; i < ink_list->n_inks; i++)
    01066     {
    01067       if (strcmp(ink_type, ink_list->inknames[i]->name) == 0)
    01068         return ink_list->inknames[i];
    01069     }
    01070   return NULL;
    01071 }
    01072
    01073 static const paper_adjustment_t *
    01074 get_media_adjustment(const stp_vars_t *v)
    01075 {
    01076   const paper_t *pt = get_media_type(v);
    01077   const inklist_t *ink_list = escp2_inklist(v);
    01078   if (pt && ink_list && ink_list->paper_adjustments)
    01079     {
    01080       const paper_adjustment_list_t *adjlist = ink_list->paper_adjustments;
    01081       const char *paper_name = pt->name;
    01082       int i;
    01083       for (i = 0; i < adjlist->paper_count; i++)
    01084         {
    01085           if (strcmp(paper_name, adjlist->papers[i].name) == 0)
    01086             return &(adjlist->papers[i]);
    01087         }
    01088     }
    01089   return NULL;
    01090 }
    01091
    01092
    01093 /*
    01094  * 'escp2_parameters()' - Return the parameter values for the given parameter.
    01095  */
    01096
    01097 static stp_parameter_list_t
    01098 escp2_list_parameters(const stp_vars_t *v)
    01099 {
    01100   stp_parameter_list_t *ret = stp_parameter_list_create();
    01101   int i;
    01102   for (i = 0; i < the_parameter_count; i++)
    01103     stp_parameter_list_add_param(ret, &(the_parameters[i]));
    01104   for (i = 0; i < float_parameter_count; i++)
    01105     stp_parameter_list_add_param(ret, &(float_parameters[i].param));
    01106   return ret;
    01107 }
    01108
    01109 static void
    01110 fill_transition_parameters(stp_parameter_t *description)
    01111 {
    01112   description->is_active = 1;
    01113   description->bounds.dbl.lower = 0;
    01114   description->bounds.dbl.upper = 5.0;
    01115   description->deflt.dbl = 1.0;
    01116 }
    01117
    01118 static void
    01119 set_density_parameter(const stp_vars_t *v,
    01120                       stp_parameter_t *description,
    01121                       int color)
    01122 {
    01123   description->is_active = 0;
    01124   if (stp_get_string_parameter(v, "PrintingMode") &&
    01125       strcmp(stp_get_string_parameter(v, "PrintingMode"), "BW") != 0 &&
    01126       using_automatic_settings(v, AUTO_MODE_MANUAL))
    01127     {
    01128       const escp2_inkname_t *ink_name = get_inktype(v);
    01129       if (ink_name &&
    01130           ink_name->channel_set->channel_count > color &&
    01131           ink_name->channel_set->channels[color])
    01132         description->is_active = 1;
    01133     }
    01134 }
    01135
    01136 static void
    01137 set_gray_transition_parameter(const stp_vars_t *v,
    01138                               stp_parameter_t *description,
    01139                               int expected_channels)
    01140 {
    01141   const escp2_inkname_t *ink_name = get_inktype(v);
    01142   description->is_active = 0;
    01143   if (ink_name && ink_name->channel_set->channels[STP_ECOLOR_K] &&
    01144       (ink_name->channel_set->channels[STP_ECOLOR_K]->n_subchannels ==
    01145        expected_channels) &&
    01146       using_automatic_settings(v, AUTO_MODE_MANUAL))
    01147     fill_transition_parameters(description);
    01148 }
    01149
    01150 static void
    01151 set_color_transition_parameter(const stp_vars_t *v,
    01152                                stp_parameter_t *description,
    01153                                int color)
    01154 {
    01155   description->is_active = 0;
    01156   if (stp_get_string_parameter(v, "PrintingMode") &&
    01157       strcmp(stp_get_string_parameter(v, "PrintingMode"), "BW") != 0 &&
    01158       using_automatic_settings(v, AUTO_MODE_MANUAL))
    01159     {
    01160       const escp2_inkname_t *ink_name = get_inktype(v);
    01161       if (ink_name &&
    01162           ink_name->channel_set->channel_count == 4 &&
    01163           ink_name->channel_set->channels[color] &&
    01164           ink_name->channel_set->channels[color]->n_subchannels == 2)
    01165         fill_transition_parameters(description);
    01166     }
    01167 }
    01168
    01169 static const res_t *
    01170 find_default_resolution(const stp_vars_t *v, int desired_hres, int desired_vres,
    01171                         int strict)
    01172 {
    01173   const res_t *const *res = escp2_reslist(v);
    01174   int i = 0;
    01175   if (desired_hres < 0)
    01176     {
    01177       while (res[i])
    01178         i++;
    01179       i--;
    01180       while (i >= 0)
    01181         {
    01182           if (verify_resolution(v, res[i]) &&
    01183               verify_resolution_by_paper_type(v, res[i]))
    01184             return res[i];
    01185           i--;
    01186         }
    01187     }
    01188   i = 0;
    01189   while (res[i])
    01190     {
    01191       if (verify_resolution(v, res[i]) &&
    01192           verify_resolution_by_paper_type(v, res[i]) &&
    01193           res[i]->vres >= desired_vres && res[i]->hres >= desired_hres &&
    01194           res[i]->vres <= 2 * desired_vres && res[i]->hres <= 2 * desired_hres)
    01195         return res[i];
    01196       i++;
    01197     }
    01198 #if 0
    01199   if (!strict)                  /* Try again to find a match */
    01200     {
    01201       i = 0;
    01202       while (res[i])
    01203         {
    01204           if (verify_resolution(v, res[i]) &&
    01205               res[i]->vres >= desired_vres &&
    01206               res[i]->hres >= desired_hres &&
    01207               res[i]->vres <= 2 * desired_vres &&
    01208               res[i]->hres <= 2 * desired_hres)
    01209             return res[i];
    01210           i++;
    01211         }
    01212     }
    01213 #endif
    01214   return NULL;
    01215 }
    01216
    01217 static const res_t *
    01218 find_resolution_from_quality(const stp_vars_t *v, const char *quality,
    01219                              int strict)
    01220 {
    01221   int i;
    01222   const quality_list_t *quals = escp2_quality_list(v);
    01223   for (i = 0; i < quals->n_quals; i++)
    01224     {
    01225       const quality_t *q = &(quals->qualities[i]);
    01226       if (strcmp(quality, q->name) == 0 &&
    01227           (q->min_vres == 0 || escp2_min_vres(v) <= q->min_vres) &&
    01228           (q->min_hres == 0 || escp2_min_hres(v) <= q->min_hres) &&
    01229           (q->max_vres == 0 || escp2_max_vres(v) >= q->max_vres) &&
    01230           (q->max_hres == 0 || escp2_max_hres(v) >= q->max_hres))
    01231         {
    01232           return find_default_resolution(v, q->desired_hres, q->desired_vres,
    01233                                          strict);
    01234         }
    01235     }
    01236   return NULL;
    01237 }
    01238
    01239 static void
    01240 escp2_parameters(const stp_vars_t *v, const char *name,
    01241                  stp_parameter_t *description)
    01242 {
    01243   int           i;
    01244   description->p_type = STP_PARAMETER_TYPE_INVALID;
    01245   if (name == NULL)
    01246     return;
    01247
    01248   for (i = 0; i < float_parameter_count; i++)
    01249     if (strcmp(name, float_parameters[i].param.name) == 0)
    01250       {
    01251         stp_fill_parameter_settings(description,
    01252                                      &(float_parameters[i].param));
    01253         description->deflt.dbl = float_parameters[i].defval;
    01254         description->bounds.dbl.upper = float_parameters[i].max;
    01255         description->bounds.dbl.lower = float_parameters[i].min;
    01256         break;
    01257       }
    01258
    01259   for (i = 0; i < the_parameter_count; i++)
    01260     if (strcmp(name, the_parameters[i].name) == 0)
    01261       {
    01262         stp_fill_parameter_settings(description, &(the_parameters[i]));
    01263         break;
    01264       }
    01265
    01266   description->deflt.str = NULL;
    01267   if (strcmp(name, "AutoMode") == 0)
    01268     {
    01269       description->bounds.str = stp_string_list_create();
    01270       stp_string_list_add_string(description->bounds.str, "None",
    01271                                  _("Full Manual Control"));
    01272       stp_string_list_add_string(description->bounds.str, "Auto",
    01273                                  _("Automatic Setting Control"));
    01274       description->deflt.str = "None"; /* so CUPS and Foomatic don't break */
    01275     }
    01276   else if (strcmp(name, "PageSize") == 0)
    01277     {
    01278       int papersizes = stp_known_papersizes();
    01279       const input_slot_t *slot = get_input_slot(v);
    01280       description->bounds.str = stp_string_list_create();
    01281       if (slot && slot->is_cd)
    01282         {
    01283           stp_string_list_add_string
    01284             (description->bounds.str, "CD5Inch", _("CD - 5 inch"));
    01285           stp_string_list_add_string
    01286             (description->bounds.str, "CD3Inch", _("CD - 3 inch"));
    01287         }
    01288       else
    01289         {
    01290           for (i = 0; i < papersizes; i++)
    01291             {
    01292               const stp_papersize_t *pt = stp_get_papersize_by_index(i);
    01293               if (verify_papersize(v, pt))
    01294                 stp_string_list_add_string(description->bounds.str,
    01295                                            pt->name, pt->text);
    01296             }
    01297         }
    01298       description->deflt.str =
    01299         stp_string_list_param(description->bounds.str, 0)->name;
    01300     }
    01301   else if (strcmp(name, "CDInnerRadius") == 0)
    01302     {
    01303       const input_slot_t *slot = get_input_slot(v);
    01304       description->bounds.str = stp_string_list_create();
    01305       if (escp2_has_cap(v, MODEL_PRINT_TO_CD, MODEL_PRINT_TO_CD_YES) &&
    01306           (!slot || (slot && slot->is_cd)))
    01307         {
    01308           stp_string_list_add_string
    01309             (description->bounds.str, "None", _("Normal"));
    01310           stp_string_list_add_string
    01311             (description->bounds.str, "Small", _("Print To Hub"));
    01312           description->deflt.str =
    01313             stp_string_list_param(description->bounds.str, 0)->name;
    01314         }
    01315       else
    01316         description->is_active = 0;
    01317     }
    01318   else if (strcmp(name, "CDXAdjustment") == 0 ||
    01319            strcmp(name, "CDYAdjustment") == 0)
    01320     {
    01321       const input_slot_t *slot = get_input_slot(v);
    01322       if (escp2_has_cap(v, MODEL_PRINT_TO_CD, MODEL_PRINT_TO_CD_YES) &&
    01323           (!slot || (slot && slot->is_cd)))
    01324         {
    01325           description->bounds.dimension.lower = -15;
    01326           description->bounds.dimension.upper = 15;
    01327           description->deflt.dimension = 0;
    01328         }
    01329       else
    01330         description->is_active = 0;
    01331     }
    01332   else if (strcmp(name, "Quality") == 0)
    01333     {
    01334       const quality_list_t *quals = escp2_quality_list(v);
    01335       int has_standard_quality = 0;
    01336       description->bounds.str = stp_string_list_create();
    01337       stp_string_list_add_string(description->bounds.str, "None",
    01338                                  _("Manual Control"));
    01339       for (i = 0; i < quals->n_quals; i++)
    01340         {
    01341           const quality_t *q = &(quals->qualities[i]);
    01342           if (((q->min_vres == 0 || escp2_min_vres(v) <= q->min_vres) &&
    01343                (q->min_hres == 0 || escp2_min_hres(v) <= q->min_hres) &&
    01344                (q->max_vres == 0 || escp2_max_vres(v) >= q->max_vres) &&
    01345                (q->max_hres == 0 || escp2_max_hres(v) >= q->max_hres)) &&
    01346               (find_resolution_from_quality(v, q->name, 1) ||
    01347                (!stp_check_string_parameter(v, "MediaType",
    01348                                             STP_PARAMETER_ACTIVE))))
    01349             stp_string_list_add_string(description->bounds.str, q->name,
    01350                                        q->text);
    01351           if (strcmp(q->name, "Standard") == 0)
    01352             has_standard_quality = 1;
    01353         }
    01354       if (has_standard_quality)
    01355         description->deflt.str = "Standard";
    01356       else
    01357         description->deflt.str = "None";
    01358     }
    01359   else if (strcmp(name, "Resolution") == 0)
    01360     {
    01361       const res_t *const *res = escp2_reslist(v);
    01362       const res_t *defval = find_default_resolution(v, 720, 360, 0);
    01363       description->bounds.str = stp_string_list_create();
    01364       i = 0;
    01365       while (res[i])
    01366         {
    01367           if (verify_resolution(v, res[i]) &&
    01368               (using_automatic_settings(v, AUTO_MODE_MANUAL) ||
    01369                !stp_check_string_parameter(v, "MediaType",
    01370                                            STP_PARAMETER_ACTIVE) ||
    01371                verify_resolution_by_paper_type(v, res[i])))
    01372             stp_string_list_add_string(description->bounds.str,
    01373                                        res[i]->name, _(res[i]->text));
    01374           i++;
    01375         }
    01376       if (defval)
    01377         description->deflt.str = defval->name;
    01378       else
    01379         description->deflt.str = res[0]->name;
    01380       if (!using_automatic_settings(v, AUTO_MODE_MANUAL))
    01381         description->is_active = 0;
    01382     }
    01383   else if (strcmp(name, "InkType") == 0)
    01384     {
    01385       const inklist_t *inks = escp2_inklist(v);
    01386       int ninktypes = inks->n_inks;
    01387       description->bounds.str = stp_string_list_create();
    01388       if (ninktypes > 1)
    01389         {
    01390           stp_string_list_add_string(description->bounds.str, "None",
    01391                                      _("Standard"));
    01392           for (i = 0; i < ninktypes; i++)
    01393             if (verify_inktype(v, inks->inknames[i]))
    01394               stp_string_list_add_string(description->bounds.str,
    01395                                          inks->inknames[i]->name,
    01396                                          _(inks->inknames[i]->text));
    01397           description->deflt.str = "None";
    01398         }
    01399       if (ninktypes <= 1 || !using_automatic_settings(v, AUTO_MODE_MANUAL))
    01400         description->is_active = 0;
    01401     }
    01402   else if (strcmp(name, "InkSet") == 0)
    01403     {
    01404       const inkgroup_t *inks = escp2_inkgroup(v);
    01405       int ninklists = inks->n_inklists;
    01406       description->bounds.str = stp_string_list_create();
    01407       if (ninklists > 1)
    01408         {
    01409           int has_default_choice = 0;
    01410           for (i = 0; i < ninklists; i++)
    01411             {
    01412               stp_string_list_add_string(description->bounds.str,
    01413                                          inks->inklists[i]->name,
    01414                                          _(inks->inklists[i]->text));
    01415               if (strcmp(inks->inklists[i]->name, "None") == 0)
    01416                 has_default_choice = 1;
    01417             }
    01418           description->deflt.str =
    01419             stp_string_list_param(description->bounds.str, 0)->name;
    01420           if (!using_automatic_settings(v, AUTO_MODE_MANUAL) &&
    01421               has_default_choice)
    01422             description->is_active = 0;
    01423         }
    01424       else
    01425         description->is_active = 0;
    01426     }
    01427   else if (strcmp(name, "MediaType") == 0)
    01428     {
    01429       const paperlist_t *p = escp2_paperlist(v);
    01430       int nmediatypes = p->paper_count;
    01431       description->bounds.str = stp_string_list_create();
    01432       if (nmediatypes)
    01433         {
    01434           for (i = 0; i < nmediatypes; i++)
    01435             stp_string_list_add_string(description->bounds.str,
    01436                                        p->papers[i].name,
    01437                                        _(p->papers[i].text));
    01438           description->deflt.str =
    01439             stp_string_list_param(description->bounds.str, 0)->name;
    01440         }
    01441       else
    01442         description->is_active = 0;
    01443     }
    01444   else if (strcmp(name, "InputSlot") == 0)
    01445     {
    01446       const input_slot_list_t *slots = escp2_input_slots(v);
    01447       int ninputslots = slots->n_input_slots;
    01448       description->bounds.str = stp_string_list_create();
    01449       if (ninputslots)
    01450         {
    01451           for (i = 0; i < ninputslots; i++)
    01452             stp_string_list_add_string(description->bounds.str,
    01453                                        slots->slots[i].name,
    01454                                        _(slots->slots[i].text));
    01455           description->deflt.str =
    01456             stp_string_list_param(description->bounds.str, 0)->name;
    01457         }
    01458       else
    01459         description->is_active = 0;
    01460     }
    01461   else if (strcmp(name, "PrintingDirection") == 0)
    01462     {
    01463       description->bounds.str = stp_string_list_create();
    01464       stp_string_list_add_string
    01465         (description->bounds.str, "None", _("Automatic"));
    01466       stp_string_list_add_string
    01467         (description->bounds.str, "Bidirectional", _("Bidirectional"));
    01468       stp_string_list_add_string
    01469         (description->bounds.str, "Unidirectional", _("Unidirectional"));
    01470       description->deflt.str =
    01471         stp_string_list_param(description->bounds.str, 0)->name;
    01472       if (!using_automatic_settings(v, AUTO_MODE_MANUAL))
    01473         description->is_active = 0;
    01474     }
    01475   else if (strcmp(name, "Weave") == 0)
    01476     {
    01477       description->bounds.str = stp_string_list_create();
    01478       if (escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_PRO))
    01479         {
    01480           const res_t *res = escp2_find_resolution(v);
    01481           const printer_weave_list_t *printer_weaves = escp2_printer_weaves(v);
    01482           int nprinter_weaves = 0;
    01483           if (use_printer_weave(v) && (!res || res->printer_weave))
    01484             nprinter_weaves = printer_weaves->n_printer_weaves;
    01485           if (nprinter_weaves)
    01486             {
    01487               stp_string_list_add_string(description->bounds.str, "None",
    01488                                          _("Standard"));
    01489               for (i = 0; i < nprinter_weaves; i++)
    01490                 stp_string_list_add_string(description->bounds.str,
    01491                                            printer_weaves->printer_weaves[i].name,
    01492                                            _(printer_weaves->printer_weaves[i].text));
    01493             }
    01494           else
    01495             description->is_active = 0;
    01496         }
    01497       else
    01498         {
    01499           stp_string_list_add_string
    01500             (description->bounds.str, "None", _("Standard"));
    01501           stp_string_list_add_string
    01502             (description->bounds.str, "Alternate", _("Alternate Fill"));
    01503           stp_string_list_add_string
    01504             (description->bounds.str, "Ascending", _("Ascending Fill"));
    01505           stp_string_list_add_string
    01506             (description->bounds.str, "Descending", _("Descending Fill"));
    01507           stp_string_list_add_string
    01508             (description->bounds.str, "Ascending2X", _("Ascending Double"));
    01509           stp_string_list_add_string
    01510             (description->bounds.str, "Staggered", _("Nearest Neighbor Avoidance"));
    01511         }
    01512       if (description->is_active)
    01513         description->deflt.str =
    01514           stp_string_list_param(description->bounds.str, 0)->name;
    01515       if (!using_automatic_settings(v, AUTO_MODE_MANUAL))
    01516         description->is_active = 0;
    01517     }
    01518   else if (strcmp(name, "OutputOrder") == 0)
    01519     {
    01520       description->bounds.str = stp_string_list_create();
    01521       description->deflt.str = "Reverse";
    01522     }
    01523   else if (strcmp(name, "FullBleed") == 0)
    01524     {
    01525       const input_slot_t *slot = get_input_slot(v);
    01526       if (slot && slot->is_cd)
    01527         description->is_active = 0;
    01528       else if (escp2_has_cap(v, MODEL_XZEROMARGIN, MODEL_XZEROMARGIN_YES))
    01529         description->deflt.boolean = 0;
    01530       else
    01531         description->is_active = 0;
    01532     }
    01533   else if (strcmp(name, "AdjustDotsize") == 0)
    01534     {
    01535       description->deflt.boolean = 0;
    01536       if (!using_automatic_settings(v, AUTO_MODE_MANUAL))
    01537         description->is_active = 0;
    01538     }
    01539   else if (strcmp(name, "CyanDensity") == 0)
    01540     set_density_parameter(v, description, STP_ECOLOR_C);
    01541   else if (strcmp(name, "MagentaDensity") == 0)
    01542     set_density_parameter(v, description, STP_ECOLOR_M);
    01543   else if (strcmp(name, "YellowDensity") == 0)
    01544     set_density_parameter(v, description, STP_ECOLOR_Y);
    01545   else if (strcmp(name, "BlackDensity") == 0)
    01546     set_density_parameter(v, description, STP_ECOLOR_K);
    01547   else if (strcmp(name, "RedDensity") == 0)
    01548     set_density_parameter(v, description, XCOLOR_R);
    01549   else if (strcmp(name, "BlueDensity") == 0)
    01550     set_density_parameter(v, description, XCOLOR_B);
    01551   else if (strcmp(name, "GlossDensity") == 0)
    01552     set_density_parameter(v, description, XCOLOR_GLOSS);
    01553   else if (strcmp(name, "GrayTransition") == 0)
    01554     set_gray_transition_parameter(v, description, 2);
    01555   else if (strcmp(name, "Gray1Transition") == 0 ||
    01556            strcmp(name, "Gray2Transition") == 0 ||
    01557            strcmp(name, "Gray3Transition") == 0)
    01558     set_gray_transition_parameter(v, description, 4);
    01559   else if (strcmp(name, "LightCyanTransition") == 0)
    01560     set_color_transition_parameter(v, description, STP_ECOLOR_C);
    01561   else if (strcmp(name, "LightMagentaTransition") == 0)
    01562     set_color_transition_parameter(v, description, STP_ECOLOR_M);
    01563   else if (strcmp(name, "DarkYellowTransition") == 0)
    01564     set_color_transition_parameter(v, description, STP_ECOLOR_Y);
    01565   else if (strcmp(name, "AlignmentPasses") == 0)
    01566     {
    01567       description->deflt.integer = escp2_alignment_passes(v);
    01568     }
    01569   else if (strcmp(name, "AlignmentChoices") == 0)
    01570     {
    01571       description->deflt.integer = escp2_alignment_choices(v);
    01572     }
    01573   else if (strcmp(name, "SupportsInkChange") == 0)
    01574     {
    01575       description->deflt.integer =
    01576         escp2_has_cap(v, MODEL_SUPPORTS_INK_CHANGE,
    01577                       MODEL_SUPPORTS_INK_CHANGE_YES);
    01578     }
    01579   else if (strcmp(name, "AlternateAlignmentPasses") == 0)
    01580     {
    01581       description->deflt.integer = escp2_alternate_alignment_passes(v);
    01582     }
    01583   else if (strcmp(name, "AlternateAlignmentChoices") == 0)
    01584     {
    01585       description->deflt.integer = escp2_alternate_alignment_choices(v);
    01586     }
    01587   else if (strcmp(name, "InkChannels") == 0)
    01588     {
    01589       description->deflt.integer = escp2_physical_channels(v);
    01590     }
    01591   else if (strcmp(name, "SupportsPacketMode") == 0)
    01592     {
    01593       description->deflt.integer =
    01594         escp2_has_cap(v, MODEL_PACKET_MODE, MODEL_PACKET_MODE_YES);
    01595     }
    01596   else if (strcmp(name, "PrintingMode") == 0)
    01597     {
    01598       description->bounds.str = stp_string_list_create();
    01599       stp_string_list_add_string
    01600         (description->bounds.str, "Color", _("Color"));
    01601       stp_string_list_add_string
    01602         (description->bounds.str, "BW", _("Black and White"));
    01603       description->deflt.str =
    01604         stp_string_list_param(description->bounds.str, 0)->name;
    01605     }
    01606   else if (strcmp(name, "RawChannels") == 0)
    01607     {
    01608       const inklist_t *inks = escp2_inklist(v);
    01609       int ninktypes = inks->n_inks;
    01610       description->bounds.str = stp_string_list_create();
    01611       if (ninktypes > 1)
    01612         {
    01613           stp_string_list_add_string(description->bounds.str, "None", "None");
    01614           for (i = 0; i < ninktypes; i++)
    01615             if (inks->inknames[i]->inkset == INKSET_EXTENDED)
    01616               {
    01617                 const channel_count_t *ch =
    01618                   (get_channel_count_by_number
    01619                    (inks->inknames[i]->channel_set->channel_count));
    01620                 stp_string_list_add_string(description->bounds.str,
    01621                                            ch->name, ch->name);
    01622               }
    01623           description->deflt.str =
    01624             stp_string_list_param(description->bounds.str, 0)->name;
    01625         }
    01626       if (ninktypes <= 1)
    01627         description->is_active = 0;
    01628     }
    01629 }
    01630
    01631 static const res_t *
    01632 escp2_find_resolution(const stp_vars_t *v)
    01633 {
    01634   const char *resolution;
    01635   if (stp_check_string_parameter(v, "Quality", STP_PARAMETER_ACTIVE))
    01636     {
    01637       const res_t *default_res =
    01638         find_resolution_from_quality(v, stp_get_string_parameter(v, "Quality"),
    01639                                      0);
    01640       if (default_res)
    01641         {
    01642           stp_dprintf(STP_DBG_ESCP2, v,
    01643                       "Setting resolution to %s from quality %s\n",
    01644                       default_res->name,
    01645                       stp_get_string_parameter(v, "Quality"));
    01646           return default_res;
    01647         }
    01648       else
    01649         stp_dprintf(STP_DBG_ESCP2, v, "Unable to map quality %s\n",
    01650                     stp_get_string_parameter(v, "Quality"));
    01651     }
    01652   resolution = stp_get_string_parameter(v, "Resolution");
    01653   if (resolution)
    01654     {
    01655       const res_t *const *res = escp2_reslist(v);
    01656       int i = 0;
    01657       while (res[i])
    01658         {
    01659           if (!strcmp(resolution, res[i]->name))
    01660             return res[i];
    01661           else if (!strcmp(res[i]->name, ""))
    01662             return NULL;
    01663           i++;
    01664         }
    01665     }
    01666   return NULL;
    01667 }
    01668
    01669 static inline int
    01670 imax(int a, int b)
    01671 {
    01672   if (a > b)
    01673     return a;
    01674   else
    01675     return b;
    01676 }
    01677
    01678 static void
    01679 internal_imageable_area(const stp_vars_t *v, int use_paper_margins,
    01680                         int *left, int *right, int *bottom, int *top)
    01681 {
    01682   int   width, height;                  /* Size of page */
    01683   int   rollfeed = 0;                   /* Roll feed selected */
    01684   int   cd = 0;                 /* CD selected */
    01685   const char *media_size = stp_get_string_parameter(v, "PageSize");
    01686   int left_margin = 0;
    01687   int right_margin = 0;
    01688   int bottom_margin = 0;
    01689   int top_margin = 0;
    01690   const stp_papersize_t *pt = NULL;
    01691   const input_slot_t *input_slot = NULL;
    01692
    01693   if (media_size && use_paper_margins)
    01694     pt = stp_get_papersize_by_name(media_size);
    01695
    01696   input_slot = get_input_slot(v);
    01697   if (input_slot)
    01698     {
    01699       cd = input_slot->is_cd;
    01700       rollfeed = input_slot->is_roll_feed;
    01701     }
    01702
    01703   stp_default_media_size(v, &width, &height);
    01704   if (cd)
    01705     {
    01706       left_margin = 0;
    01707       right_margin = 0;
    01708       bottom_margin = 0;
    01709       top_margin = 0;
    01710     }
    01711   else
    01712     {
    01713       if (pt)
    01714         {
    01715           left_margin = pt->left;
    01716           right_margin = pt->right;
    01717           bottom_margin = pt->bottom;
    01718           top_margin = pt->top;
    01719         }
    01720
    01721       left_margin = imax(left_margin, escp2_left_margin(v, rollfeed));
    01722       right_margin = imax(right_margin, escp2_right_margin(v, rollfeed));
    01723       bottom_margin = imax(bottom_margin, escp2_bottom_margin(v, rollfeed));
    01724       top_margin = imax(top_margin, escp2_top_margin(v, rollfeed));
    01725     }
    01726   *left =       left_margin;
    01727   *right =      width - right_margin;
    01728   *top =        top_margin;
    01729   *bottom =     height - bottom_margin;
    01730   if (!cd &&
    01731       escp2_has_cap(v, MODEL_XZEROMARGIN, MODEL_XZEROMARGIN_YES) &&
    01732       stp_get_boolean_parameter(v, "FullBleed"))
    01733     {
    01734       *left -= 80 / (360 / 72); /* 80 per the Epson manual */
    01735       *right += 80 / (360 / 72);        /* 80 per the Epson manual */
    01736       *bottom += escp2_nozzles(v) * escp2_nozzle_separation(v) * 72 /
    01737         escp2_base_separation(v);
    01738     }
    01739 }
    01740
    01741 /*
    01742  * 'escp2_imageable_area()' - Return the imageable area of the page.
    01743  */
    01744
    01745 static void
    01746 escp2_imageable_area(const stp_vars_t *v,   /* I */
    01747                      int  *left,        /* O - Left position in points */
    01748                      int  *right,       /* O - Right position in points */
    01749                      int  *bottom,      /* O - Bottom position in points */
    01750                      int  *top)         /* O - Top position in points */
    01751 {
    01752   internal_imageable_area(v, 1, left, right, bottom, top);
    01753 }
    01754
    01755 static void
    01756 escp2_limit(const stp_vars_t *v,                        /* I */
    01757             int *width, int *height,
    01758             int *min_width, int *min_height)
    01759 {
    01760   *width =      escp2_max_paper_width(v);
    01761   *height =     escp2_max_paper_height(v);
    01762   *min_width =  escp2_min_paper_width(v);
    01763   *min_height = escp2_min_paper_height(v);
    01764 }
    01765
    01766 static void
    01767 escp2_describe_resolution(const stp_vars_t *v, int *x, int *y)
    01768 {
    01769   const res_t *res = escp2_find_resolution(v);
    01770   if (res && verify_resolution(v, res))
    01771     {
    01772       *x = res->printed_hres;
    01773       *y = res->printed_vres;
    01774       return;
    01775     }
    01776   *x = -1;
    01777   *y = -1;
    01778 }
    01779
    01780 static const char *
    01781 escp2_describe_output(const stp_vars_t *v)
    01782 {
    01783   const char *printing_mode = stp_get_string_parameter(v, "PrintingMode");
    01784   const char *input_image_type = stp_get_string_parameter(v, "InputImageType");
    01785   if (input_image_type && strcmp(input_image_type, "Raw") == 0)
    01786     return "Raw";
    01787   else if (printing_mode && strcmp(printing_mode, "BW") == 0)
    01788     return "Grayscale";
    01789   else
    01790     {
    01791       const escp2_inkname_t *ink_type = get_inktype(v);
    01792       if (ink_type)
    01793         {
    01794           switch (ink_type->inkset)
    01795             {
    01796             case INKSET_CMYKRB:
    01797               return "CMYKRB";
    01798             case INKSET_CMYK:
    01799             case INKSET_CcMmYK:
    01800             case INKSET_CcMmYyK:
    01801             case INKSET_CcMmYKk:
    01802             default:
    01803               if (ink_type->channel_set->channels[0])
    01804                 return "KCMY";
    01805               else
    01806                 return "CMY";
    01807               break;
    01808             }
    01809         }
    01810       else
    01811         return "CMYK";
    01812     }
    01813 }
    01814
    01815 static int
    01816 escp2_has_advanced_command_set(const stp_vars_t *v)
    01817 {
    01818   return (escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_PRO) ||
    01819           escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_1999) ||
    01820           escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_2000));
    01821 }
    01822
    01823 static int
    01824 escp2_use_extended_commands(const stp_vars_t *v, int use_softweave)
    01825 {
    01826   return (escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_PRO) ||
    01827           (escp2_has_cap(v, MODEL_VARIABLE_DOT, MODEL_VARIABLE_YES) &&
    01828            use_softweave));
    01829 }
    01830
    01831 static int
    01832 set_raw_ink_type(stp_vars_t *v)
    01833 {
    01834   const inklist_t *inks = escp2_inklist(v);
    01835   int ninktypes = inks->n_inks;
    01836   int i;
    01837   const char *channel_name = stp_get_string_parameter(v, "RawChannels");
    01838   const channel_count_t *count;
    01839   if (!channel_name)
    01840     return 0;
    01841   count = get_channel_count_by_name(channel_name);
    01842   if (!count)
    01843     return 0;
    01844
    01845   /*
    01846    * If we're using raw printer output, we dummy up the appropriate inkset.
    01847    */
    01848   for (i = 0; i < ninktypes; i++)
    01849     if (inks->inknames[i]->inkset == INKSET_EXTENDED &&
    01850         (inks->inknames[i]->channel_set->channel_count == count->count))
    01851       {
    01852         stp_dprintf(STP_DBG_INK, v, "Changing ink type from %s to %s\n",
    01853                     stp_get_string_parameter(v, "InkType") ?
    01854                     stp_get_string_parameter(v, "InkType") : "NULL",
    01855                     inks->inknames[i]->name);
    01856         stp_set_string_parameter(v, "InkType", inks->inknames[i]->name);
    01857         stp_set_int_parameter(v, "STPIRawChannels", count->count);
    01858         return 1;
    01859       }
    01860   stp_eprintf
    01861     (v, _("This printer does not support raw printer output at depth %d\n"),
    01862      count->count);
    01863   return 0;
    01864 }
    01865
    01866 static void
    01867 adjust_density_and_ink_type(stp_vars_t *v, stp_image_t *image)
    01868 {
    01869   escp2_privdata_t *pd = get_privdata(v);
    01870   const paper_adjustment_t *pt = pd->paper_adjustment;
    01871   double paper_density = .8;
    01872   int o_resid = compute_printed_resid(pd->res);
    01873
    01874   if (pt)
    01875     paper_density = pt->base_density;
    01876
    01877   if (!stp_check_float_parameter(v, "Density", STP_PARAMETER_DEFAULTED))
    01878     {
    01879       stp_set_float_parameter_active(v, "Density", STP_PARAMETER_ACTIVE);
    01880       stp_set_float_parameter(v, "Density", 1.0);
    01881     }
    01882
    01883   stp_scale_float_parameter
    01884     (v, "Density", paper_density * escp2_density(v, o_resid));
    01885   pd->drop_size = escp2_ink_type(v, o_resid);
    01886   pd->ink_resid = o_resid;
    01887
    01888   /*
    01889    * If density is greater than 1, try to find the dot size from a lower
    01890    * resolution that will let us print.  This allows use of high ink levels
    01891    * on special paper types that need a lot of ink.
    01892    */
    01893   if (stp_get_float_parameter(v, "Density") > 1.0)
    01894     {
    01895       if (stp_check_int_parameter(v, "escp2_ink_type", STP_PARAMETER_ACTIVE) ||
    01896           stp_check_int_parameter(v, "escp2_density", STP_PARAMETER_ACTIVE) ||
    01897           stp_check_int_parameter(v, "escp2_bits", STP_PARAMETER_ACTIVE) ||
    01898           (stp_check_boolean_parameter(v, "AdjustDotsize",
    01899                                        STP_PARAMETER_ACTIVE) &&
    01900            ! stp_get_boolean_parameter(v, "AdjustDotsize")))
    01901         {
    01902           stp_set_float_parameter(v, "Density", 1.0);
    01903         }
    01904       else
    01905         {
    01906           double density = stp_get_float_parameter(v, "Density");
    01907           int resid = o_resid;
    01908           int xresid = resid;
    01909           double xdensity = density;
    01910           while (density > 1.0 && resid >= RES_360)
    01911             {
    01912               int tresid = xresid - 1;
    01913               int bits_now = escp2_bits(v, resid);
    01914               double density_now = escp2_density(v, resid);
    01915               int bits_then = escp2_bits(v, tresid);
    01916               double density_then = escp2_density(v, tresid);
    01917               int drop_size_then = escp2_ink_type(v, tresid);
    01918
    01919               /*
    01920                * If we would change the number of bits in the ink type,
    01921                * don't try this.  Some resolutions require using a certain
    01922                * number of bits!
    01923                */
    01924
    01925               if (bits_now != bits_then || density_then <= 0.0 ||
    01926                   drop_size_then == -1)
    01927                 break;
    01928               xdensity = density * density_then / density_now / 2;
    01929               xresid = tresid;
    01930
    01931               /*
    01932                * If we wouldn't get a significant improvement by changing the
    01933                * resolution, don't waste the effort trying.
    01934                */
    01935               if (density / xdensity > 1.001)
    01936                 {
    01937                   density = xdensity;
    01938                   resid = tresid;
    01939                 }
    01940             }
    01941           pd->drop_size = escp2_ink_type(v, resid);
    01942           pd->ink_resid = resid;
    01943           if (density > 1.0)
    01944             density = 1.0;
    01945           stp_set_float_parameter(v, "Density", density);
    01946         }
    01947     }
    01948 }
    01949
    01950 static void
    01951 adjust_print_quality(stp_vars_t *v, stp_image_t *image)
    01952 {
    01953   escp2_privdata_t *pd = get_privdata(v);
    01954   stp_curve_t *adjustment = NULL;
    01955   const paper_adjustment_t *pt;
    01956   double k_upper = 1.0;
    01957   double k_lower = 0;
    01958   double k_transition = 1.0;
    01959
    01960   /*
    01961    * Compute the LUT.  For now, it's 8 bit, but that may eventually
    01962    * sometimes change.
    01963    */
    01964
    01965   pt = pd->paper_adjustment;
    01966   if (pt)
    01967     {
    01968       k_lower = pt->k_lower;
    01969       k_upper = pt->k_upper;
    01970       k_transition = pt->k_transition;
    01971       stp_set_default_float_parameter(v, "CyanDensity", 1.0);
    01972       stp_scale_float_parameter(v, "CyanDensity", pt->cyan);
    01973       stp_set_default_float_parameter(v, "MagentaDensity", 1.0);
    01974       stp_scale_float_parameter(v, "MagentaDensity", pt->magenta);
    01975       stp_set_default_float_parameter(v, "YellowDensity", 1.0);
    01976       stp_scale_float_parameter(v, "YellowDensity", pt->yellow);
    01977       stp_set_default_float_parameter(v, "BlackDensity", 1.0);
    01978       stp_scale_float_parameter(v, "BlackDensity", pt->black);
    01979       stp_set_default_float_parameter(v, "Saturation", 1.0);
    01980       stp_scale_float_parameter(v, "Saturation", pt->saturation);
    01981       stp_set_default_float_parameter(v, "Gamma", 1.0);
    01982       stp_scale_float_parameter(v, "Gamma", pt->gamma);
    01983     }
    01984
    01985
    01986   if (!stp_check_float_parameter(v, "GCRLower", STP_PARAMETER_ACTIVE))
    01987     stp_set_default_float_parameter(v, "GCRLower", k_lower);
    01988   if (!stp_check_float_parameter(v, "GCRUpper", STP_PARAMETER_ACTIVE))
    01989     stp_set_default_float_parameter(v, "GCRUpper", k_upper);
    01990   if (!stp_check_float_parameter(v, "BlackGamma", STP_PARAMETER_ACTIVE))
    01991     stp_set_default_float_parameter(v, "BlackGamma", k_transition);
    01992
    01993
    01994   if (!stp_check_curve_parameter(v, "HueMap", STP_PARAMETER_ACTIVE) &&
    01995       pt->hue_adjustment)
    01996     {
    01997       adjustment = stp_curve_create_from_string(pt->hue_adjustment);
    01998       stp_set_curve_parameter(v, "HueMap", adjustment);
    01999       stp_set_curve_parameter_active(v, "HueMap", STP_PARAMETER_ACTIVE);
    02000       stp_curve_destroy(adjustment);
    02001     }
    02002   if (!stp_check_curve_parameter(v, "SatMap", STP_PARAMETER_ACTIVE) &&
    02003       pt->sat_adjustment)
    02004     {
    02005       adjustment = stp_curve_create_from_string(pt->sat_adjustment);
    02006       stp_set_curve_parameter(v, "SatMap", adjustment);
    02007       stp_set_curve_parameter_active(v, "SatMap", STP_PARAMETER_ACTIVE);
    02008       stp_curve_destroy(adjustment);
    02009     }
    02010   if (!stp_check_curve_parameter(v, "LumMap", STP_PARAMETER_ACTIVE) &&
    02011       pt->lum_adjustment)
    02012     {
    02013       adjustment = stp_curve_create_from_string(pt->lum_adjustment);
    02014       stp_set_curve_parameter(v, "LumMap", adjustment);
    02015       stp_set_curve_parameter_active(v, "LumMap", STP_PARAMETER_ACTIVE);
    02016       stp_curve_destroy(adjustment);
    02017     }
    02018 }
    02019
    02020 static int
    02021 count_channels(const escp2_inkname_t *inks)
    02022 {
    02023   int answer = 0;
    02024   int i;
    02025   for (i = 0; i < inks->channel_set->channel_count; i++)
    02026     if (inks->channel_set->channels[i])
    02027       answer += inks->channel_set->channels[i]->n_subchannels;
    02028   return answer;
    02029 }
    02030
    02031 static int
    02032 compute_channel_count(const escp2_inkname_t *ink_type, int channel_limit)
    02033 {
    02034   int i;
    02035   int physical_channels = 0;
    02036   for (i = 0; i < channel_limit; i++)
    02037     {
    02038       const ink_channel_t *channel = ink_type->channel_set->channels[i];
    02039       if (channel)
    02040         physical_channels += channel->n_subchannels;
    02041     }
    02042   return physical_channels;
    02043 }
    02044
    02045 static double
    02046 get_double_param(const stp_vars_t *v, const char *param)
    02047 {
    02048   if (param && stp_check_float_parameter(v, param, STP_PARAMETER_ACTIVE))
    02049     return stp_get_float_parameter(v, param);
    02050   else
    02051     return 1.0;
    02052 }
    02053
    02054 static void
    02055 setup_inks(stp_vars_t *v)
    02056 {
    02057   escp2_privdata_t *pd = get_privdata(v);
    02058   int i, j;
    02059   const escp2_dropsize_t *drops;
    02060   const escp2_inkname_t *ink_type = pd->inkname;
    02061   const paper_adjustment_t *paper = pd->paper_adjustment;
    02062
    02063   drops = escp2_dropsizes(v, pd->ink_resid);
    02064   stp_init_debug_messages(v);
    02065   for (i = 0; i < pd->logical_channels; i++)
    02066     {
    02067       const ink_channel_t *channel = ink_type->channel_set->channels[i];
    02068       if (channel && channel->n_subchannels > 0)
    02069         {
    02070           const char *param = channel->subchannels[0].channel_density;
    02071           const shade_t *shades = escp2_shades(v, i);
    02072           double userval = get_double_param(v, param);
    02073           if (shades->n_shades < channel->n_subchannels)
    02074             {
    02075               stp_erprintf("Not enough shades!\n");
    02076             }
    02077           if (strcmp(param, "BlackDensity") == 0)
    02078             stp_channel_set_black_channel(v, i);
    02079           stp_dither_set_inks(v, i, 1.0, ink_darknesses[i % 8],
    02080                               channel->n_subchannels, shades->shades,
    02081                               drops->numdropsizes, drops->dropsizes);
    02082           for (j = 0; j < channel->n_subchannels; j++)
    02083             {
    02084               const char *subparam =
    02085                 channel->subchannels[j].subchannel_scale;
    02086               double scale = userval * get_double_param(v, subparam);
    02087               scale *= get_double_param(v, "Density");
    02088               stp_channel_set_density_adjustment(v, i, j, scale);
    02089               if (paper)
    02090                 stp_channel_set_cutoff_adjustment(v, i, j,
    02091                                                   paper->subchannel_cutoff);
    02092             }
    02093         }
    02094     }
    02095   stp_flush_debug_messages(v);
    02096 }
    02097
    02098 static void
    02099 setup_head_offset(stp_vars_t *v)
    02100 {
    02101   escp2_privdata_t *pd = get_privdata(v);
    02102   int i;
    02103   int channel_id = 0;
    02104   int channel_limit = pd->logical_channels;
    02105   const escp2_inkname_t *ink_type = pd->inkname;
    02106   if (pd->channels_in_use > pd->logical_channels)
    02107     channel_limit = pd->channels_in_use;
    02108   pd->head_offset = stp_zalloc(sizeof(int) * channel_limit);
    02109   for (i = 0; i < pd->logical_channels; i++)
    02110     {
    02111       const ink_channel_t *channel = ink_type->channel_set->channels[i];
    02112       if (channel)
    02113         {
    02114           int j;
    02115           for (j = 0; j < channel->n_subchannels; j++)
    02116             {
    02117               pd->head_offset[channel_id] =
    02118                 channel->subchannels[j].head_offset;
    02119               channel_id++;
    02120             }
    02121         }
    02122     }
    02123   if (pd->physical_channels == 1)
    02124     pd->head_offset[0] = 0;
    02125   pd->max_head_offset = 0;
    02126   if (pd->physical_channels > 1)
    02127     for (i = 0; i < pd->channels_in_use; i++)
    02128       {
    02129         pd->head_offset[i] = pd->head_offset[i] * pd->res->vres /
    02130           escp2_base_separation(v);
    02131         if (pd->head_offset[i] > pd->max_head_offset)
    02132           pd->max_head_offset = pd->head_offset[i];
    02133       }
    02134 }
    02135
    02136 static void
    02137 setup_misc(stp_vars_t *v)
    02138 {
    02139   escp2_privdata_t *pd = get_privdata(v);
    02140   pd->input_slot = get_input_slot(v);
    02141   pd->paper_type = get_media_type(v);
    02142   pd->paper_adjustment = get_media_adjustment(v);
    02143   pd->ink_group = escp2_inkgroup(v);
    02144   pd->init_sequence = escp2_preinit_sequence(v);
    02145   pd->deinit_sequence = escp2_postinit_remote_sequence(v);
    02146   pd->advanced_command_set = escp2_has_advanced_command_set(v);
    02147   pd->command_set = escp2_get_cap(v, MODEL_COMMAND);
    02148   pd->variable_dots = escp2_has_cap(v, MODEL_VARIABLE_DOT, MODEL_VARIABLE_YES);
    02149   pd->has_vacuum = escp2_has_cap(v, MODEL_VACUUM, MODEL_VACUUM_YES);
    02150   pd->has_graymode = escp2_has_cap(v, MODEL_GRAYMODE, MODEL_GRAYMODE_YES);
    02151   pd->base_separation = escp2_base_separation(v);
    02152   pd->resolution_scale = escp2_resolution_scale(v);
    02153   pd->use_extended_commands =
    02154     escp2_use_extended_commands(v, pd->res->softweave);
    02155 }
    02156
    02157 static void
    02158 allocate_channels(stp_vars_t *v, int line_length)
    02159 {
    02160   escp2_privdata_t *pd = get_privdata(v);
    02161   const escp2_inkname_t *ink_type = pd->inkname;
    02162   int i;
    02163   int channel_id = 0;
    02164
    02165   pd->cols = stp_zalloc(sizeof(unsigned char *) * pd->channels_in_use);
    02166   pd->channels =
    02167     stp_zalloc(sizeof(physical_subchannel_t *) * pd->channels_in_use);
    02168
    02169   for (i = 0; i < pd->logical_channels; i++)
    02170     {
    02171       const ink_channel_t *channel = ink_type->channel_set->channels[i];
    02172       if (channel)
    02173         {
    02174           int j;
    02175           for (j = 0; j < channel->n_subchannels; j++)
    02176             {
    02177               pd->cols[channel_id] = stp_zalloc(line_length);
    02178               pd->channels[channel_id] = &(channel->subchannels[j]);
    02179               stp_dither_add_channel(v, pd->cols[channel_id], i, j);
    02180               channel_id++;
    02181             }
    02182         }
    02183     }
    02184   stp_set_string_parameter(v, "STPIOutputType", escp2_describe_output(v));
    02185 }
    02186
    02187 static unsigned
    02188 gcd(unsigned a, unsigned b)
    02189 {
    02190   unsigned tmp;
    02191   if (b > a)
    02192     {
    02193       tmp = a;
    02194       a = b;
    02195       b = tmp;
    02196     }
    02197   while (1)
    02198     {
    02199       tmp = a % b;
    02200       if (tmp == 0)
    02201         return b;
    02202       a = b;
    02203       b = tmp;
    02204     }
    02205 }
    02206
    02207 static unsigned
    02208 lcm(unsigned a, unsigned b)
    02209 {
    02210   if (a == b)
    02211     return a;
    02212   else
    02213     return a * b / gcd(a, b);
    02214 }
    02215
    02216 static int
    02217 adjusted_vertical_resolution(const res_t *res)
    02218 {
    02219   if (res->vres >= 720)
    02220     return res->vres;
    02221   else if (res->hres >= 720)    /* Special case 720x360 */
    02222     return 720;
    02223   else if (res->vres % 90 == 0)
    02224     return res->vres;
    02225   else
    02226     return lcm(res->hres, res->vres);
    02227 }
    02228
    02229 static int
    02230 adjusted_horizontal_resolution(const res_t *res)
    02231 {
    02232   if (res->vres % 90 == 0)
    02233     return res->hres;
    02234   else
    02235     return lcm(res->hres, res->vres);
    02236 }
    02237
    02238 static void
    02239 setup_resolution(stp_vars_t *v)
    02240 {
    02241   escp2_privdata_t *pd = get_privdata(v);
    02242   const res_t *res = escp2_find_resolution(v);
    02243   int resid = compute_resid(res);
    02244
    02245   int vertical = adjusted_vertical_resolution(res);
    02246   int horizontal = adjusted_horizontal_resolution(res);
    02247
    02248   pd->res = res;
    02249   pd->physical_xdpi = escp2_base_res(v, resid);
    02250   if (pd->physical_xdpi > pd->res->hres)
    02251     pd->physical_xdpi = pd->res->hres;
    02252
    02253   if (escp2_use_extended_commands(v, pd->res->softweave))
    02254     {
    02255       pd->unit_scale = escp2_max_hres(v);
    02256       pd->horizontal_units = horizontal;
    02257       pd->micro_units = horizontal;
    02258     }
    02259   else
    02260     {
    02261       pd->unit_scale = 3600;
    02262       if (pd->res->hres <= 720)
    02263         pd->micro_units = vertical;
    02264       else
    02265         pd->micro_units = horizontal;
    02266       pd->horizontal_units = vertical;
    02267     }
    02268   if (escp2_has_cap(v, MODEL_COMMAND, MODEL_COMMAND_1999) &&
    02269       escp2_has_cap(v, MODEL_VARIABLE_DOT, MODEL_VARIABLE_NO))
    02270     pd->micro_units = 1440;
    02271   pd->vertical_units = vertical;
    02272   pd->page_management_units = vertical;
    02273   pd->printing_resolution = escp2_base_res(v, resid);
    02274 }
    02275
    02276 static void
    02277 setup_softweave_parameters(stp_vars_t *v)
    02278 {
    02279   escp2_privdata_t *pd = get_privdata(v);
    02280   pd->horizontal_passes = pd->res->printed_hres / pd->physical_xdpi;
    02281   if (pd->physical_channels == 1 &&
    02282       (pd->res->vres >=
    02283        (escp2_base_separation(v) / escp2_black_nozzle_separation(v))) &&
    02284       (escp2_max_black_resolution(v) < 0 ||
    02285        pd->res->vres <= escp2_max_black_resolution(v)) &&
    02286       escp2_black_nozzles(v))
    02287     pd->use_black_parameters = 1;
    02288   else
    02289     pd->use_black_parameters = 0;
    02290   if (pd->use_fast_360)
    02291     {
    02292       pd->nozzles = escp2_fast_nozzles(v);
    02293       pd->nozzle_separation = escp2_fast_nozzle_separation(v);
    02294       pd->min_nozzles = escp2_min_fast_nozzles(v);
    02295     }
    02296   else if (pd->use_black_parameters)
    02297     {
    02298       pd->nozzles = escp2_black_nozzles(v);
    02299       pd->nozzle_separation = escp2_black_nozzle_separation(v);
    02300       pd->min_nozzles = escp2_min_black_nozzles(v);
    02301     }
    02302   else
    02303     {
    02304       pd->nozzles = escp2_nozzles(v);
    02305       pd->nozzle_separation = escp2_nozzle_separation(v);
    02306       pd->min_nozzles = escp2_min_nozzles(v);
    02307     }
    02308 }
    02309
    02310 static void
    02311 setup_printer_weave_parameters(stp_vars_t *v)
    02312 {
    02313   escp2_privdata_t *pd = get_privdata(v);
    02314   pd->horizontal_passes = 1;
    02315   pd->nozzles = 1;
    02316   pd->nozzle_separation = 1;
    02317   pd->min_nozzles = 1;
    02318   pd->use_black_parameters = 0;
    02319 }
    02320
    02321 static void
    02322 setup_head_parameters(stp_vars_t *v)
    02323 {
    02324   escp2_privdata_t *pd = get_privdata(v);
    02325   /*
    02326    * Set up the output channels
    02327    */
    02328   if (strcmp(stp_get_string_parameter(v, "PrintingMode"), "BW") == 0)
    02329     pd->logical_channels = 1;
    02330   else
    02331     pd->logical_channels = pd->inkname->channel_set->channel_count;
    02332
    02333   pd->physical_channels =
    02334     compute_channel_count(pd->inkname, pd->logical_channels);
    02335   if (pd->physical_channels == 0)
    02336     {
    02337       pd->inkname = &stpi_escp2_default_black_inkset;
    02338       pd->physical_channels =
    02339         compute_channel_count(pd->inkname, pd->logical_channels);
    02340     }
    02341
    02342   pd->use_printer_weave = use_printer_weave(v);
    02343   if (pd->use_printer_weave)
    02344     {
    02345       pd->printer_weave = get_printer_weave(v);
    02346       if (pd->res->softweave && pd->printer_weave && pd->printer_weave->value == 0)
    02347         pd->printer_weave = NULL;
    02348     }
    02349
    02350
    02351   if (escp2_has_cap(v, MODEL_FAST_360, MODEL_FAST_360_YES) &&
    02352       (pd->inkname->inkset == INKSET_CMYK || pd->physical_channels == 1) &&
    02353       pd->res->hres == pd->physical_xdpi && pd->res->vres == 360)
    02354     pd->use_fast_360 = 1;
    02355   else
    02356     pd->use_fast_360 = 0;
    02357
    02358   /*
    02359    * Set up the printer-specific parameters (weaving)
    02360    */
    02361   if (pd->use_printer_weave)
    02362     setup_printer_weave_parameters(v);
    02363   else
    02364     setup_softweave_parameters(v);
    02365   pd->separation_rows = escp2_separation_rows(v);
    02366   pd->pseudo_separation_rows = escp2_pseudo_separation_rows(v);
    02367   pd->extra_720dpi_separation = escp2_extra_720dpi_separation(v);
    02368
    02369   if (pd->horizontal_passes == 0)
    02370     pd->horizontal_passes = 1;
    02371
    02372   setup_head_offset(v);
    02373
    02374   if (strcmp(stp_get_string_parameter(v, "PrintingMode"), "BW") == 0 &&
    02375       pd->physical_channels == 1)
    02376     {
    02377       if (pd->use_black_parameters)
    02378         pd->initial_vertical_offset =
    02379           escp2_black_initial_vertical_offset(v) * pd->page_management_units /
    02380           escp2_base_separation(v);
    02381       else
    02382         pd->initial_vertical_offset = pd->head_offset[0] +
    02383           (escp2_initial_vertical_offset(v) *
    02384            pd->page_management_units / escp2_base_separation(v));
    02385     }
    02386   else
    02387     pd->initial_vertical_offset =
    02388       escp2_initial_vertical_offset(v) * pd->page_management_units /
    02389       escp2_base_separation(v);
    02390
    02391   pd->printing_initial_vertical_offset = 0;
    02392   pd->bitwidth = escp2_bits(v, compute_printed_resid(pd->res));
    02393 }
    02394
    02395 static void
    02396 setup_page(stp_vars_t *v)
    02397 {
    02398   int n;
    02399   escp2_privdata_t *pd = get_privdata(v);
    02400   const input_slot_t *input_slot = get_input_slot(v);
    02401   int extra_left = 0;
    02402   int extra_top = 0;
    02403   const char *inner_radius_name = stp_get_string_parameter(v, "CDInnerRadius");
    02404   int hub_size = 43;            /* 43 mm standard CD hub */
    02405
    02406   if (inner_radius_name && strcmp(inner_radius_name, "Small") == 0)
    02407     hub_size = 16;              /* 15 mm prints to the hole - play it
    02408                                    safe and print 16 mm */
    02409
    02410   stp_default_media_size(v, &n, &(pd->page_true_height));
    02411   internal_imageable_area(v, 0, &pd->page_left, &pd->page_right,
    02412                           &pd->page_bottom, &pd->page_top);
    02413
    02414   if (input_slot && input_slot->is_cd && escp2_cd_x_offset(v) > 0)
    02415     {
    02416       int left_center = escp2_cd_x_offset(v) +
    02417         stp_get_dimension_parameter(v, "CDXAdjustment");
    02418       int top_center = escp2_cd_y_offset(v) +
    02419         stp_get_dimension_parameter(v, "CDYAdjustment");
    02420       extra_top = top_center - (pd->page_bottom / 2);
    02421       extra_left = left_center - (pd->page_right / 2);
    02422       pd->cd_inner_radius = hub_size * pd->micro_units * 10 / 254 / 2;
    02423       pd->cd_outer_radius = pd->page_right * pd->micro_units / 72 / 2;
    02424       pd->cd_x_offset =
    02425         ((pd->page_right / 2) - stp_get_left(v)) * pd->micro_units / 72;
    02426       pd->cd_y_offset =
    02427         ((pd->page_bottom / 2) - stp_get_top(v)) * pd->micro_units / 72;
    02428       if (escp2_cd_page_height(v))
    02429         {
    02430           pd->page_right = escp2_cd_page_width(v);
    02431           pd->page_bottom = escp2_cd_page_height(v);
    02432           pd->page_true_height = escp2_cd_page_height(v);
    02433         }
    02434     }
    02435
    02436   pd->page_right += extra_left + 1;
    02437   pd->page_width = pd->page_right - pd->page_left;
    02438   pd->image_left = stp_get_left(v) - pd->page_left + extra_left;
    02439   pd->image_width = stp_get_width(v);
    02440   pd->image_scaled_width = pd->image_width * pd->res->hres / 72;
    02441   pd->image_printed_width = pd->image_width * pd->res->printed_hres / 72;
    02442   pd->image_left_position = pd->image_left * pd->micro_units / 72;
    02443
    02444
    02445   pd->page_bottom += extra_top + 1;
    02446   pd->page_true_height += extra_top + 1;
    02447   pd->page_height = pd->page_bottom - pd->page_top;
    02448   pd->image_top = stp_get_top(v) - pd->page_top + extra_top;
    02449   pd->image_height = stp_get_height(v);
    02450   pd->image_scaled_height = pd->image_height * pd->res->vres / 72;
    02451   pd->image_printed_height = pd->image_height * pd->res->printed_vres / 72;
    02452
    02453   if (input_slot && input_slot->roll_feed_cut_flags)
    02454     {
    02455       pd->page_true_height += 4; /* Empirically-determined constants */
    02456       pd->page_top += 2;
    02457       pd->page_bottom += 2;
    02458       pd->image_top += 2;
    02459       pd->page_height += 2;
    02460     }
    02461 }
    02462
    02463 static void
    02464 set_mask(unsigned char *cd_mask, int x_center, int scaled_x_where,
    02465          int limit, int expansion, int invert)
    02466 {
    02467   int clear_val = invert ? 255 : 0;
    02468   int set_val = invert ? 0 : 255;
    02469   int bytesize = 8 / expansion;
    02470   int byteextra = bytesize - 1;
    02471   int first_x_on = x_center - scaled_x_where;
    02472   int first_x_off = x_center + scaled_x_where;
    02473   if (first_x_on < 0)
    02474     first_x_on = 0;
    02475   if (first_x_on > limit)
    02476     first_x_on = limit;
    02477   if (first_x_off < 0)
    02478     first_x_off = 0;
    02479   if (first_x_off > limit)
    02480     first_x_off = limit;
    02481   first_x_on += byteextra;
    02482   if (first_x_off > (first_x_on - byteextra))
    02483     {
    02484       int first_x_on_byte = first_x_on / bytesize;
    02485       int first_x_on_mod = expansion * (byteextra - (first_x_on % bytesize));
    02486       int first_x_on_extra = ((1 << first_x_on_mod) - 1) ^ clear_val;
    02487       int first_x_off_byte = first_x_off / bytesize;
    02488       int first_x_off_mod = expansion * (byteextra - (first_x_off % bytesize));
    02489       int first_x_off_extra = ((1 << 8) - (1 << first_x_off_mod)) ^ clear_val;
    02490       if (first_x_off_byte < first_x_on_byte)
    02491         {
    02492           /* This can happen, if 6 or fewer points are turned on */
    02493           cd_mask[first_x_on_byte] = first_x_on_extra & first_x_off_extra;
    02494         }
    02495       else
    02496         {
    02497           if (first_x_on_extra != clear_val)
    02498             cd_mask[first_x_on_byte - 1] = first_x_on_extra;
    02499           if (first_x_off_byte > first_x_on_byte)
    02500             memset(cd_mask + first_x_on_byte, set_val,
    02501                    first_x_off_byte - first_x_on_byte);
    02502           if (first_x_off_extra != clear_val)
    02503             cd_mask[first_x_off_byte] = first_x_off_extra;
    02504         }
    02505     }
    02506 }
    02507
    02508 static int
    02509 escp2_print_data(stp_vars_t *v, stp_image_t *image)
    02510 {
    02511   escp2_privdata_t *pd = get_privdata(v);
    02512   int errdiv  = stp_image_height(image) / pd->image_printed_height;
    02513   int errmod  = stp_image_height(image) % pd->image_printed_height;
    02514   int errval  = 0;
    02515   int errlast = -1;
    02516   int errline  = 0;
    02517   int y;
    02518   double outer_r_sq = 0;
    02519   double inner_r_sq = 0;
    02520   int x_center = pd->cd_x_offset * pd->res->printed_hres / pd->micro_units;
    02521   unsigned char *cd_mask = NULL;
    02522   if (pd->cd_outer_radius > 0)
    02523     {
    02524       cd_mask = stp_malloc(1 + (pd->image_printed_width + 7) / 8);
    02525       outer_r_sq = (double) pd->cd_outer_radius * (double) pd->cd_outer_radius;
    02526       inner_r_sq = (double) pd->cd_inner_radius * (double) pd->cd_inner_radius;
    02527     }
    02528
    02529   for (y = 0; y < pd->image_printed_height; y ++)
    02530     {
    02531       int duplicate_line = 1;
    02532       unsigned zero_mask;
    02533
    02534       if (errline != errlast)
    02535         {
    02536           errlast = errline;
    02537           duplicate_line = 0;
    02538           if (stp_color_get_row(v, image, errline, &zero_mask))
    02539             return 2;
    02540         }
    02541
    02542       if (cd_mask)
    02543         {
    02544           int y_distance_from_center =
    02545             pd->cd_outer_radius - (y * pd->micro_units / pd->res->printed_vres);
    02546           if (y_distance_from_center < 0)
    02547             y_distance_from_center = -y_distance_from_center;
    02548           memset(cd_mask, 0, (pd->image_printed_width + 7) / 8);
    02549           if (y_distance_from_center < pd->cd_outer_radius)
    02550             {
    02551               double y_sq = (double) y_distance_from_center *
    02552                 (double) y_distance_from_center;
    02553               int x_where = sqrt(outer_r_sq - y_sq) + .5;
    02554               int scaled_x_where = x_where * pd->res->printed_hres / pd->micro_units;
    02555               set_mask(cd_mask, x_center, scaled_x_where,
    02556                        pd->image_printed_width, 1, 0);
    02557               if (y_distance_from_center < pd->cd_inner_radius)
    02558                 {
    02559                   x_where = sqrt(inner_r_sq - y_sq) + .5;
    02560                   scaled_x_where = x_where * pd->res->printed_hres / pd->micro_units;
    02561                   set_mask(cd_mask, x_center, scaled_x_where,
    02562                            pd->image_printed_width, 1, 1);
    02563                 }
    02564             }
    02565         }
    02566
    02567       stp_dither(v, y, duplicate_line, zero_mask, cd_mask);
    02568
    02569       stp_write_weave(v, pd->cols);
    02570       errval += errmod;
    02571       errline += errdiv;
    02572       if (errval >= pd->image_printed_height)
    02573         {
    02574           errval -= pd->image_printed_height;
    02575           errline ++;
    02576         }
    02577     }
    02578   if (cd_mask)
    02579     stp_free(cd_mask);
    02580   return 1;
    02581 }
    02582
    02583 static int
    02584 escp2_print_page(stp_vars_t *v, stp_image_t *image)
    02585 {
    02586   int status;
    02587   int i;
    02588   escp2_privdata_t *pd = get_privdata(v);
    02589   int out_channels;             /* Output bytes per pixel */
    02590   int line_width = (pd->image_printed_width + 7) / 8 * pd->bitwidth;
    02591   int weave_pattern = STP_WEAVE_ZIGZAG;
    02592   if (stp_check_string_parameter(v, "Weave", STP_PARAMETER_ACTIVE))
    02593     {
    02594       const char *weave = stp_get_string_parameter(v, "Weave");
    02595       if (strcmp(weave, "Alternate") == 0)
    02596         weave_pattern = STP_WEAVE_ZIGZAG;
    02597       else if (strcmp(weave, "Ascending") == 0)
    02598         weave_pattern = STP_WEAVE_ASCENDING;
    02599       else if (strcmp(weave, "Descending") == 0)
    02600         weave_pattern = STP_WEAVE_DESCENDING;
    02601       else if (strcmp(weave, "Ascending2X") == 0)
    02602         weave_pattern = STP_WEAVE_ASCENDING_2X;
    02603       else if (strcmp(weave, "Staggered") == 0)
    02604         weave_pattern = STP_WEAVE_STAGGERED;
    02605     }
    02606
    02607   stp_initialize_weave
    02608     (v,
    02609      pd->nozzles,
    02610      pd->nozzle_separation * pd->res->vres / escp2_base_separation(v),
    02611      pd->horizontal_passes,
    02612      pd->res->vertical_passes,
    02613      1,
    02614      pd->channels_in_use,
    02615      pd->bitwidth,
    02616      pd->image_printed_width,
    02617      pd->image_printed_height,
    02618      pd->image_top * pd->res->vres / 72,
    02619      (pd->page_height + escp2_extra_feed(v)) * pd->res->vres / 72,
    02620      pd->head_offset,
    02621      weave_pattern,
    02622      stpi_escp2_flush_pass,
    02623      FILLFUNC,
    02624      PACKFUNC,
    02625      COMPUTEFUNC);
    02626
    02627   stp_dither_init(v, image, pd->image_printed_width, pd->res->printed_hres,
    02628                   pd->res->printed_vres);
    02629   allocate_channels(v, line_width);
    02630   adjust_print_quality(v, image);
    02631   out_channels = stp_color_init(v, image, 65536);
    02632
    02633 /*  stpi_dither_set_expansion(v, pd->res->hres / pd->res->printed_hres); */
    02634
    02635   setup_inks(v);
    02636
    02637   status = escp2_print_data(v, image);
    02638   stp_image_conclude(image);
    02639   stp_flush_all(v);
    02640   stpi_escp2_terminate_page(v);
    02641
    02642   /*
    02643    * Cleanup...
    02644    */
    02645   for (i = 0; i < pd->channels_in_use; i++)
    02646     if (pd->cols[i])
    02647       stp_free(pd->cols[i]);
    02648   stp_free(pd->cols);
    02649   stp_free(pd->channels);
    02650   return status;
    02651 }
    02652
    02653 /*
    02654  * 'escp2_print()' - Print an image to an EPSON printer.
    02655  */
    02656 static int
    02657 escp2_do_print(stp_vars_t *v, stp_image_t *image, int print_op)
    02658 {
    02659   int status = 1;
    02660
    02661   escp2_privdata_t *pd;
    02662
    02663   if (!stp_verify(v))
    02664     {
    02665       stp_eprintf(v, _("Print options not verified; cannot print.\n"));
    02666       return 0;
    02667     }
    02668   stp_image_init(image);
    02669
    02670   if (strcmp(stp_get_string_parameter(v, "InputImageType"), "Raw") == 0 &&
    02671       !set_raw_ink_type(v))
    02672     return 0;
    02673
    02674   pd = (escp2_privdata_t *) stp_zalloc(sizeof(escp2_privdata_t));
    02675   pd->printed_something = 0;
    02676   pd->last_color = -1;
    02677   pd->last_pass_offset = 0;
    02678   pd->last_pass = -1;
    02679   pd->send_zero_pass_advance =
    02680     escp2_has_cap(v, MODEL_SEND_ZERO_ADVANCE, MODEL_SEND_ZERO_ADVANCE_YES);
    02681   stp_allocate_component_data(v, "Driver", NULL, NULL, pd);
    02682
    02683   pd->inkname = get_inktype(v);
    02684   pd->channels_in_use = count_channels(pd->inkname);
    02685
    02686   setup_resolution(v);
    02687   setup_head_parameters(v);
    02688   setup_page(v);
    02689   setup_misc(v);
    02690
    02691   adjust_density_and_ink_type(v, image);
    02692   if (print_op & OP_JOB_START)
    02693     stpi_escp2_init_printer(v);
    02694   if (print_op & OP_JOB_PRINT)
    02695     status = escp2_print_page(v, image);
    02696   if (print_op & OP_JOB_END)
    02697     stpi_escp2_deinit_printer(v);
    02698
    02699   stp_free(pd->head_offset);
    02700   stp_free(pd);
    02701
    02702   return status;
    02703 }
    02704
    02705 static int
    02706 escp2_print(const stp_vars_t *v, stp_image_t *image)
    02707 {
    02708   stp_vars_t *nv = stp_vars_create_copy(v);
    02709   int op = OP_JOB_PRINT;
    02710   int status;
    02711   if (!stp_get_string_parameter(v, "JobMode") ||
    02712       strcmp(stp_get_string_parameter(v, "JobMode"), "Page") == 0)
    02713     op = OP_JOB_START | OP_JOB_PRINT | OP_JOB_END;
    02714   stp_prune_inactive_options(nv);
    02715   status = escp2_do_print(nv, image, op);
    02716   stp_vars_destroy(nv);
    02717   return status;
    02718 }
    02719
    02720 static int
    02721 escp2_job_start(const stp_vars_t *v, stp_image_t *image)
    02722 {
    02723   stp_vars_t *nv = stp_vars_create_copy(v);
    02724   int status;
    02725   stp_prune_inactive_options(nv);
    02726   status = escp2_do_print(nv, image, OP_JOB_START);
    02727   stp_vars_destroy(nv);
    02728   return status;
    02729 }
    02730
    02731 static int
    02732 escp2_job_end(const stp_vars_t *v, stp_image_t *image)
    02733 {
    02734   stp_vars_t *nv = stp_vars_create_copy(v);
    02735   int status;
    02736   stp_prune_inactive_options(nv);
    02737   status = escp2_do_print(nv, image, OP_JOB_END);
    02738   stp_vars_destroy(nv);
    02739   return status;
    02740 }
    02741
    02742 static const stp_printfuncs_t print_escp2_printfuncs =
    02743 {
    02744   escp2_list_parameters,
    02745   escp2_parameters,
    02746   stp_default_media_size,
    02747   escp2_imageable_area,
    02748   escp2_limit,
    02749   escp2_print,
    02750   escp2_describe_resolution,
    02751   escp2_describe_output,
    02752   stp_verify_printer_params,
    02753   escp2_job_start,
    02754   escp2_job_end
    02755 };
    02756
    02757 static stp_family_t print_escp2_module_data =
    02758   {
    02759     &print_escp2_printfuncs,
    02760     NULL
    02761   };
    02762
    02763
    02764 static int
    02765 print_escp2_module_init(void)
    02766 {
    02767   return stp_family_register(print_escp2_module_data.printer_list);
    02768 }
    02769
    02770
    02771 static int
    02772 print_escp2_module_exit(void)
    02773 {
    02774   return stp_family_unregister(print_escp2_module_data.printer_list);
    02775 }
    02776
    02777
    02778 /* Module header */
    02779 #define stp_module_version print_escp2_LTX_stp_module_version
    02780 #define stp_module_data print_escp2_LTX_stp_module_data
    02781
    02782 stp_module_version_t stp_module_version = {0, 0};
    02783
    02784 stp_module_t stp_module_data =
    02785   {
    02786     "escp2",
    02787     VERSION,
    02788     "Epson family driver",
    02789     STP_MODULE_CLASS_FAMILY,
    02790     NULL,
    02791     print_escp2_module_init,
    02792     print_escp2_module_exit,
    02793     (void *) &print_escp2_module_data
    02794   };
    02795