Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

src/main/print-escp2.c

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

Generated on Wed May 12 20:21:31 2004 for libgimpprint API Reference by doxygen1.2.17