1/*
2 * "$Id: print-canon.c,v 1.249 2011/05/01 07:40:55 gernot2270 Exp $"
3 *
4 *   Print plug-in CANON BJL driver for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com),
7 *	Robert Krawitz (rlk@alum.mit.edu) and
8 *      Andy Thaller (thaller@ph.tum.de)
9 *
10 *   Copyright (c) 2006 - 2007 Sascha Sommer (saschasommer@freenet.de)
11 *
12 *   This program is free software; you can redistribute it and/or modify it
13 *   under the terms of the GNU General Public License as published by the Free
14 *   Software Foundation; either version 2 of the License, or (at your option)
15 *   any later version.
16 *
17 *   This program is distributed in the hope that it will be useful, but
18 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 *   for more details.
21 *
22 *   You should have received a copy of the GNU General Public License
23 *   along with this program; if not, write to the Free Software
24 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27/*
28 * This file must include only standard C header files.  The core code must
29 * compile on generic platforms that don't support glib, gimp, gtk, etc.
30 */
31
32/*
33 * Large parts of this file (mainly the ink handling) is based on
34 * print-escp2.c -- refer to README.new-printer on how to adjust the colors
35 * for a certain model.
36 */
37
38/* TODO-LIST
39 *
40 *   * adjust the colors of all supported models
41 *
42 */
43#ifdef HAVE_CONFIG_H
44#include <config.h>
45#endif
46#include <gutenprint/gutenprint.h>
47#include "gutenprint-internal.h"
48#include <gutenprint/gutenprint-intl-internal.h>
49#include <string.h>
50#include <stdio.h>
51#if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
52#include <varargs.h>
53#else
54#include <stdarg.h>
55#endif
56#ifdef HAVE_LIMITS_H
57#include <limits.h>
58#endif
59#include <math.h>
60
61#include "print-canon.h"
62
63#ifndef MIN
64#  define MIN(a,b) (((a)<(b)) ? (a) : (b))
65#endif /* !MIN */
66#ifndef MAX
67#  define MAX(a, b) ((a) > (b) ? (a) : (b))
68#endif /* !MAX */
69
70
71
72
73
74
75
76static int
77pack_pixels(unsigned char* buf,int len)
78{
79  int read_pos = 0;
80  int write_pos = 0;
81  int shift = 6;
82  while(read_pos < len)
83  {
84    /* read 5pixels a 2 bit */
85    unsigned short value = buf[read_pos] << 8;
86    if(read_pos+1 < len)
87      value += buf[read_pos + 1];
88    if(shift)       /*6,4,2,0*/
89      value >>= shift;
90    /* write 8bit value representing the 10 bit pixel combination */
91    buf[write_pos] = tentoeight[value & 1023];
92    ++write_pos;
93    if(shift == 0)
94    {
95      shift = 6;
96      read_pos += 2;
97    }
98    else
99    {
100      shift -= 2;
101      ++read_pos;
102    }
103  }
104  return write_pos;
105}
106
107/* model peculiarities */
108#define CANON_CAP_MSB_FIRST 0x02ul    /* how to send data           */
109#define CANON_CAP_a         0x04ul
110#define CANON_CAP_b         0x08ul
111#define CANON_CAP_q         0x10ul
112#define CANON_CAP_m         0x20ul
113#define CANON_CAP_d         0x40ul
114#define CANON_CAP_t         0x80ul
115#define CANON_CAP_c         0x100ul
116#define CANON_CAP_p         0x200ul
117#define CANON_CAP_l         0x400ul
118#define CANON_CAP_r         0x800ul
119#define CANON_CAP_g         0x1000ul
120#define CANON_CAP_px        0x2000ul
121#define CANON_CAP_rr        0x4000ul
122#define CANON_CAP_I         0x8000ul
123#define CANON_CAP_T         0x10000ul /* not sure of this yet! */
124#define CANON_CAP_P         0x20000ul
125#define CANON_CAP_DUPLEX    0x40000ul
126#define CANON_CAP_XML       0x80000ul /* not sure of this yet */
127#define CANON_CAP_CARTRIDGE 0x100000ul /* not sure of this yet */
128
129#define CANON_CAP_STD0 (CANON_CAP_b|CANON_CAP_c|CANON_CAP_d|\
130                        CANON_CAP_l|CANON_CAP_q|CANON_CAP_t)
131
132#define CANON_CAP_STD1 (CANON_CAP_b|CANON_CAP_c|CANON_CAP_d|CANON_CAP_l|\
133                        CANON_CAP_m|CANON_CAP_p|CANON_CAP_q|CANON_CAP_t)
134
135#include "canon-inks.h"
136#include "canon-modes.h"
137#include "canon-media.h"
138#include "canon-printers.h"
139
140
141typedef struct {
142    char name;
143    const canon_ink_t* props;
144    unsigned char* buf;
145    unsigned char* comp_buf_offset;
146    unsigned int buf_length;
147    unsigned int delay;
148} canon_channel_t;
149
150
151
152typedef struct
153{
154  const canon_mode_t* mode;
155  const canon_slot_t* slot;
156  const canon_paper_t *pt;
157  unsigned int used_inks;
158  int num_channels;
159  int quality;
160  canon_channel_t* channels;
161  char* channel_order;
162  const canon_cap_t *caps;
163  unsigned char *comp_buf;
164  unsigned char *fold_buf;
165  int delay_max;
166  int buf_length_max;
167  int length;
168  int out_width;
169  int out_height;
170  int page_width;
171  int page_height;
172  int top;
173  int left;
174  int emptylines;
175  int ncolors; /* number of colors to print with */
176  int physical_xdpi, nozzle_ydpi, stepper_ydpi;
177  int nozzles;   /* count of inkjets for one pass */
178  int nozzle_separation;
179  int horizontal_passes;
180  int vertical_passes;
181  int vertical_oversample;
182  int *head_offset;
183  int last_pass_offset;
184  int bidirectional; /* tells us if we are allowed to print bidirectional */
185  int direction;     /* stores the last direction of the print head */
186  int weave_bits[4];
187  const char *duplex_str;
188  int is_first_page;
189  double cd_inner_radius;
190  double cd_outer_radius;
191} canon_privdata_t;
192
193static void canon_write_line(stp_vars_t *v);
194
195static void canon_advance_paper(stp_vars_t *, int);
196static void canon_flush_pass(stp_vars_t *, int, int);
197static void canon_write_multiraster(stp_vars_t *v,canon_privdata_t* pd,int y);
198
199static const stp_parameter_t the_parameters[] =
200{
201  {
202    "PageSize", N_("Page Size"), "Color=No,Category=Basic Printer Setup",
203    N_("Size of the paper being printed to"),
204    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
205    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
206  },
207  {
208    "MediaType", N_("Media Type"), "Color=Yes,Category=Basic Printer Setup",
209    N_("Type of media (plain paper, photo paper, etc.)"),
210    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
211    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
212  },
213  {
214    "InputSlot", N_("Media Source"), "Color=No,Category=Basic Printer Setup",
215    N_("Source (input slot) of the media"),
216    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
217    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
218  },
219  {
220    "CDInnerRadius", N_("CD Hub Size"), "Color=No,Category=Basic Printer Setup",
221    N_("Print only outside of the hub of the CD, or all the way to the hole"),
222    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
223    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
224  },
225  {
226    "CDOuterDiameter", N_("CD Size (Custom)"), "Color=No,Category=Basic Printer Setup",
227    N_("Variable adjustment for the outer diameter of CD"),
228    STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
229    STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0
230  },
231  {
232    "CDInnerDiameter", N_("CD Hub Size (Custom)"), "Color=No,Category=Basic Printer Setup",
233    N_("Variable adjustment to the inner hub of the CD"),
234    STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
235    STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0
236  },
237  {
238    "CDXAdjustment", N_("CD Horizontal Fine Adjustment"), "Color=No,Category=Advanced Printer Setup",
239    N_("Fine adjustment to horizontal position for CD printing"),
240    STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
241    STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0
242  },
243  {
244    "CDYAdjustment", N_("CD Vertical Fine Adjustment"), "Color=No,Category=Advanced Printer Setup",
245    N_("Fine adjustment to horizontal position for CD printing"),
246    STP_PARAMETER_TYPE_DIMENSION, STP_PARAMETER_CLASS_FEATURE,
247    STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0
248  },
249  {
250    "Resolution", N_("Resolution"), "Color=Yes,Category=Basic Printer Setup",
251    N_("Resolution and quality of the print"),
252    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
253    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
254  },
255  {
256    "InkType", N_("Ink Type"), "Color=Yes,Category=Advanced Printer Setup",
257    N_("Type of ink in the printer"),
258    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
259    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
260  },
261  {
262    "InkChannels", N_("Ink Channels"), "Color=Yes,Category=Advanced Printer Functionality",
263    N_("Ink Channels"),
264    STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE,
265    STP_PARAMETER_LEVEL_INTERNAL, 0, 0, STP_CHANNEL_NONE, 0, 0
266  },
267  {
268    "PrintingMode", N_("Printing Mode"), "Color=Yes,Category=Core Parameter",
269    N_("Printing Output Mode"),
270    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
271    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
272  },
273  {
274    "Duplex", N_("Double-Sided Printing"), "Color=No,Category=Basic Printer Setup",
275    N_("Duplex/Tumble Setting"),
276    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
277    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
278  },
279  {
280    "Quality", N_("Print Quality"), "Color=Yes,Category=Basic Output Adjustment",
281    N_("Print Quality"),
282    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
283    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 0, 0
284  },
285};
286
287static const int the_parameter_count =
288sizeof(the_parameters) / sizeof(const stp_parameter_t);
289
290typedef struct
291{
292  const stp_parameter_t param;
293  double min;
294  double max;
295  double defval;
296  int color_only;
297} float_param_t;
298
299static const float_param_t float_parameters[] =
300{
301  {
302    {
303      "CyanDensity", N_("Cyan Density"), "Color=Yes,Category=Output Level Adjustment",
304      N_("Adjust the cyan density"),
305      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
306      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 1, 1, 0
307    }, 0.0, 2.0, 1.0, 1
308  },
309  {
310    {
311      "MagentaDensity", N_("Magenta Density"), "Color=Yes,Category=Output Level Adjustment",
312      N_("Adjust the magenta density"),
313      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
314      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 2, 1, 0
315    }, 0.0, 2.0, 1.0, 1
316  },
317  {
318    {
319      "YellowDensity", N_("Yellow Density"), "Color=Yes,Category=Output Level Adjustment",
320      N_("Adjust the yellow density"),
321      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
322      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 3, 1, 0
323    }, 0.0, 2.0, 1.0, 1
324  },
325  {
326    {
327      "BlackDensity", N_("Black Density"), "Color=Yes,Category=Output Level Adjustment",
328      N_("Adjust the black density"),
329      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
330      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 0, 1, 0
331    }, 0.0, 2.0, 1.0, 1
332  },
333  {
334    {
335      "LightCyanTrans", N_("Light Cyan Transition"), "Color=Yes,Category=Advanced Ink Adjustment",
336      N_("Light Cyan Transition"),
337      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
338      STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, STP_CHANNEL_NONE, 1, 0
339    }, 0.0, 5.0, 1.0, 1
340  },
341  {
342    {
343      "LightMagentaTrans", N_("Light Magenta Transition"), "Color=Yes,Category=Advanced Ink Adjustment",
344      N_("Light Magenta Transition"),
345      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
346      STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, STP_CHANNEL_NONE, 1, 0
347    }, 0.0, 5.0, 1.0, 1
348  },
349 {
350    {
351      "LightYellowTrans", N_("Light Yellow Transition"), "Color=Yes,Category=Advanced Ink Adjustment",
352      N_("Light Yellow Transition"),
353      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
354      STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, STP_CHANNEL_NONE, 1, 0
355    }, 0.0, 5.0, 1.0, 1
356  },
357};
358
359
360static const int float_parameter_count =
361sizeof(float_parameters) / sizeof(const float_param_t);
362
363/*
364 * Duplex support - modes available
365 * Note that the internal names MUST match those in cups/genppd.c else the
366 * PPD files will not be generated correctly
367 */
368
369static const stp_param_string_t duplex_types[] =
370{
371  { "None",             N_ ("Off") },
372  { "DuplexNoTumble",   N_ ("Long Edge (Standard)") },
373  { "DuplexTumble",     N_ ("Short Edge (Flip)") }
374};
375#define NUM_DUPLEX (sizeof (duplex_types) / sizeof (stp_param_string_t))
376
377
378
379static const canon_paper_t *
380get_media_type(const canon_cap_t* caps,const char *name)
381{
382  int i;
383  if (name && caps->paperlist)
384    for (i = 0; i < caps->paperlist->count; i++)
385      {
386	/* translate paper_t.name */
387	if (!strcmp(name, caps->paperlist->papers[i].name))
388	  return &(caps->paperlist->papers[i]);
389      }
390  return &(caps->paperlist->papers[0]);
391}
392
393
394static const char* canon_families[] = {
395 "", /* the old BJC printers */
396 "S",
397 "i",
398 "PIXMA iP",
399 "PIXMA iX",
400 "PIXMA MP",
401 "PIXUS",
402 "PIXMA Pro",
403 "PIXMA MG",
404 "PIXMA MX",
405};
406
407/* canon model ids look like the following
408   FFMMMMMM
409   FF: family is the offset in the canon_families struct
410   MMMMMM: model nr
411*/
412static char* canon_get_printername(const stp_vars_t* v)
413{
414  unsigned int model = stp_get_model_id(v);
415  unsigned int family = model / 1000000;
416  unsigned int nr = model - family * 1000000;
417  char* name;
418  size_t len;
419  if(family >= sizeof(canon_families) / sizeof(canon_families[0])){
420    stp_erprintf("canon_get_printername: no family %i using default BJC\n", family);
421    family = 0;
422  }
423  len = strlen(canon_families[family]) + 7; /* max model nr. + terminating 0 */
424  name = stp_zalloc(len);
425  snprintf(name,len,"%s%u",canon_families[family],nr);
426  return name;
427}
428
429
430
431
432static const canon_cap_t * canon_get_model_capabilities(const stp_vars_t*v)
433{
434  int i;
435  char* name = canon_get_printername(v);
436  int models= sizeof(canon_model_capabilities) / sizeof(canon_cap_t);
437  for (i=0; i<models; i++) {
438    if (!strcmp(canon_model_capabilities[i].name,name)) {
439      stp_free(name);
440      return &(canon_model_capabilities[i]);
441    }
442  }
443  stp_erprintf("canon: model %s not found in capabilities list=> using default\n",name);
444  stp_free(name);
445  return &(canon_model_capabilities[0]);
446}
447
448static const canon_slot_t *
449canon_source_type(const char *name, const canon_cap_t * caps)
450{
451    if(name){
452        int i;
453        for(i=0; i<caps->slotlist->count; i++){
454            if( !strcmp(name,caps->slotlist->slots[i].name))
455                 return &(caps->slotlist->slots[i]);
456        }
457    }
458    return &(caps->slotlist->slots[0]);
459}
460
461
462/* function returns the current set printmode (specified by resolution) */
463/* if no mode is set the default mode will be returned */
464static const canon_mode_t* canon_get_current_mode(const stp_vars_t *v){
465    const char* input_slot = stp_get_string_parameter(v, "InputSlot");
466    const char *resolution = stp_get_string_parameter(v, "Resolution");
467    const char *quality = stp_get_string_parameter(v, "Quality");
468    const canon_cap_t * caps = canon_get_model_capabilities(v);
469    const canon_mode_t* mode = NULL;
470    int i;
471
472    if(resolution){
473        for(i=0;i<caps->modelist->count;i++){
474            if(!strcmp(resolution,caps->modelist->modes[i].name)){
475                mode = &caps->modelist->modes[i];
476                break;
477            }
478        }
479    }
480
481    if(!mode)
482        mode = &caps->modelist->modes[caps->modelist->default_mode];
483
484#if 0
485    if(quality && strcmp(quality, "None") == 0)
486        quality = "Standard";
487
488    if(quality && !strcmp(quality,"Standard")){
489        return &caps->modelist->modes[caps->modelist->default_mode];
490    }
491#endif
492
493#if 0
494    /* only some modes can print to cd */
495    if(input_slot && !strcmp(input_slot,"CD") && !(mode->flags & MODE_FLAG_CD)){
496        for(i=0;i<caps->modelist->count;i++){
497            if(caps->modelist->modes[i].flags & MODE_FLAG_CD){
498                mode = &caps->modelist->modes[i];
499                break;
500            }
501        }
502    }
503#endif
504
505
506
507
508
509    return mode;
510}
511
512/* function returns the best ink_type for the current mode */
513static unsigned int
514canon_printhead_colors(const stp_vars_t*v)
515{
516  int i;
517  const canon_mode_t* mode;
518  const char *print_mode = stp_get_string_parameter(v, "PrintingMode");
519  const char *ink_type = stp_get_string_parameter(v, "InkType");
520  if(print_mode && strcmp(print_mode, "BW") == 0)
521    return CANON_INK_K;
522
523  if(ink_type){
524      for(i=0;i<sizeof(canon_inktypes)/sizeof(canon_inktypes[0]);i++){
525          if(ink_type && !strcmp(canon_inktypes[i].name,ink_type))
526              return canon_inktypes[i].ink_type;
527     }
528  }
529  mode = canon_get_current_mode(v);
530  for(i=0;i<sizeof(canon_inktypes)/sizeof(canon_inktypes[0]);i++){
531    if(mode->ink_types & canon_inktypes[i].ink_type)
532        return canon_inktypes[i].ink_type;
533  }
534  return CANON_INK_K;
535}
536
537static unsigned char
538canon_size_type(const stp_vars_t *v, const canon_cap_t * caps)
539{
540  const stp_papersize_t *pp = stp_get_papersize_by_size(stp_get_page_height(v),
541							stp_get_page_width(v));
542  if (pp)
543    {
544      const char *name = pp->name;
545      /* used internally: do not translate */
546      /* built ins:                                  Japanese driver notation */
547      if (!strcmp(name,"A5"))          return 0x01;
548      if (!strcmp(name,"A4"))          return 0x03;
549      if (!strcmp(name,"A3"))          return 0x05;
550      if (!strcmp(name,"B5"))          return 0x08;
551      if (!strcmp(name,"B4"))          return 0x0a;
552      if (!strcmp(name,"Letter"))      return 0x0d;
553      if (!strcmp(name,"Legal"))       return 0x0f;
554      if (!strcmp(name,"Tabloid"))     return 0x11; /* 11x17 */
555      if (!strcmp(name,"w283h420"))    return 0x14; /* Hagaki */
556      if (!strcmp(name,"COM10"))       return 0x16;
557      if (!strcmp(name,"DL"))          return 0x17;
558      if (!strcmp(name,"LetterExtra")) return 0x2a;
559      if (!strcmp(name,"A4Extra"))     return 0x2b;
560      if (!strcmp(name,"A3plus"))      return 0x2c; /* A3navi --- A3+ */
561      if (!strcmp(name,"w288h144"))    return 0x2d;
562      if (!strcmp(name,"w252h360J"))   return 0x32; /* L --- similar to US 3.5x5 size */
563      if (!strcmp(name,"w360h504J"))   return 0x33; /* 2L --- similar to US5x7 */
564      if (!strcmp(name,"w288h432J"))   return 0x34; /* KG --- same size as US 4x6 */
565      if (!strcmp(name,"w360h504"))    return 0x37; /* US5x7 */
566      if (!strcmp(name,"w420h567"))    return 0x39; /* Ofuku Hagaki */
567      if (!strcmp(name,"w288h576"))    return 0x46; /* US4x8 */
568      if (!strcmp(name,"w1008h1224J")) return 0x47; /* HanKire --- 14in x 17in */
569      if (!strcmp(name,"720h864J"))    return 0x48; /* YonKire --- 10in x 12 in*/
570      if (!strcmp(name,"c8x10J"))      return 0x49; /* RokuKire --- same size as 8x10 */
571      if (!strcmp(name,"w288h512"))    return 0x52; /* Wide101.6x180.6 */
572      /* custom */
573
574      stp_deprintf(STP_DBG_CANON,"canon: Unknown paper size '%s' - using custom\n",name);
575    } else {
576      stp_deprintf(STP_DBG_CANON,"canon: Couldn't look up paper size %dx%d - "
577	      "using custom\n",stp_get_page_height(v), stp_get_page_width(v));
578    }
579  return 0;
580}
581
582static void
583canon_describe_resolution(const stp_vars_t *v, int *x, int *y)
584{
585    const canon_mode_t* mode = canon_get_current_mode(v);
586    *x = mode->xdpi;
587    *y = mode->ydpi;
588}
589
590static const char *
591canon_describe_output(const stp_vars_t *v)
592{
593  unsigned int ink_type = canon_printhead_colors(v);
594
595  if(ink_type & CANON_INK_CMYK_MASK)
596    return "CMYK";
597  if(ink_type & CANON_INK_CMY_MASK)
598    return "CMY";
599  return "Grayscale";
600}
601
602/*
603 * 'canon_parameters()' - Return the parameter values for the given parameter.
604 */
605
606static stp_parameter_list_t
607canon_list_parameters(const stp_vars_t *v)
608{
609  stp_parameter_list_t *ret = stp_parameter_list_create();
610  int i;
611  for (i = 0; i < the_parameter_count; i++)
612    stp_parameter_list_add_param(ret, &(the_parameters[i]));
613  for (i = 0; i < float_parameter_count; i++)
614    stp_parameter_list_add_param(ret, &(float_parameters[i].param));
615  return ret;
616}
617
618static void
619canon_parameters(const stp_vars_t *v, const char *name,
620		 stp_parameter_t *description)
621{
622  int		i;
623
624  const canon_cap_t * caps=
625    canon_get_model_capabilities(v);
626  description->p_type = STP_PARAMETER_TYPE_INVALID;
627
628  if (name == NULL)
629    return;
630
631  for (i = 0; i < float_parameter_count; i++)
632    if (strcmp(name, float_parameters[i].param.name) == 0)
633      {
634	unsigned int ink_type = canon_printhead_colors(v);
635
636	stp_fill_parameter_settings(description,
637				    &(float_parameters[i].param));
638	description->deflt.dbl = float_parameters[i].defval;
639	description->bounds.dbl.upper = float_parameters[i].max;
640	description->bounds.dbl.lower = float_parameters[i].min;
641	if (ink_type != CANON_INK_K || !float_parameters[i].color_only)
642	  description->is_active = 1;
643	else
644	  description->is_active = 0;
645	return;
646      }
647
648  for (i = 0; i < the_parameter_count; i++)
649    if (strcmp(name, the_parameters[i].name) == 0)
650      {
651	stp_fill_parameter_settings(description, &(the_parameters[i]));
652	break;
653      }
654  if (strcmp(name, "PageSize") == 0)
655    {
656      const char* input_slot = stp_get_string_parameter(v, "InputSlot");
657      int height_limit, width_limit;
658      int papersizes = stp_known_papersizes();
659      description->bounds.str = stp_string_list_create();
660
661      width_limit = caps->max_width;
662      height_limit = caps->max_height;
663
664      if(input_slot && !strcmp(input_slot,"CD")){
665        stp_string_list_add_string
666          (description->bounds.str, "CD5Inch", _("CD - 5 inch"));
667        stp_string_list_add_string
668          (description->bounds.str, "CD3Inch", _("CD - 3 inch"));
669        stp_string_list_add_string
670          (description->bounds.str, "CDCustom", _("CD - Custom"));
671      }else{
672        for (i = 0; i < papersizes; i++) {
673          const stp_papersize_t *pt = stp_get_papersize_by_index(i);
674          if (strlen(pt->name) > 0 &&
675	      pt->width <= width_limit && pt->height <= height_limit){
676	    stp_string_list_add_string(description->bounds.str,
677				     pt->name, gettext(pt->text));
678           }
679        }
680      }
681      description->deflt.str =
682        stp_string_list_param(description->bounds.str, 0)->name;
683  }
684  else if (strcmp(name, "CDInnerRadius") == 0 )
685    {
686      const char* input_slot = stp_get_string_parameter(v, "InputSlot");
687      description->bounds.str = stp_string_list_create();
688      if (input_slot && !strcmp(input_slot,"CD") &&
689         (!stp_get_string_parameter(v, "PageSize") ||
690          strcmp(stp_get_string_parameter(v, "PageSize"), "CDCustom") != 0))
691	{
692	  stp_string_list_add_string
693	    (description->bounds.str, "None", _("Normal"));
694	  stp_string_list_add_string
695	    (description->bounds.str, "Small", _("Print To Hub"));
696	  description->deflt.str =
697	    stp_string_list_param(description->bounds.str, 0)->name;
698	}
699      else
700	description->is_active = 0;
701    }
702  else if (strcmp(name, "CDInnerDiameter") == 0 )
703    {
704      const char* input_slot = stp_get_string_parameter(v, "InputSlot");
705      description->bounds.dimension.lower = 16 * 10 * 72 / 254;
706      description->bounds.dimension.upper = 43 * 10 * 72 / 254;
707      description->deflt.dimension = 43 * 10 * 72 / 254;
708      if (input_slot && !strcmp(input_slot,"CD") &&
709         (!stp_get_string_parameter(v, "PageSize") ||
710         strcmp(stp_get_string_parameter(v, "PageSize"), "CDCustom") == 0))
711	description->is_active = 1;
712      else
713	description->is_active = 0;
714    }
715  else if (strcmp(name, "CDOuterDiameter") == 0 )
716    {
717      const char* input_slot = stp_get_string_parameter(v, "InputSlot");
718      description->bounds.dimension.lower = 65 * 10 * 72 / 254;
719      description->bounds.dimension.upper = 120 * 10 * 72 / 254;
720      description->deflt.dimension = 329;
721      if (input_slot && !strcmp(input_slot,"CD") &&
722         (!stp_get_string_parameter(v, "PageSize") ||
723          strcmp(stp_get_string_parameter(v, "PageSize"), "CDCustom") == 0))
724	description->is_active = 1;
725      else
726	description->is_active = 0;
727    }
728  else if (strcmp(name, "CDXAdjustment") == 0 ||
729	   strcmp(name, "CDYAdjustment") == 0)
730    {
731      const char* input_slot = stp_get_string_parameter(v, "InputSlot");
732      description->bounds.dimension.lower = -15;
733      description->bounds.dimension.upper = 15;
734      description->deflt.dimension = 0;
735      if (input_slot && !strcmp(input_slot,"CD"))
736	description->is_active = 1;
737      else
738	description->is_active = 0;
739    }
740  else if (strcmp(name, "Resolution") == 0)
741  {
742    const char* input_slot = stp_get_string_parameter(v, "InputSlot");
743    description->bounds.str= stp_string_list_create();
744    description->deflt.str = NULL;
745    for(i=0;i<caps->modelist->count;i++){
746#if 0
747	if(!(input_slot && !strcmp(input_slot,"CD") && !(caps->modelist->modes[i].flags & MODE_FLAG_CD)))
748#endif
749          stp_string_list_add_string(description->bounds.str,
750                                        caps->modelist->modes[i].name, gettext(caps->modelist->modes[i].text));
751        stp_deprintf(STP_DBG_CANON,"supports mode '%s'\n",
752                      caps->modelist->modes[i].name);
753        if(i == caps->modelist->default_mode)
754            description->deflt.str=caps->modelist->modes[i].name;
755
756
757    }
758  }
759  else if (strcmp(name, "InkType") == 0)
760  {
761    const canon_mode_t* mode = canon_get_current_mode(v);
762    description->bounds.str= stp_string_list_create();
763    for(i=0;i<sizeof(canon_inktypes)/sizeof(canon_inktypes[0]);i++){
764      if(mode->ink_types & canon_inktypes[i].ink_type){
765          stp_string_list_add_string(description->bounds.str,canon_inktypes[i].name,_(canon_inktypes[i].text));
766      }
767    }
768    description->deflt.str = stp_string_list_param(description->bounds.str, 0)->name;
769  }
770  else if (strcmp(name, "InkChannels") == 0)
771    {
772      unsigned int ink_type = canon_printhead_colors(v);
773      for(i=0;i<sizeof(canon_inktypes)/sizeof(canon_inktypes[0]);i++){
774          if(ink_type == canon_inktypes[i].ink_type)
775              description->deflt.integer = canon_inktypes[i].num_channels;
776      }
777      description->bounds.integer.lower = -1;
778      description->bounds.integer.upper = -1;
779    }
780  else if (strcmp(name, "MediaType") == 0)
781  {
782    const canon_paper_t * canon_paper_list = caps->paperlist->papers;
783    int count = caps->paperlist->count;
784    description->bounds.str= stp_string_list_create();
785    description->deflt.str= canon_paper_list[0].name;
786
787    for (i = 0; i < count; i ++)
788      stp_string_list_add_string(description->bounds.str,
789				canon_paper_list[i].name,
790				gettext(canon_paper_list[i].text));
791  }
792  else if (strcmp(name, "InputSlot") == 0)
793  {
794    const canon_slot_t * canon_slot_list = caps->slotlist->slots;
795    int count = caps->slotlist->count;
796    description->bounds.str= stp_string_list_create();
797    description->deflt.str= canon_slot_list[0].name;
798
799    for (i = 0; i < count; i ++)
800      stp_string_list_add_string(description->bounds.str,
801				canon_slot_list[i].name,
802				gettext(canon_slot_list[i].text));
803  }
804  else if (strcmp(name, "PrintingMode") == 0)
805  {
806    const canon_mode_t* mode = canon_get_current_mode(v);
807    description->bounds.str = stp_string_list_create();
808    if (mode->ink_types != CANON_INK_K)
809      stp_string_list_add_string
810	(description->bounds.str, "Color", _("Color"));
811    stp_string_list_add_string
812      (description->bounds.str, "BW", _("Black and White"));
813    description->deflt.str =
814      stp_string_list_param(description->bounds.str, 0)->name;
815  }
816  else if (strcmp(name, "Duplex") == 0)
817  {
818    int offer_duplex=0;
819
820    description->bounds.str = stp_string_list_create();
821
822/*
823 * Don't offer the Duplex/Tumble options if the JobMode parameter is
824 * set to "Page" Mode.
825 * "Page" mode is set by the Gimp Plugin, which only outputs one page at a
826 * time, so Duplex/Tumble is meaningless.
827 */
828
829    if (stp_get_string_parameter(v, "JobMode"))
830        offer_duplex = strcmp(stp_get_string_parameter(v, "JobMode"), "Page");
831    else
832     offer_duplex=1;
833
834    if (offer_duplex && (caps->features & CANON_CAP_DUPLEX))
835    {
836      description->deflt.str = duplex_types[0].name;
837      for (i=0; i < NUM_DUPLEX; i++)
838        {
839          stp_string_list_add_string(description->bounds.str,
840				     duplex_types[i].name,gettext(duplex_types[i].text));
841        }
842    }
843    else
844      description->is_active = 0;
845  }
846  else if (strcmp(name, "Quality") == 0)
847  {
848    int has_standard_quality = 0;
849    description->bounds.str = stp_string_list_create();
850    stp_string_list_add_string(description->bounds.str, "None",
851			       _("Manual Control"));
852    stp_string_list_add_string(description->bounds.str, "Standard",
853			       _("Standard"));
854    description->deflt.str = "Standard";
855  }
856  /* Cartridge selection for those printers that have it */
857  else if (strcmp(name, "Cartridge") == 0)
858  {
859    int offer_cartridge_selection = 0;
860    description->bounds.str = stp_string_list_create();
861    stp_string_list_add_string(description->bounds.str, "Both",
862			       _("Both"));
863    stp_string_list_add_string(description->bounds.str, "Color",
864			       _("Color"));
865    stp_string_list_add_string(description->bounds.str, "Black",
866			       _("Black"));
867
868    /* description->deflt.str = "Both"; */
869    /* Note: not necessary set cartridge if Mono mode */
870
871    if (caps->features & CANON_CAP_CARTRIDGE)
872      {
873	description->deflt.str =
874	  stp_string_list_param(description->bounds.str, 0)->name;
875      }
876    else
877      description->is_active = 0;
878  }
879
880}
881
882
883/*
884 * 'canon_imageable_area()' - Return the imageable area of the page.
885 */
886
887static void
888internal_imageable_area(const stp_vars_t *v,   /* I */
889			int  use_paper_margins,
890			int  *left,	/* O - Left position in points */
891			int  *right,	/* O - Right position in points */
892			int  *bottom,	/* O - Bottom position in points */
893			int  *top)	/* O - Top position in points */
894{
895  int	width, length;			/* Size of page */
896  int left_margin = 0;
897  int right_margin = 0;
898  int bottom_margin = 0;
899  int top_margin = 0;
900  int cd = 0;
901
902  const canon_cap_t * caps= canon_get_model_capabilities(v);
903  const char *media_size = stp_get_string_parameter(v, "PageSize");
904  const stp_papersize_t *pt = NULL;
905  const char* input_slot = stp_get_string_parameter(v, "InputSlot");
906
907  if(input_slot && !strcmp(input_slot,"CD"))
908    cd = 1;
909
910  if (media_size && use_paper_margins)
911    pt = stp_get_papersize_by_name(media_size);
912
913  stp_default_media_size(v, &width, &length);
914  if (pt)
915    {
916      left_margin = pt->left;
917      right_margin = pt->right;
918      bottom_margin = pt->bottom;
919      top_margin = pt->top;
920    }
921  /* ignore printer margins for the cd print, margins get adjusted in do_print */
922  if(!cd){
923    left_margin = MAX(left_margin, caps->border_left);
924    right_margin = MAX(right_margin, caps->border_right);
925    top_margin = MAX(top_margin, caps->border_top);
926    bottom_margin = MAX(bottom_margin, caps->border_bottom);
927  }
928
929  *left =	left_margin;
930  *right =	width - right_margin;
931  *top =	top_margin;
932  *bottom =	length - bottom_margin;
933}
934
935static void
936canon_imageable_area(const stp_vars_t *v,   /* I */
937                     int  *left,	/* O - Left position in points */
938                     int  *right,	/* O - Right position in points */
939                     int  *bottom,	/* O - Bottom position in points */
940                     int  *top)		/* O - Top position in points */
941{
942  internal_imageable_area(v, 1, left, right, bottom, top);
943}
944
945static void
946canon_limit(const stp_vars_t *v,  		/* I */
947	    int *width,
948	    int *height,
949	    int *min_width,
950	    int *min_height)
951{
952  const canon_cap_t * caps=
953    canon_get_model_capabilities(v);
954  *width =	caps->max_width;
955  *height =	caps->max_height;
956  *min_width = 1;
957  *min_height = 1;
958}
959
960/*
961 * 'canon_cmd()' - Sends a command with variable args
962 */
963static void
964canon_cmd(const stp_vars_t *v, /* I - the printer         */
965	  const char *ini, /* I - 2 bytes start code  */
966	  const char cmd,  /* I - command code        */
967	  int  num,  /* I - number of arguments */
968	  ...        /* I - the args themselves */
969	  )
970{
971  unsigned char *buffer = stp_zalloc(num + 1);
972  int i;
973  va_list ap;
974
975  if (num)
976    {
977      va_start(ap, num);
978      for (i=0; i<num; i++)
979	buffer[i]= (unsigned char) va_arg(ap, int);
980      va_end(ap);
981    }
982
983  stp_zfwrite(ini,2,1,v);
984  if (cmd)
985    {
986      stp_putc(cmd,v);
987      stp_put16_le(num, v);
988      if (num)
989	stp_zfwrite((const char *)buffer,num,1,v);
990    }
991  stp_free(buffer);
992}
993
994#define PUT(WHAT,VAL,RES) stp_deprintf(STP_DBG_CANON,"canon: "WHAT\
995" is %04x =% 5d = %f\" = %f mm\n",(VAL),(VAL),(VAL)/(1.*RES),(VAL)/(RES/25.4))
996
997#define ESC28 "\033\050"
998#define ESC5b "\033\133"
999#define ESC40 "\033\100"
1000
1001static void canon_control_cmd(const stp_vars_t*v,const char* cmd){
1002      canon_cmd(v,ESC5b,0x4b, 2, 0x00,0x1f);
1003      stp_puts("BJLSTART\nControlMode=Common\n",v);
1004      stp_puts(cmd,v);
1005      stp_putc('\n',v);
1006      stp_puts("BJLEND\n",v);
1007}
1008
1009
1010/* ESC [K --  -- reset printer:
1011 */
1012static void
1013canon_init_resetPrinter(const stp_vars_t *v, const canon_privdata_t *init)
1014{
1015  if ( init->caps->control_cmdlist ){
1016    int i=0;
1017    while(init->caps->control_cmdlist[i]){
1018      canon_control_cmd(v,init->caps->control_cmdlist[i]);
1019      ++i;
1020    }
1021  }
1022  if(!strcmp(init->slot->name,"CD"))
1023    canon_control_cmd(v,"MediaDetection=ON");
1024  canon_cmd(v,ESC5b,0x4b, 2, 0x00,0x0f);
1025}
1026
1027/* ESC ($ -- 0x24 -- cmdSetDuplex --:
1028 */
1029static void
1030canon_init_setDuplex(const stp_vars_t *v, const canon_privdata_t *init)
1031{
1032  if (!(init->caps->features & CANON_CAP_DUPLEX))
1033    return;
1034  if (strncmp(init->duplex_str, "Duplex", 6))
1035    return;
1036  /* The same command seems to be needed for both Duplex and DuplexTumble
1037     no idea about the meanings of the single bytes */
1038  canon_cmd(v,ESC28,0x24,9,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x02);
1039}
1040
1041/* ESC (a -- 0x61 -- cmdSetPageMode --:
1042 */
1043static void
1044canon_init_setPageMode(const stp_vars_t *v, const canon_privdata_t *init)
1045{
1046  if (!(init->caps->features & CANON_CAP_a))
1047    return;
1048
1049  if (init->caps->features & CANON_CAP_a)
1050    canon_cmd(v,ESC28,0x61, 1, 0x01);
1051}
1052
1053/* ESC (b -- 0x62 -- -- set data compression:
1054 */
1055static void
1056canon_init_setDataCompression(const stp_vars_t *v, const canon_privdata_t *init)
1057{
1058  if (!(init->caps->features & CANON_CAP_b))
1059    return;
1060
1061  canon_cmd(v,ESC28,0x62, 1, 0x01);
1062}
1063
1064/* ESC (c -- 0x63 -- cmdSetColor --:
1065 */
1066static void
1067canon_init_setColor(const stp_vars_t *v, const canon_privdata_t *init)
1068{
1069  unsigned char
1070    numargs, arg_63[6];
1071
1072  if (!(init->caps->features & CANON_CAP_c))
1073    return;
1074
1075  numargs = 3;
1076  arg_63[0] = init->caps->model_id << 4; /* MODEL_ID */
1077
1078  switch ( init->caps->model_id ) {
1079
1080  	case 0:			/* very old 360 dpi series: BJC-800/820 */
1081		break;		/*	tbd */
1082
1083  	case 1:			/* 360 dpi series - BJC-4000, BJC-210, BJC-70 and their descendants */
1084		if (init->used_inks == CANON_INK_K)
1085                            arg_63[0]|= 0x01;                                        /* PRINT_COLOUR */
1086
1087                  arg_63[1] = ((init->pt ? init->pt->media_code_c : 0) << 4)                /* PRINT_MEDIA */
1088			+ 1;	/* hardcode to High quality for now */		/* PRINT_QUALITY */
1089
1090                  canon_cmd(v,ESC28,0x63, 2, arg_63[0], arg_63[1]);
1091		break;
1092
1093	case 2:			/* are any models using this? */
1094		break;
1095
1096	case 3:			/* 720 dpi series - BJC-3000 and descendants */
1097		if (init->used_inks == CANON_INK_K)
1098                            arg_63[0]|= 0x01;                                        /* colour mode */
1099
1100                  arg_63[1] = (init->pt) ? init->pt->media_code_c : 0;                /* print media type */
1101
1102                 if (!strcmp(init->caps->name,"S200")) /* S200 */
1103                   {
1104                     if ((init->mode->xdpi == 720) && (init->mode->ydpi == 720 ))
1105                       arg_63[2] = 1;
1106                     else
1107                       arg_63[2] = 4; /* hardcoded: quality 3  (may be 0...4) */
1108                     /* bidirectional is controlled via quality: 0..2 is bidi, 3 and 4 uni */
1109                     /* not every combination works, no idea about the principle */
1110                     if ( (init->mode->xdpi > 360) || (init->mode->ydpi > 360) )
1111                       {
1112                         numargs = 6;
1113                         arg_63[3] = 0x10; arg_63[4] = 6; arg_63[5] = 8; /* arg5 makes a vert. offset for K */
1114                         if (init->used_inks == CANON_INK_K)
1115                           arg_63[4] = 1;
1116                       }
1117                   }
1118                 else
1119                   arg_63[2] = init->quality;        /* hardcode to whatever this means for now; quality, apparently */
1120
1121                 stp_zprintf(v, "\033\050\143");
1122                 stp_put16_le(numargs, v);
1123                 stp_zfwrite((const char *)arg_63, numargs, 1, v);
1124		break;
1125  	}
1126
1127  return;
1128}
1129
1130/* ESC (d -- 0x64 -- -- set raster resolution:
1131 */
1132static void
1133canon_init_setResolution(const stp_vars_t *v, const canon_privdata_t *init)
1134{
1135  if (!(init->caps->features & CANON_CAP_d))
1136    return;
1137
1138   if (strcmp(init->caps->name,"S200") || (init->mode->xdpi <= 360))
1139  canon_cmd(v,ESC28,0x64, 4,
1140	    (init->mode->ydpi >> 8 ), (init->mode->ydpi & 255),
1141	    (init->mode->xdpi >> 8 ), (init->mode->xdpi & 255));
1142   else
1143     if (init->mode->xdpi < 2880)
1144       canon_cmd(v,ESC28,0x64, 4,
1145         (720 >> 8), (720 & 255),
1146         (720 >> 8), (720 & 255));
1147     else
1148       canon_cmd(v,ESC28,0x64, 4,
1149         (720 >> 8), (720 & 255),
1150         (2880 >> 8), (2880 & 255));
1151  }
1152
1153/* ESC (g -- 0x67 -- cmdSetPageMargins --:
1154 */
1155static void
1156canon_init_setPageMargins(const stp_vars_t *v, const canon_privdata_t *init)
1157{
1158  /* TOFIX: what exactly is to be sent?
1159   * Is it the printable length or the bottom border?
1160   * Is is the printable width or the right border?
1161   */
1162
1163  int minlength= 0;
1164  int minwidth= 0;
1165  int length= init->page_height*5/36;
1166  int width= init->page_width*5/36;
1167
1168  if (!(init->caps->features & CANON_CAP_g))
1169    return;
1170
1171  if (minlength>length) length= minlength;
1172  if (minwidth>width) width= minwidth;
1173
1174  canon_cmd(v,ESC28,0x67, 4, 0,
1175	    (unsigned char)(length),1,
1176	    (unsigned char)(width));
1177
1178}
1179
1180/* ESC (l -- 0x6c -- cmdSetTray --:
1181 */
1182static void
1183canon_init_setTray(const stp_vars_t *v, const canon_privdata_t *init)
1184{
1185  unsigned char
1186    arg_6c_1 = 0x00,
1187    arg_6c_2 = 0x00; /* plain paper */
1188
1189  if (!(init->caps->features & CANON_CAP_l))
1190    return;
1191
1192  arg_6c_1 = init->caps->model_id << 4;
1193
1194  arg_6c_1|= (init->slot->code & 0x0f);
1195
1196  if (init->pt) arg_6c_2= init->pt->media_code_l;
1197  if(init->caps->model_id >= 3)
1198    canon_cmd(v,ESC28,0x6c, 3, arg_6c_1, arg_6c_2, 0);
1199  else
1200    canon_cmd(v,ESC28,0x6c, 2, arg_6c_1, arg_6c_2);
1201}
1202
1203/* ESC (m -- 0x6d --  -- :
1204 */
1205static void
1206canon_init_setPrintMode(const stp_vars_t *v, const canon_privdata_t *init)
1207{
1208  unsigned char
1209    arg_6d_1 = 0x03, /* color printhead? */
1210    arg_6d_2 = 0x00, /* 00=color  02=b/w */
1211    arg_6d_3 = 0x00, /* only 01 for bjc8200 and S200*/
1212                     /* S200:for envelope and t-shirt transfer = 03 */
1213    arg_6d_a = 0x03, /* A4 paper */
1214    arg_6d_b = 0x00;
1215
1216  if (!(init->caps->features & CANON_CAP_m))
1217    return;
1218
1219  arg_6d_a= canon_size_type(v,init->caps);
1220  if (!arg_6d_a)
1221    arg_6d_b= 1;
1222
1223    arg_6d_1= 0x04;
1224  if ((!strcmp(init->caps->name,"7000")) && (init->used_inks == CANON_INK_K || init->used_inks == CANON_INK_CcMmYK || init->used_inks == CANON_INK_CcMmYyK))
1225    arg_6d_1= 0x03;
1226
1227  if (((!strcmp(init->caps->name,"8200") || !strcmp(init->caps->name,"S200")) && init->used_inks == CANON_INK_K) || init->used_inks == CANON_INK_CMYK)
1228      arg_6d_1= 0x02;
1229
1230  if(!strcmp(init->caps->name,"S200") && init->used_inks == CANON_INK_CMY)
1231      arg_6d_1= 0x02;
1232
1233  if (init->used_inks == CANON_INK_K)
1234    arg_6d_2= 0x02;
1235
1236  if (!strcmp(init->caps->name,"8200") || !strcmp(init->caps->name,"S200"))
1237    arg_6d_3= 0x01;
1238
1239  canon_cmd(v,ESC28,0x6d,12, arg_6d_1,
1240	    0xff,0xff,0x00,0x00,0x07,0x00,
1241	    arg_6d_a,arg_6d_b,arg_6d_2,0x00,arg_6d_3);
1242}
1243
1244/* ESC (p -- 0x70 -- cmdSetPageMargins2 --:
1245 */
1246static void
1247canon_init_setPageMargins2(const stp_vars_t *v, const canon_privdata_t *init)
1248{
1249  /* TOFIX: what exactly is to be sent?
1250   * Is it the printable length or the bottom border?
1251   * Is is the printable width or the right border?
1252   */
1253  int printable_width=  (init->page_width + 1)*5/6;
1254  int printable_length= (init->page_height + 1)*5/6;
1255
1256  unsigned char arg_70_1= (printable_length >> 8) & 0xff;
1257  unsigned char arg_70_2= (printable_length) & 0xff;
1258  unsigned char arg_70_3= (printable_width >> 8) & 0xff;
1259  unsigned char arg_70_4= (printable_width) & 0xff;
1260  const char* input_slot = stp_get_string_parameter(v, "InputSlot");
1261
1262  if (!(init->caps->features & CANON_CAP_px) && !(init->caps->features & CANON_CAP_p))
1263	return;
1264
1265  if ((init->caps->features & CANON_CAP_px) && !(input_slot && !strcmp(input_slot,"CD")))
1266  {
1267    unsigned int unit = 600;
1268    stp_zfwrite(ESC28,2,1,v); /* ESC( */
1269    stp_putc(0x70,v);         /* p    */
1270    stp_put16_le(46, v);      /* len  */
1271    stp_put16_be(printable_length,v);
1272    stp_put16_be(0,v);
1273    stp_put16_be(printable_width,v);
1274    stp_put16_be(0,v);
1275    stp_put32_be(0,v);
1276    stp_put16_be(unit,v);
1277
1278    stp_put32_be(init->caps->border_left * unit / 72,v); /* area_right */
1279    stp_put32_be(init->caps->border_top * unit / 72,v);  /* area_top */
1280    stp_put32_be(init->page_width  * unit / 72,v); /* area_width */
1281    stp_put32_be(init->page_height * unit / 72,v); /* area_length */
1282    stp_put32_be(0,v); /* paper_right */
1283    stp_put32_be(0,v); /* paper_top */
1284    stp_put32_be((init->page_width + init->caps->border_left + init->caps->border_right) * unit / 72,v); /* paper_width */
1285    stp_put32_be((init->page_height + init->caps->border_top + init->caps->border_bottom) * unit / 72,v); /* paper_height */
1286    return;
1287  }
1288
1289  canon_cmd(v,ESC28,0x70, 8,
1290   	      arg_70_1, arg_70_2, 0x00, 0x00,
1291	      arg_70_3, arg_70_4, 0x00, 0x00);
1292}
1293
1294/* ESC (P -- 0x50 -- unknown -- :
1295   seems to set media and page information. Different byte lengths depending on printer model. */
1296static void
1297canon_init_setESC_P(const stp_vars_t *v, const canon_privdata_t *init)
1298{
1299  unsigned char arg_ESCP_2;
1300  if(!(init->caps->features & CANON_CAP_P))
1301    return;
1302
1303  arg_ESCP_2 = (init->pt) ? init->pt->media_code_P: 0x00;
1304
1305  /* models that add two more bytes "1 0" to the end of the usual 4-byte sequence: */
1306  /* iP2700 */
1307  /* MX340 */
1308  /* MX350 --- same driver as MX340 */
1309  /* MX360 */
1310  /* MX410 --- same driver as MX360 */
1311  /* MX420 */
1312  /* MX870 */
1313  /* MX880 */
1314  /* MP493 */
1315  /* MP550 */
1316  /* MP640 */
1317  /* iX6500 */
1318  /* iX7000 */
1319  if ( (!strcmp(init->caps->name,"iP2700")) || (!strcmp(init->caps->name,"MX340")) || (!strcmp(init->caps->name,"MX360")) || (!strcmp(init->caps->name,"MX410")) || (!strcmp(init->caps->name,"MX420")) || (!strcmp(init->caps->name,"MX870"))  || (!strcmp(init->caps->name,"MX880"))  || (!strcmp(init->caps->name,"MP550")) || (!strcmp(init->caps->name,"MP493")) || (!strcmp(init->caps->name,"MP640")) || (!strcmp(init->caps->name,"iX6500")) || (!strcmp(init->caps->name,"iX7000")) || (!strcmp(init->caps->name,"iP4700")) || (!strcmp(init->caps->name,"iP4800")) )
1320 /* add a lot more here: try if(init->caps->model_id >= 3) how to guess for 4 bytes or more */
1321    {/* the 4th of the 6 bytes is the media type. 2nd byte is media size. Both read from canon-media array. */
1322
1323      /* arg_ESCP_1 = 0x03; */ /* A4 size */
1324      /* arg_ESCP_2 = 0x00; */ /* plain media */
1325      /*                             size      media                */
1326      canon_cmd( v,ESC28,0x50,6,0x00,0x03,0x00,arg_ESCP_2,0x01,0x00);
1327    }
1328  else
1329    /*                             size      media       */
1330    canon_cmd( v,ESC28,0x50,4,0x00,0x03,0x00,arg_ESCP_2 );
1331}
1332
1333/* ESC (T -- 0x54 -- setCartridge -- :
1334 */
1335static void
1336canon_init_setCartridge(const stp_vars_t *v, const canon_privdata_t *init)
1337{
1338  if (!(init->caps->features & CANON_CAP_T))
1339    return;
1340
1341  canon_cmd(v,ESC28,0x54,3,0x03,0x04,0x04); /* default: both cartridges */
1342}
1343
1344/* ESC (q -- 0x71 -- setPageID -- :
1345 */
1346static void
1347canon_init_setPageID(const stp_vars_t *v, const canon_privdata_t *init)
1348{
1349  if (!(init->caps->features & CANON_CAP_q))
1350    return;
1351
1352  canon_cmd(v,ESC28,0x71, 1, 0x01);
1353}
1354
1355/* ESC (r -- 0x72 --  -- :
1356 */
1357static void
1358canon_init_setX72(const stp_vars_t *v, const canon_privdata_t *init)
1359{
1360  if ( !( (init->caps->features & CANON_CAP_r)
1361         || (init->caps->features & CANON_CAP_rr) ) )
1362    return;
1363
1364  if ( (init->caps->features & CANON_CAP_r)
1365       || (init->caps->features & CANON_CAP_rr) )
1366      canon_cmd(v,ESC28,0x72, 1, init->caps->ESC_r_arg); /* whatever for - 8200/S200 need it */
1367  if (init->caps->features & CANON_CAP_rr)
1368      canon_cmd(v,ESC28,0x72, 3, 0x63, 1, 0); /* whatever for - S200 needs it */
1369      /* probably to set the print direction of the head */
1370}
1371
1372/* ESC (r -- 0x72 -- ??? set direction ??? -- :
1373   only works if quality = 01  (S200) */
1374static void
1375canon_set_X72(const stp_vars_t *v, int x72arg)
1376{
1377  canon_cmd(v,ESC28,0x72, 3, 0x63, x72arg, 0);
1378}
1379
1380/* ESC (t -- 0x74 -- cmdSetImage --:
1381 */
1382static void
1383canon_init_setImage(const stp_vars_t *v, const canon_privdata_t *init)
1384{
1385  unsigned char
1386    arg_74_1 = 0x01, /* 1 bit per pixel */
1387    arg_74_2 = 0x00, /*  */
1388    arg_74_3 = 0x01; /* 01 <= 360 dpi    09 >= 720 dpi */
1389
1390  if (!(init->caps->features & CANON_CAP_t))
1391    return;
1392
1393  if(init->mode->flags & MODE_FLAG_EXTENDED_T)  /*code requires extended mode settings*/
1394  {
1395    int i;
1396    int length = init->mode->num_inks*3 + 3;
1397    unsigned char* buf = stp_zalloc(length);
1398    buf[0]=0x80;
1399    if(init->mode->flags & MODE_FLAG_PRO){
1400        buf[1]=0x90; /* was 0x10, but this should probably be 0x90 */
1401    	buf[2]=0x4;
1402    }else if(init->mode->flags & MODE_FLAG_IP8500){
1403    	buf[1]=0x00;
1404    	buf[2]=0x01;
1405    }else{
1406    	buf[1]=0x80;
1407    	buf[2]=0x01;
1408    }
1409    for(i=0;i<init->mode->num_inks;i++){
1410        if(init->mode->inks[i].ink){
1411          if(init->mode->inks[i].ink->flags & INK_FLAG_5pixel_in_1byte)
1412            buf[3+i*3+0]=(1<<5)|init->mode->inks[i].ink->bits; /*info*/
1413           /*else if(init->mode->inks[i].ink->flags & INK_FLAG_lowresmode)
1414             {
1415               buf[3+i*3+1]=0x01;
1416               buf[3+i*3+0]=init->mode->inks[i].ink->bits;
1417             }*/
1418          else
1419            buf[3+i*3+0]=init->mode->inks[i].ink->bits;
1420
1421          /* workaround for now on the 4-4 inkset and others */
1422          /*if (init->mode->inks[i].ink->bits == 4)
1423            buf[3+i*3+2] = 0x04;*/
1424          /*else if (init->mode->inks[i].ink->bits == 2)
1425            buf[3+i*3+2] = 0x04;*/
1426          /*else if (init->mode->inks[i].ink->bits == 1)
1427            buf[3+i*3+2] = 0x02;*/
1428          buf[3+i*3+2]= init->mode->inks[i].ink->numsizes+1;/*level*/
1429          /*else
1430            buf[3+i*3+2] = 0x00;*/
1431          /* this should show that there is an error */
1432       }
1433    }
1434    stp_zfwrite(ESC28,2,1,v);
1435    stp_putc(0x74,v);
1436    stp_put16_le(length,v);
1437    stp_zfwrite((char*)buf,length,1,v);
1438    stp_free(buf);
1439    return;
1440  }
1441
1442  /* other models mostly hardcoded stuff not really understood ;( */
1443  if (!strcmp(init->caps->name,"S200")) /* 1 bit per pixel (arg 4,7,10,13); */
1444                               /* 2 level per pixel (arg 6,9,12,15) for each color */
1445                               /* though we print only 1bit/pixel - but this is how */
1446                               /* the windows driver works */
1447  {
1448    canon_cmd(v,ESC28,0x74, 30, 0x80, 4, 1, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2,\
1449              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1450    return;
1451  }
1452
1453  if (init->mode->xdpi==1440) arg_74_2= 0x04;
1454  if (init->mode->ydpi>=720)  arg_74_3= 0x09;
1455
1456  if (init->mode->inks[0].ink->bits>1) {
1457    arg_74_1= 0x02;
1458    arg_74_2= 0x80;
1459    arg_74_3= 0x09;
1460    if (init->used_inks == CANON_INK_CMY) arg_74_3= 0x02; /* for BC-06 cartridge!!! */
1461  }
1462
1463  /* workaround for the bjc8200 in 6color mode - not really understood */
1464  if (!strcmp(init->caps->name,"8200")) {
1465    if (init->used_inks == CANON_INK_CcMmYK) {
1466      arg_74_1= 0xff;
1467      arg_74_2= 0x90;
1468      arg_74_3= 0x04;
1469      if (init->mode->ydpi>600)  arg_74_3= 0x09;
1470    } else {
1471      arg_74_1= 0x01;
1472      arg_74_2= 0x00;
1473      arg_74_3= 0x01;
1474      if (init->mode->ydpi>600)  arg_74_3= 0x09;
1475    }
1476  }
1477
1478  canon_cmd(v,ESC28,0x74, 3, arg_74_1, arg_74_2, arg_74_3);
1479}
1480
1481/* ESC (I (J (L
1482 */
1483static void
1484canon_init_setMultiRaster(const stp_vars_t *v, const canon_privdata_t *init){
1485
1486  int i; /* introduced for channel counting */
1487  char* raster_channel_order; /* introduced for channel counting */
1488
1489  if(!(init->caps->features & CANON_CAP_I))
1490	return;
1491
1492  canon_cmd(v,ESC28,0x49, 1, 0x1);  /* enable MultiLine Raster? */
1493  canon_cmd(v,ESC28,0x4a, 1, init->caps->raster_lines_per_block);    /* set number of lines per raster block */
1494
1495  /* set the color sequence */
1496  stp_zfwrite("\033(L", 3, 1, v);
1497  stp_put16_le(init->num_channels, v);
1498  /* add an exception here to add 0x60 of cmy channels for those printers/modes that require it */
1499  raster_channel_order=init->channel_order;
1500  /*  if (!strcmp(init->caps->name,"MP450"))*/
1501    {
1502      /* if cmy there, add 0x60 to each --- this is not yet correct, some modes do not require it! */
1503      /*      if (init->num_channels==7) {*/
1504	for(i=0;i<init->num_channels;i++){
1505	  switch(init->channel_order[i]){
1506	    /* case 'c':raster_channel_order[i]+=0x60; break;;*/
1507	    /* case 'm':raster_channel_order[i]+=0x60; break;;*/
1508	    /* case 'y':raster_channel_order[i]+=0x60; break;;*/
1509	  }
1510	}
1511	/*}*/
1512      stp_zfwrite((const char *)raster_channel_order,init->num_channels, 1, v);
1513    }
1514    /*  else
1515    {
1516      stp_zfwrite((const char *)init->channel_order,init->num_channels, 1, v);
1517      }*/
1518}
1519
1520
1521
1522
1523static void
1524canon_init_printer(const stp_vars_t *v, const canon_privdata_t *init)
1525{
1526  unsigned int mytop;
1527  /* init printer */
1528  if (init->is_first_page) {
1529    canon_init_resetPrinter(v,init);       /* ESC [K */
1530    canon_init_setDuplex(v,init);          /* ESC ($ */
1531  }
1532  canon_init_setPageMode(v,init);        /* ESC (a */
1533  canon_init_setDataCompression(v,init); /* ESC (b */
1534  canon_init_setPageID(v,init);          /* ESC (q */
1535  canon_init_setPrintMode(v,init);       /* ESC (m */
1536  canon_init_setResolution(v,init);      /* ESC (d */
1537  canon_init_setImage(v,init);           /* ESC (t */
1538  canon_init_setColor(v,init);           /* ESC (c */
1539  canon_init_setPageMargins(v,init);     /* ESC (g */
1540  canon_init_setPageMargins2(v,init);    /* ESC (p */
1541  canon_init_setESC_P(v,init);           /* ESC (P */
1542  canon_init_setCartridge(v,init);       /* ESC (T */
1543  canon_init_setTray(v,init);            /* ESC (l */
1544  canon_init_setX72(v,init);             /* ESC (r */
1545  canon_init_setMultiRaster(v,init);     /* ESC (I (J (L */
1546
1547  /* some linefeeds */
1548
1549  mytop= (init->top*init->mode->ydpi)/72;
1550
1551  if(init->caps->features & CANON_CAP_I)
1552    mytop /= init->caps->raster_lines_per_block;
1553
1554  if(mytop)
1555    canon_cmd(v,ESC28,0x65, 2, (mytop >> 8 ),(mytop & 255));
1556}
1557
1558static void
1559canon_deinit_printer(const stp_vars_t *v, const canon_privdata_t *init)
1560{
1561  /* eject page */
1562  stp_putc(0x0c,v);
1563
1564  /* say goodbye */
1565  canon_cmd(v,ESC28,0x62,1,0);
1566  if (init->caps->features & CANON_CAP_a)
1567    canon_cmd(v,ESC28,0x61, 1, 0);
1568}
1569
1570static int
1571canon_start_job(const stp_vars_t *v, stp_image_t *image)
1572{
1573  const canon_cap_t * caps = canon_get_model_capabilities(v);
1574  /* output XML for iP2700 and other devices */
1575  if (caps->features & CANON_CAP_XML) {
1576    int length=strlen(prexml_iP2700); /* 680 */
1577    stp_zfwrite((const char*)prexml_iP2700,length,1,v);
1578  }
1579  return 1;
1580}
1581
1582static int
1583canon_end_job(const stp_vars_t *v, stp_image_t *image)
1584{
1585  const canon_cap_t * caps = canon_get_model_capabilities(v);
1586  canon_cmd(v,ESC40,0,0);
1587  /* output XML for iP2700 and other devices */
1588  if (caps->features & CANON_CAP_XML) {
1589    int length=strlen(postxml_iP2700); /* 263 */
1590    stp_zfwrite((const char*)postxml_iP2700,length,1,v);
1591  }
1592  return 1;
1593}
1594
1595/*
1596 * 'advance_buffer()' - Move (num) lines of length (len) down one line
1597 *                      and sets first line to 0s
1598 *                      accepts NULL pointers as buf
1599 *                  !!! buf must contain more than (num) lines !!!
1600 *                      also sets first line to 0s if num<1
1601 */
1602static void
1603canon_advance_buffer(unsigned char *buf, int len, int num)
1604{
1605  if (!buf || !len) return;
1606  if (num>0) memmove(buf+len,buf,len*num);
1607  memset(buf,0,len);
1608}
1609
1610static void
1611canon_printfunc(stp_vars_t *v)
1612{
1613  int i;
1614  canon_privdata_t *pd = (canon_privdata_t *) stp_get_component_data(v, "Driver");
1615  canon_write_line(v);
1616  for (i = 0; i < pd->num_channels ; i++)
1617    canon_advance_buffer(pd->channels[i].buf, pd->length, pd->channels[i].delay);
1618
1619}
1620
1621static double
1622get_double_param(stp_vars_t *v, const char *param)
1623{
1624  if (param && stp_check_float_parameter(v, param, STP_PARAMETER_ACTIVE))
1625    return stp_get_float_parameter(v, param);
1626  else
1627    return 1.0;
1628}
1629
1630
1631
1632static void
1633set_mask(unsigned char *cd_mask, int x_center, int scaled_x_where,
1634         int limit, int expansion, int invert)
1635{
1636  int clear_val = invert ? 255 : 0;
1637  int set_val = invert ? 0 : 255;
1638  int bytesize = 8 / expansion;
1639  int byteextra = bytesize - 1;
1640  int first_x_on = x_center - scaled_x_where;
1641  int first_x_off = x_center + scaled_x_where;
1642  if (first_x_on < 0)
1643    first_x_on = 0;
1644  if (first_x_on > limit)
1645    first_x_on = limit;
1646  if (first_x_off < 0)
1647    first_x_off = 0;
1648  if (first_x_off > limit)
1649    first_x_off = limit;
1650  first_x_on += byteextra;
1651  if (first_x_off > (first_x_on - byteextra))
1652    {
1653      int first_x_on_byte = first_x_on / bytesize;
1654      int first_x_on_mod = expansion * (byteextra - (first_x_on % bytesize));
1655      int first_x_on_extra = ((1 << first_x_on_mod) - 1) ^ clear_val;
1656      int first_x_off_byte = first_x_off / bytesize;
1657      int first_x_off_mod = expansion * (byteextra - (first_x_off % bytesize));
1658      int first_x_off_extra = ((1 << 8) - (1 << first_x_off_mod)) ^ clear_val;
1659      if (first_x_off_byte < first_x_on_byte)
1660        {
1661          /* This can happen, if 6 or fewer points are turned on */
1662          cd_mask[first_x_on_byte] = first_x_on_extra & first_x_off_extra;
1663        }
1664      else
1665        {
1666          if (first_x_on_extra != clear_val)
1667
1668            cd_mask[first_x_on_byte - 1] = first_x_on_extra;
1669          if (first_x_off_byte > first_x_on_byte)
1670            memset(cd_mask + first_x_on_byte, set_val,
1671                   first_x_off_byte - first_x_on_byte);
1672          if (first_x_off_extra != clear_val)
1673            cd_mask[first_x_off_byte] = first_x_off_extra;
1674        }
1675    }
1676}
1677
1678
1679/* get delay settings for the specified color and mode */
1680static int canon_get_delay(canon_privdata_t* privdata,char color){
1681    int i=0;
1682    int delay = 0;
1683    const canon_delay_t* delaylist = privdata->mode->delay;
1684
1685    while(delaylist && delaylist[i].color){
1686        if(delaylist[i].color == color){
1687           delay = delaylist[i].delay;
1688           break;
1689        }
1690        ++i;
1691    }
1692    if(delay > privdata->delay_max)
1693       privdata->delay_max = delay;
1694    return delay;
1695}
1696
1697
1698/* add a single channel to the dither engine */
1699static int canon_setup_channel(stp_vars_t *v,canon_privdata_t* privdata,int channel,int subchannel,const canon_inkset_t* ink,stp_shade_t** shades){
1700    if(ink->channel && ink->density > 0.0){
1701        int delay = canon_get_delay(privdata,ink->channel);
1702        canon_channel_t* current;
1703        /* create a new channel */
1704        privdata->channels = stp_realloc(privdata->channels,sizeof(canon_channel_t) * (privdata->num_channels + 1));
1705        privdata->channel_order = stp_realloc(privdata->channel_order,privdata->num_channels + 2);
1706        /* update channel order */
1707        privdata->channel_order[privdata->num_channels]=ink->channel;
1708        privdata->channel_order[privdata->num_channels+1]='\0';
1709        current = &(privdata->channels[privdata->num_channels]);
1710        ++privdata->num_channels;
1711        /* fill ink properties */
1712        current->name = ink->channel;
1713        current->props = ink->ink;
1714        current->delay = delay;
1715        /* calculate buffer length */
1716        current->buf_length = ((privdata->length * current->props->bits)+1)*(delay + 1);
1717        /* update maximum buffer length */
1718        if(current->buf_length > privdata->buf_length_max)
1719             privdata->buf_length_max = current->buf_length;
1720        /* allocate buffer for the raster data */
1721        current->buf = stp_zalloc(current->buf_length + 1);
1722        /* add channel to the dither engine */
1723        stp_dither_add_channel(v, current->buf , channel , subchannel);
1724
1725        /* add shades to the shades array */
1726        *shades = stp_realloc(*shades,(subchannel + 1) * sizeof(stp_shade_t));
1727	/* move previous shades up one position as set_inks_full expects the subchannels first */
1728	if(subchannel)
1729		memcpy(*shades + 1,*shades,sizeof(stp_shade_t) * subchannel);
1730        (*shades)[0].value = ink->density;
1731        (*shades)[0].numsizes = ink->ink->numsizes;
1732        (*shades)[0].dot_sizes = ink->ink->dot_sizes;
1733        return 1;
1734    }
1735    return 0;
1736}
1737
1738
1739
1740
1741
1742/* setup the dither channels */
1743static void canon_setup_channels(stp_vars_t *v,canon_privdata_t* privdata){
1744    /* (in gutenprint notation) => KCMY,  1230 => CMYK etc. */
1745    const char default_channel_order[STP_NCOLORS] = {0,1,2,3};
1746    /* codes for the primary channels */
1747    const char primary[STP_NCOLORS] = {'K','C','M','Y',};
1748    /* codes for the subchannels */
1749    const char secondary[STP_NCOLORS] = {'k','c','m','y'};
1750    /* names of the density adjustment controls */
1751    const char *primary_density_control[STP_NCOLORS] = {"BlackDensity","CyanDensity","MagentaDensity","YellowDensity"};
1752    const char *secondary_density_control[STP_NCOLORS] = {NULL,"LightCyanTrans","LightMagentaTrans","LightYellowTrans"};
1753    /* ink darkness for every channel */
1754    const double ink_darkness[] = {1.0, 0.31 / .5, 0.61 / .97, 0.08};
1755    const char* channel_order = default_channel_order;
1756
1757
1758
1759    int channel;
1760    int channel_idx;
1761
1762    if(privdata->caps->channel_order)
1763        channel_order = privdata->caps->channel_order;
1764
1765
1766    /* loop through the dither channels */
1767    for(channel_idx = 0; channel_idx < STP_NCOLORS ; channel_idx++){
1768        int i;
1769        unsigned int subchannel = 0;
1770        stp_shade_t* shades = NULL;
1771	int is_black_channel = 0;
1772        channel = channel_order[channel_idx];
1773        if(channel == STP_ECOLOR_K && privdata->used_inks & CANON_INK_K_MASK){ /* black channel */
1774            /* find K and k inks */
1775            for(i=0;i<privdata->mode->num_inks;i++){
1776                const canon_inkset_t* ink = &privdata->mode->inks[i];
1777                if(ink->channel == primary[channel] || ink->channel == secondary[channel])
1778                    subchannel += canon_setup_channel(v,privdata,channel,subchannel,ink,&shades);
1779            }
1780	    is_black_channel = 1;
1781        }else if(channel != STP_ECOLOR_K && privdata->used_inks & CANON_INK_CMY_MASK){  /* color channels */
1782            for(i=0;i<privdata->mode->num_inks;i++){
1783                const canon_inkset_t* ink = &privdata->mode->inks[i];
1784                if(ink->channel == primary[channel] || ((privdata->used_inks & CANON_INK_CcMmYyKk_MASK) && (ink->channel == secondary[channel])))
1785                    subchannel += canon_setup_channel(v,privdata,channel,subchannel,ink,&shades);
1786            }
1787        }
1788
1789        /* set inks and density */
1790        if(shades){
1791          stp_dither_set_inks_full(v,channel, subchannel, shades, 1.0, ink_darkness[channel]);
1792          for(i=0;i<subchannel;i++){
1793            double density = get_double_param(v, primary_density_control[channel]) * get_double_param(v, "Density");
1794            if(i > 0 && secondary_density_control[channel])
1795              density *= get_double_param(v, secondary_density_control[channel]);
1796            stp_channel_set_density_adjustment(v,channel,subchannel,density);
1797          }
1798	  if (is_black_channel)
1799	    stp_channel_set_black_channel(v, channel);
1800          stp_free(shades);
1801        }
1802    }
1803}
1804
1805
1806
1807
1808
1809
1810
1811/* FIXME move this to printercaps */
1812#define CANON_CD_X 176
1813#define CANON_CD_Y 405
1814
1815static void setup_page(stp_vars_t* v,canon_privdata_t* privdata){
1816  const char    *media_source = stp_get_string_parameter(v, "InputSlot");
1817  const char *cd_type = stp_get_string_parameter(v, "PageSize");
1818  int print_cd= (media_source && (!strcmp(media_source, "CD")));
1819  int           page_left,
1820                page_top,
1821                page_right,
1822                page_bottom;
1823  int hub_size = 0;
1824
1825
1826  if (cd_type && (strcmp(cd_type, "CDCustom") == 0 ))
1827     {
1828	int outer_diameter = stp_get_dimension_parameter(v, "CDOuterDiameter");
1829	stp_set_page_width(v, outer_diameter);
1830	stp_set_page_height(v, outer_diameter);
1831	stp_set_width(v, outer_diameter);
1832	stp_set_height(v, outer_diameter);
1833	hub_size = stp_get_dimension_parameter(v, "CDInnerDiameter");
1834     }
1835 else
1836    {
1837	const char *inner_radius_name = stp_get_string_parameter(v, "CDInnerRadius");
1838  	hub_size = 43 * 10 * 72 / 254;		/* 43 mm standard CD hub */
1839
1840  	if (inner_radius_name && strcmp(inner_radius_name, "Small") == 0)
1841   	  hub_size = 16 * 10 * 72 / 254;		/* 15 mm prints to the hole - play it
1842				   safe and print 16 mm */
1843    }
1844
1845  privdata->top = stp_get_top(v);
1846  privdata->left = stp_get_left(v);
1847  privdata->out_width = stp_get_width(v);
1848  privdata->out_height = stp_get_height(v);
1849
1850  internal_imageable_area(v, 0, &page_left, &page_right,
1851                          &page_bottom, &page_top);
1852  if (print_cd) {
1853    privdata->cd_inner_radius = hub_size / 2;
1854    privdata->cd_outer_radius = stp_get_width(v) / 2;
1855    privdata->left = CANON_CD_X - privdata->cd_outer_radius + stp_get_dimension_parameter(v, "CDXAdjustment");;
1856    privdata->top = CANON_CD_Y - privdata->cd_outer_radius + stp_get_dimension_parameter(v, "CDYAdjustment");
1857    privdata->page_width = privdata->left + privdata->out_width;
1858    privdata->page_height = privdata->top + privdata->out_height;
1859  } else {
1860    privdata->left -= page_left;
1861    privdata->top -= page_top;
1862    privdata->page_width = page_right - page_left;
1863    privdata->page_height = page_bottom - page_top;
1864  }
1865
1866}
1867
1868
1869/* combine all curve parameters in s and apply them */
1870static void canon_set_curve_parameter(stp_vars_t *v,const char* type,stp_curve_compose_t comp,const char* s1,const char* s2,const char* s3){
1871  const char * s[3];
1872  size_t count = sizeof(s) / sizeof(s[0]);
1873  stp_curve_t *ret = NULL;
1874  int curve_count = 0;
1875  int i;
1876  const size_t piecewise_point_count = 384;
1877
1878
1879  /* ignore settings from the printercaps if the user specified his own parameters */
1880  if(stp_check_curve_parameter(v,type, STP_PARAMETER_ACTIVE))
1881    return;
1882
1883  /* init parameter list (FIXME pass array directly???)*/
1884  s[0] = s1;
1885  s[1] = s2;
1886  s[2] = s3;
1887
1888  /* skip empty curves */
1889  for(i=0;i<count;i++){
1890    if(s[i])
1891      s[curve_count++] = s[i];
1892  }
1893
1894  /* combine curves */
1895  if(curve_count){
1896    for(i=0;i<curve_count;i++){
1897      stp_curve_t* t_tmp = stp_curve_create_from_string(s[i]);
1898      if(t_tmp){
1899        if(stp_curve_is_piecewise(t_tmp)){
1900          stp_curve_resample(t_tmp, piecewise_point_count);
1901        }
1902        if(!ret){
1903          ret = t_tmp;
1904        }else{
1905          stp_curve_t* t_comp = NULL;
1906          stp_curve_compose(&t_comp, ret, t_tmp, comp, -1);
1907          if(t_comp){
1908            stp_curve_destroy(ret);
1909            ret = t_comp;
1910          }
1911          stp_curve_destroy(t_tmp);
1912        }
1913      }
1914    }
1915  }
1916
1917  /* apply result */
1918  if(ret){
1919    stp_set_curve_parameter(v, type, ret);
1920    stp_curve_destroy(ret);
1921  }
1922}
1923
1924/*
1925 * 'canon_print()' - Print an image to a CANON printer.
1926 */
1927static int
1928canon_do_print(stp_vars_t *v, stp_image_t *image)
1929{
1930  int i;
1931  int		status = 1;
1932  const char	*media_source = stp_get_string_parameter(v, "InputSlot");
1933  const char    *duplex_mode =stp_get_string_parameter(v, "Duplex");
1934  int           page_number = stp_get_int_parameter(v, "PageNumber");
1935  const canon_cap_t * caps= canon_get_model_capabilities(v);
1936  int		y;		/* Looping vars */
1937  canon_privdata_t privdata;
1938  int		errdiv,		/* Error dividend */
1939		errmod,		/* Error modulus */
1940		errval,		/* Current error value */
1941		errline,	/* Current raster line */
1942		errlast,	/* Last raster line loaded */
1943		out_channels;	/* Output bytes per pixel */
1944  unsigned	zero_mask;
1945  int           print_cd= (media_source && (!strcmp(media_source, "CD")));
1946  int           image_height,
1947                image_width;
1948  double        k_upper, k_lower;
1949  unsigned char *cd_mask = NULL;
1950  double outer_r_sq = 0;
1951  double inner_r_sq = 0;
1952  unsigned char* weave_cols[4] ; /* TODO clean up weaving code to be more generic */
1953
1954  if (!stp_verify(v))
1955    {
1956      stp_eprintf(v, "Print options not verified; cannot print.\n");
1957      return 0;
1958    }
1959  /*
1960  * Setup a read-only pixel region for the entire image...
1961  */
1962
1963  stp_image_init(image);
1964
1965
1966  /* rotate even pages for DuplexNoTumble */
1967  if((page_number & 1) && duplex_mode && !strcmp(duplex_mode,"DuplexNoTumble"))
1968  	image = stpi_buffer_image(image,BUFFER_FLAG_FLIP_X | BUFFER_FLAG_FLIP_Y);
1969
1970  memset(&privdata,0,sizeof(canon_privdata_t));
1971  privdata.caps = caps;
1972
1973  /* find the wanted print mode */
1974  privdata.mode = canon_get_current_mode(v);
1975
1976  /* set quality */
1977  privdata.quality = privdata.mode->quality;
1978
1979  /* force grayscale if image is grayscale
1980   *                 or single black cartridge installed
1981   */
1982  privdata.used_inks = canon_printhead_colors(v);
1983  if (privdata.used_inks == CANON_INK_K)
1984      stp_set_string_parameter(v, "PrintingMode", "BW");
1985
1986  setup_page(v,&privdata);
1987
1988  image_height = stp_image_height(image);
1989  image_width = stp_image_width(image);
1990
1991  privdata.pt = get_media_type(caps,stp_get_string_parameter(v, "MediaType"));
1992  privdata.slot = canon_source_type(media_source,caps);
1993  privdata.duplex_str = duplex_mode;
1994  privdata.is_first_page = (page_number == 0);
1995
1996 /*
1997  * Convert image size to printer resolution...
1998  */
1999
2000  privdata.out_width  = privdata.mode->xdpi * privdata.out_width / 72;
2001  privdata.out_height = privdata.mode->ydpi * privdata.out_height / 72;
2002
2003  privdata.left = privdata.mode->xdpi * privdata.left / 72;
2004
2005  stp_deprintf(STP_DBG_CANON,"density is %f\n",
2006               stp_get_float_parameter(v, "Density"));
2007
2008  /*
2009   * Compute the LUT.  For now, it's 8 bit, but that may eventually
2010   * sometimes change.
2011   */
2012
2013  if (!stp_check_float_parameter(v, "Density", STP_PARAMETER_DEFAULTED))
2014    {
2015      stp_set_float_parameter_active(v, "Density", STP_PARAMETER_ACTIVE);
2016      stp_set_float_parameter(v, "Density", 1.0);
2017    }
2018
2019  stp_scale_float_parameter(v, "Density", privdata.pt->base_density);
2020  stp_scale_float_parameter(v, "Density",privdata.mode->density);
2021
2022  if (stp_get_float_parameter(v, "Density") > 1.0)
2023    stp_set_float_parameter(v, "Density", 1.0);
2024
2025  if (privdata.used_inks == CANON_INK_K)
2026    stp_scale_float_parameter(v, "Gamma", 1.25);
2027  stp_scale_float_parameter( v, "Gamma", privdata.mode->gamma );
2028
2029  stp_deprintf(STP_DBG_CANON,"density is %f\n",
2030               stp_get_float_parameter(v, "Density"));
2031
2032  if(privdata.used_inks & CANON_INK_CMYK_MASK)
2033    stp_set_string_parameter(v, "STPIOutputType", "KCMY");
2034  else if(privdata.used_inks & CANON_INK_CMY_MASK)
2035    stp_set_string_parameter(v, "STPIOutputType", "CMY");
2036  else
2037    stp_set_string_parameter(v, "STPIOutputType", "Grayscale");
2038
2039  privdata.length = (privdata.out_width + 7) / 8;
2040
2041  stp_dither_init(v, image, privdata.out_width, privdata.mode->xdpi, privdata.mode->ydpi);
2042
2043  canon_setup_channels(v,&privdata);
2044
2045
2046  stp_deprintf(STP_DBG_CANON,
2047	       "canon: driver will use colors %s\n",privdata.channel_order);
2048
2049  /* Allocate compression buffer */
2050  if(caps->features & CANON_CAP_I)
2051      privdata.comp_buf = stp_zalloc(privdata.buf_length_max * 2 * caps->raster_lines_per_block * privdata.num_channels); /* for multiraster we need to buffer 8 lines for every color */
2052  else
2053      privdata.comp_buf = stp_zalloc(privdata.buf_length_max * 2);
2054  /* Allocate fold buffer */
2055  privdata.fold_buf = stp_zalloc(privdata.buf_length_max);
2056
2057
2058
2059 /*
2060  * Output the page...
2061  */
2062
2063   /* FIXME this is probably broken, kept for backward compatibility */
2064   if(privdata.num_channels > 4){
2065       k_lower = 0.4 / privdata.channels[4].props->bits + .1;
2066   }else
2067       k_lower = 0.25;
2068
2069  k_lower *= privdata.pt->k_lower_scale;
2070  k_upper = privdata.pt->k_upper;
2071
2072  if (!stp_check_float_parameter(v, "GCRLower", STP_PARAMETER_ACTIVE))
2073    stp_set_default_float_parameter(v, "GCRLower", k_lower);
2074  if (!stp_check_float_parameter(v, "GCRUpper", STP_PARAMETER_ACTIVE))
2075    stp_set_default_float_parameter(v, "GCRUpper", k_upper);
2076
2077
2078  /* init the printer */
2079  canon_init_printer(v, &privdata);
2080
2081  /* initialize weaving for S200 for resolutions > 360dpi */
2082  if (privdata.mode->flags & MODE_FLAG_WEAVE)
2083     {
2084       char weave_color_order[] = "KCMY";
2085
2086       privdata.stepper_ydpi = 720;
2087       privdata.nozzle_ydpi = 360;
2088       if (privdata.mode->xdpi == 2880)
2089         privdata.physical_xdpi = 2880;
2090       else
2091         privdata.physical_xdpi = 720;
2092
2093       stp_deprintf(STP_DBG_CANON,"canon: adjust leftskip: old=%d,\n", privdata.left);
2094       privdata.left = (int)( (float)privdata.left * (float)privdata.physical_xdpi / (float)privdata.mode->xdpi ); /* adjust left margin */
2095       stp_deprintf(STP_DBG_CANON,"canon: adjust leftskip: new=%d,\n", privdata.left);
2096
2097       privdata.ncolors = 4;
2098       privdata.head_offset = stp_zalloc(sizeof(int) * privdata.ncolors);
2099       memset(privdata.head_offset, 0, sizeof(privdata.head_offset));
2100
2101       if ( privdata.used_inks == CANON_INK_K )
2102           privdata.nozzles = 64; /* black nozzles */
2103       else
2104           privdata.nozzles = 24; /* color nozzles */
2105       if ( privdata.used_inks == CANON_INK_K )
2106         {
2107           privdata.ncolors = 1;
2108           privdata.head_offset[0] = 0; /* K starts at 0 */
2109           privdata.head_offset[1] = 0 ;/* how far C starts after K */
2110           privdata.head_offset[2] = 0;/* how far M starts after K */
2111           privdata.head_offset[3] = 0;/* how far Y starts after K */
2112           privdata.top += 11;
2113         }
2114       else if ( privdata.used_inks == CANON_INK_CMYK )
2115         {
2116           privdata.head_offset[0] = 0; /* K starts at 0 */
2117           privdata.head_offset[1] = 144 ;/* how far C starts after K */
2118           privdata.head_offset[2] = 144 + 64;/* how far M starts after K */
2119           privdata.head_offset[3] = 144 + 64 + 64;/* how far Y starts after K */
2120           privdata.top += 5;
2121         }
2122       else  /* colormode == CMY */
2123         {
2124           privdata.head_offset[0] = 0; /* K starts at 0 */
2125           privdata.head_offset[1] = 0 ;/* how far C starts after K */
2126           privdata.head_offset[2] = 64;/* how far M starts after K */
2127           privdata.head_offset[3] = 128;/* how far Y starts after K */
2128           privdata.top += 18;
2129         }
2130
2131       privdata.nozzle_separation = privdata.stepper_ydpi / privdata.nozzle_ydpi;
2132       privdata.horizontal_passes = privdata.mode->xdpi / privdata.physical_xdpi;
2133       privdata.vertical_passes = 1;
2134       privdata.vertical_oversample = privdata.mode->ydpi / privdata.stepper_ydpi;
2135       privdata.bidirectional = 1; /* 1: bidirectional; 0: unidirectional  printing */
2136       privdata.direction = 1;
2137       stp_allocate_component_data(v, "Driver", NULL, NULL, &privdata);
2138       stp_deprintf(STP_DBG_CANON,"canon: initializing weaving: nozzles=%d, nozzle_separation=%d,\n"
2139                                    "horizontal_passes=%d, vertical_passes=%d,vertical_oversample=%d,\n"
2140                                    "ncolors=%d, out_width=%d, out_height=%d\n"
2141                                    "weave_top=%d, weave_page_height=%d \n"
2142                                    "head_offset=[%d,%d,%d,%d]  \n",
2143                                    privdata.nozzles, privdata.nozzle_separation,
2144                                    privdata.horizontal_passes, privdata.vertical_passes,
2145                                    privdata.vertical_oversample, privdata.ncolors,
2146                                    privdata.out_width, privdata.out_height,
2147                                    privdata.top * privdata.stepper_ydpi / 72, privdata.page_height * privdata.stepper_ydpi / 72,
2148                                    privdata.head_offset[0],privdata.head_offset[1],
2149                                    privdata.head_offset[2],privdata.head_offset[3]);
2150
2151       stp_initialize_weave(v, privdata.nozzles, privdata.nozzle_separation,
2152                                privdata.horizontal_passes, privdata.vertical_passes,
2153                                privdata.vertical_oversample, privdata.ncolors,
2154                                1,
2155                                privdata.out_width, privdata.out_height,
2156                                privdata.top * privdata.stepper_ydpi / 72,
2157                                privdata.page_height * privdata.stepper_ydpi / 72,
2158                                privdata.head_offset,
2159                                STP_WEAVE_ZIGZAG,
2160                                canon_flush_pass,
2161                                stp_fill_uncompressed,
2162                                stp_pack_uncompressed,
2163                                stp_compute_uncompressed_linewidth);
2164       privdata.last_pass_offset = 0;
2165
2166
2167       for(i=0;i<4;i++){
2168           int x;
2169           for(x=0;x<privdata.num_channels;x++){
2170               if(weave_color_order[i] == privdata.channel_order[x])
2171                   weave_cols[i] = privdata.channels[x].buf;
2172                   privdata.weave_bits[i] = privdata.channels[x].props->bits;
2173           }
2174       }
2175  }
2176
2177
2178  errdiv  = image_height / privdata.out_height;
2179  errmod  = image_height % privdata.out_height;
2180  errval  = 0;
2181  errlast = -1;
2182  errline  = 0;
2183
2184  /* set Hue, Lum and Sat Maps */
2185  canon_set_curve_parameter(v,"HueMap",STP_CURVE_COMPOSE_ADD,caps->hue_adjustment,privdata.pt->hue_adjustment,privdata.mode->hue_adjustment);
2186  canon_set_curve_parameter(v,"LumMap",STP_CURVE_COMPOSE_MULTIPLY,caps->lum_adjustment,privdata.pt->lum_adjustment,privdata.mode->lum_adjustment);
2187  canon_set_curve_parameter(v,"SatMap",STP_CURVE_COMPOSE_MULTIPLY,caps->sat_adjustment,privdata.pt->sat_adjustment,privdata.mode->sat_adjustment);
2188
2189  out_channels = stp_color_init(v, image, 65536);
2190  stp_allocate_component_data(v, "Driver", NULL, NULL, &privdata);
2191
2192  privdata.emptylines = 0;
2193  if (print_cd) {
2194    cd_mask = stp_malloc(1 + (privdata.out_width + 7) / 8);
2195    outer_r_sq = (double)privdata.cd_outer_radius * (double)privdata.cd_outer_radius;
2196    inner_r_sq = (double)privdata.cd_inner_radius * (double)privdata.cd_inner_radius;
2197  }
2198  for (y = 0; y < privdata.out_height; y ++)
2199  {
2200    int duplicate_line = 1;
2201
2202    if (errline != errlast)
2203    {
2204      errlast = errline;
2205      duplicate_line = 0;
2206      if (stp_color_get_row(v, image, errline, &zero_mask))
2207	{
2208	  status = 2;
2209	  break;
2210	}
2211    }
2212    if (print_cd)
2213      {
2214	int x_center = privdata.cd_outer_radius * privdata.mode->xdpi / 72;
2215	int y_distance_from_center =
2216	  privdata.cd_outer_radius - (y * 72 / privdata.mode->ydpi);
2217	if (y_distance_from_center < 0)
2218	  y_distance_from_center = -y_distance_from_center;
2219	memset(cd_mask, 0, (privdata.out_width + 7) / 8);
2220	if (y_distance_from_center < privdata.cd_outer_radius)
2221	  {
2222	    double y_sq = (double) y_distance_from_center *
2223	      (double) y_distance_from_center;
2224	    int x_where = sqrt(outer_r_sq - y_sq) + .5;
2225	    int scaled_x_where = x_where * privdata.mode->xdpi / 72;
2226	    set_mask(cd_mask, x_center, scaled_x_where,
2227		     privdata.out_width, 1, 0);
2228	    if (y_distance_from_center < privdata.cd_inner_radius)
2229	      {
2230		x_where = sqrt(inner_r_sq - y_sq) + .5;
2231		scaled_x_where = x_where * privdata.mode->ydpi / 72;
2232		set_mask(cd_mask, x_center, scaled_x_where,
2233			 privdata.out_width, 1, 1);
2234	      }
2235	  }
2236      }
2237    stp_dither(v, y, duplicate_line, zero_mask, cd_mask);
2238    if ( privdata.mode->flags & MODE_FLAG_WEAVE )
2239        stp_write_weave(v, weave_cols);
2240    else if ( caps->features & CANON_CAP_I)
2241        canon_write_multiraster(v,&privdata,y);
2242    else
2243        canon_printfunc(v);
2244    errval += errmod;
2245    errline += errdiv;
2246    if (errval >= privdata.out_height)
2247    {
2248      errval -= privdata.out_height;
2249      errline ++;
2250    }
2251  }
2252
2253  if ( privdata.mode->flags & MODE_FLAG_WEAVE )
2254  {
2255      stp_flush_all(v);
2256      canon_advance_paper(v, 5);
2257  }
2258  else
2259  {
2260
2261  /*
2262   * Flush delayed buffers...
2263   */
2264
2265  if (privdata.delay_max) {
2266    stp_deprintf(STP_DBG_CANON,"\ncanon: flushing %d possibly delayed buffers\n",
2267		 privdata.delay_max);
2268    for (y= 0; y<privdata.delay_max; y++) {
2269
2270      canon_write_line(v);
2271      for (i = 0; i < privdata.num_channels; i++)
2272	canon_advance_buffer(privdata.channels[i].buf, privdata.length,
2273			     privdata.channels[i].delay);
2274    }
2275  }
2276  }
2277  stp_image_conclude(image);
2278
2279 /*
2280  * Cleanup...
2281  */
2282
2283  stp_free(privdata.fold_buf);
2284  stp_free(privdata.comp_buf);
2285
2286  if(cd_mask)
2287      stp_free(cd_mask);
2288
2289
2290  canon_deinit_printer(v, &privdata);
2291  /* canon_end_job does not get called for jobmode automatically */
2292  if(!stp_get_string_parameter(v, "JobMode") ||
2293    strcmp(stp_get_string_parameter(v, "JobMode"), "Page") == 0){
2294    canon_end_job(v,image);
2295  }
2296
2297  for(i=0;i< privdata.num_channels;i++)
2298      if(privdata.channels[i].buf)
2299          stp_free(privdata.channels[i].buf);
2300  if(privdata.channels)
2301      stp_free(privdata.channels);
2302
2303  stp_free(privdata.channel_order);
2304  if (privdata.head_offset)
2305    stp_free(privdata.head_offset);
2306
2307
2308  return status;
2309}
2310
2311static int
2312canon_print(const stp_vars_t *v, stp_image_t *image)
2313{
2314  int status;
2315  stp_vars_t *nv = stp_vars_create_copy(v);
2316  stp_prune_inactive_options(nv);
2317  status = canon_do_print(nv, image);
2318  stp_vars_destroy(nv);
2319  return status;
2320}
2321
2322static const stp_printfuncs_t print_canon_printfuncs =
2323{
2324  canon_list_parameters,
2325  canon_parameters,
2326  stp_default_media_size,
2327  canon_imageable_area,
2328  canon_imageable_area,
2329  canon_limit,
2330  canon_print,
2331  canon_describe_resolution,
2332  canon_describe_output,
2333  stp_verify_printer_params,
2334  canon_start_job,
2335  canon_end_job,
2336  NULL
2337};
2338
2339static void
2340canon_shift_buffer(unsigned char *line,int length,int bits)
2341{
2342  int i,j;
2343  for (j=0; j<bits; j++) {
2344    for (i=length-1; i>0; i--) {
2345      line[i]= (line[i] >> 1) | (line[i-1] << 7);
2346    }
2347    line[0] = line[0] >> 1;
2348  }
2349}
2350
2351
2352/* fold, apply 5 pixel in 1 byte compression, pack tiff and return the compressed length */
2353static int canon_compress(stp_vars_t *v, canon_privdata_t *pd, unsigned char* line,int length,int offset,unsigned char* comp_buf,int bits, int ink_flags)
2354{
2355  unsigned char
2356    *in_ptr= line,
2357    *comp_ptr, *comp_data;
2358  int offset2,bitoffset;
2359
2360  /* Don't send blank lines... */
2361
2362  if (line[0] == 0 && memcmp(line, line + 1, (length * bits)  - 1) == 0)
2363    return 0;
2364
2365  offset2 = offset / 8;
2366  bitoffset = offset % 8;
2367
2368  /* fold lsb/msb pairs if drop modulation is active */
2369
2370
2371  if (bits==2) {
2372    int pixels_per_byte = 4;
2373    if(ink_flags & INK_FLAG_5pixel_in_1byte)
2374      pixels_per_byte = 5;
2375
2376    stp_fold(line,length,pd->fold_buf);
2377    in_ptr= pd->fold_buf;
2378    length= (length*8/4); /* 4 pixels in 8bit */
2379    /* calculate the number of compressed bytes that can be sent directly */
2380    offset2 = offset / pixels_per_byte;
2381    /* calculate the number of (uncompressed) bits that have to be added to the raster data */
2382    bitoffset = (offset % pixels_per_byte) * 2;
2383  }
2384  else if (bits==3) {
2385    stp_fold_3bit_323(line,length,pd->fold_buf);
2386    in_ptr= pd->fold_buf;
2387    length= (length*8)/3;
2388    offset2 = offset/3;
2389#if 0
2390    switch(offset%3){
2391    case 0: offset= (offset/3)*8;   break;
2392    case 1: offset= (offset/3)*8/*+3 CAREFUL! CANNOT SHIFT _AFTER_ RECODING!!*/; break;
2393    case 2: offset= (offset/3)*8/*+5 CAREFUL! CANNOT SHIFT _AFTER_ RECODING!!*/; break;
2394    }
2395#endif
2396    bitoffset= 0;
2397  }
2398  else if (bits==4) {
2399    stp_fold_4bit(line,length,pd->fold_buf);
2400    in_ptr= pd->fold_buf;
2401    length= (length*8)/2;
2402    offset2 = offset / 2;
2403    bitoffset= offset % 2;
2404  }
2405
2406  /* pack left border rounded to multiples of 8 dots */
2407
2408  comp_data= comp_buf;
2409  while (offset2>0) {
2410    unsigned char toffset = offset2 > 127 ? 127 : offset2;
2411    comp_data[0] = 1 - toffset;
2412    comp_data[1] = 0;
2413    comp_data += 2;
2414    offset2-= toffset;
2415  }
2416  if (bitoffset) {
2417    if (bitoffset<8)
2418    {
2419       in_ptr[ length++ ] = 0;
2420       canon_shift_buffer(in_ptr,length,bitoffset);
2421    }
2422    else if (bitoffset == 8)
2423    {
2424      memmove(in_ptr + 1,in_ptr,length++);
2425      in_ptr[0] = 0;
2426    }
2427    else
2428      stp_deprintf(STP_DBG_CANON,"SEVERE BUG IN print-canon.c::canon_write() "
2429	      "bitoffset=%d!!\n",bitoffset);
2430  }
2431
2432    if(ink_flags & INK_FLAG_5pixel_in_1byte)
2433       length = pack_pixels(in_ptr,length);
2434
2435  stp_pack_tiff(v, in_ptr, length, comp_data, &comp_ptr, NULL, NULL);
2436
2437  return comp_ptr - comp_buf;
2438}
2439
2440/*
2441 * 'canon_write()' - Send graphics using TIFF packbits compression.
2442 */
2443
2444static int
2445canon_write(stp_vars_t *v,		/* I - Print file or command */
2446            canon_privdata_t *pd,       /* privdata */
2447	    const canon_cap_t *   caps,	        /* I - Printer model */
2448	    unsigned char *line,	/* I - Output bitmap data */
2449	    int           length,	/* I - Length of bitmap data */
2450	    int           coloridx,	/* I - Which color */
2451	    int           *empty,       /* IO- Preceeding empty lines */
2452	    int           width,	/* I - Printed width */
2453	    int           offset, 	/* I - Offset from left side */
2454	    int           bits,
2455            int           ink_flags)
2456{
2457
2458  unsigned char color;
2459  int newlength = canon_compress(v,pd,line,length,offset,pd->comp_buf,bits,ink_flags);
2460  if(!newlength)
2461      return 0;
2462  /* send packed empty lines if any */
2463
2464  if (*empty) {
2465    stp_zfwrite("\033\050\145\002\000", 5, 1, v);
2466    stp_put16_be(*empty, v);
2467    *empty= 0;
2468  }
2469
2470 /* Send a line of raster graphics... */
2471
2472  stp_zfwrite("\033\050\101", 3, 1, v);
2473  stp_put16_le(newlength + 1, v);
2474  color= "CMYKcmyk"[coloridx];
2475  if (!color) color= 'K';
2476  stp_putc(color,v);
2477  stp_zfwrite((const char *)pd->comp_buf, newlength, 1, v);
2478  stp_putc('\015', v);
2479  return 1;
2480}
2481
2482
2483static void
2484canon_write_line(stp_vars_t *v)
2485{
2486  canon_privdata_t *pd =
2487    (canon_privdata_t *) stp_get_component_data(v, "Driver");
2488  char write_sequence[] = "KYMCymck";
2489  static const int write_number[] = { 3, 2, 1, 0, 6, 5, 4, 7 };   /* KYMCymc */
2490  int i;
2491  int written= 0;
2492  for (i = 0; i < strlen(write_sequence) ; i++)
2493    {
2494      int x;
2495      const canon_channel_t* channel=NULL;
2496      int num = write_number[i];
2497
2498      /* TODO optimize => move reorder code to do_print */
2499      for(x=0;x < pd->num_channels; x++){
2500          if(pd->channels[x].name == write_sequence[i]){
2501              channel = &(pd->channels[x]);
2502              break;
2503          }
2504      }
2505      if(channel){
2506        written += canon_write(v, pd, pd->caps,
2507                               channel->buf + channel->delay * pd->length /*buf_length[i]*/,
2508                               pd->length, num,
2509                               &(pd->emptylines), pd->out_width,
2510                               pd->left, channel->props->bits, channel->props->flags);
2511      }
2512    }
2513  if (written)
2514    stp_zfwrite("\033\050\145\002\000\000\001", 7, 1, v);
2515  else
2516    pd->emptylines += 1;
2517}
2518
2519
2520/* write one multiraster block */
2521static void canon_write_block(stp_vars_t* v,canon_privdata_t* pd,unsigned char* start, unsigned char* end){
2522    unsigned int length = end - start;
2523    if(!length)
2524        return;
2525    stp_zfwrite("\033(F", 3, 1, v);
2526    stp_put16_le(length, v);
2527    stp_zfwrite((const char *)start, length, 1, v);
2528}
2529
2530
2531static void canon_write_multiraster(stp_vars_t *v,canon_privdata_t* pd,int y){
2532    int i;
2533    int raster_lines_per_block = pd->caps->raster_lines_per_block;
2534    unsigned int max_length = 2*pd->buf_length_max * raster_lines_per_block;
2535    /* a new raster block begins */
2536    if(!(y % raster_lines_per_block)){
2537        if(y != 0){
2538            /* write finished blocks */
2539            for(i=0;i<pd->num_channels;i++)
2540                canon_write_block(v,pd,pd->comp_buf + i * max_length,pd->channels[i].comp_buf_offset);
2541        }
2542        /* reset start offsets */
2543        for(i=0;i<pd->num_channels;i++)
2544            pd->channels[i].comp_buf_offset = pd->comp_buf + i * max_length;
2545    }
2546    /* compress lines and add them to the buffer */
2547    for(i=0;i<pd->num_channels;i++){
2548       pd->channels[i].comp_buf_offset += canon_compress(v,pd, pd->channels[i].buf,pd->length,pd->left,pd->channels[i].comp_buf_offset,pd->channels[i].props->bits, pd->channels[i].props->flags);
2549       *(pd->channels[i].comp_buf_offset) = 0x80; /* terminate the line */
2550        ++pd->channels[i].comp_buf_offset;
2551    }
2552    if(y == pd->out_height - 1){
2553        /* we just compressed our last line */
2554        if(pd->out_height % raster_lines_per_block){
2555            /* but our raster block is not finished yet */
2556            int missing = raster_lines_per_block - (pd->out_height % raster_lines_per_block); /* calculate missing lines */
2557            for(i=0;i<pd->num_channels;i++){
2558                /* add missing empty lines and write blocks */
2559                int x;
2560                for(x=0;x < missing ; x++){
2561                  *(pd->channels[i].comp_buf_offset) = 0x80; /* terminate the line */
2562                  ++pd->channels[i].comp_buf_offset;
2563                }
2564                canon_write_block(v,pd,pd->comp_buf + i * max_length,pd->channels[i].comp_buf_offset);
2565            }
2566        }
2567    }
2568}
2569
2570
2571static void
2572canon_advance_paper(stp_vars_t *v, int advance)
2573{
2574  if ( advance > 0 )
2575    {
2576      int a0, a1, a2, a3;
2577      stp_deprintf(STP_DBG_CANON,"                      --advance paper %d\n", advance);
2578      a0 = advance         & 0xff;
2579      a1 = (advance >> 8)  & 0xff;
2580      a2 = (advance >> 16) & 0xff;
2581      a3 = (advance >> 24) & 0xff;
2582      stp_zprintf(v, "\033(e%c%c%c%c%c%c", 4, 0, a3, a2, a1, a0);
2583    }
2584}
2585
2586static void
2587canon_flush_pass(stp_vars_t *v, int passno, int vertical_subpass)
2588{
2589  stp_lineoff_t        *lineoffs   = stp_get_lineoffsets_by_pass(v, passno);
2590  stp_lineactive_t     *lineactive = stp_get_lineactive_by_pass(v, passno);
2591  const stp_linebufs_t *bufs       = stp_get_linebases_by_pass(v, passno);
2592  stp_pass_t           *pass       = stp_get_pass_by_pass(v, passno);
2593  stp_linecount_t      *linecount  = stp_get_linecount_by_pass(v, passno);
2594  canon_privdata_t      *pd         = (canon_privdata_t *) stp_get_component_data(v, "Driver");
2595  int                    papershift = (pass->logicalpassstart - pd->last_pass_offset);
2596
2597  int color, line, written = 0, linelength = 0, lines = 0;
2598  int idx[4]={3, 0, 1, 2}; /* color numbering is different between canon_write and weaving */
2599
2600  stp_deprintf(STP_DBG_CANON,"canon_flush_pass: ----pass=%d,---- \n", passno);
2601  (pd->emptylines) = 0;
2602
2603  for ( color = 0; color < pd->ncolors; color++ ) /* find max. linecount */
2604    {
2605      if ( linecount[0].v[color] > lines )
2606        lines = linecount[0].v[color];
2607    }
2608
2609  for ( line = 0; line < lines; line++ )  /* go through each nozzle f that pass */
2610    {
2611      stp_deprintf(STP_DBG_CANON,"                      --line=%d\n", line);
2612
2613      if ( written > 0 )
2614        canon_cmd(v,ESC28,0x65, 2, 0, 1); /* go to next nozzle*/
2615                                           /* if there was printed some data */
2616
2617      written = 0;
2618      for ( color = 0; color < pd->ncolors; color++ )
2619        {
2620          if ( line < linecount[0].v[color] )  /* try only existing lines */
2621            {
2622              if ( lineactive[0].v[color] > 0 )
2623                {
2624                  linelength = lineoffs[0].v[color] / linecount[0].v[color];
2625/*                stp_deprintf(STP_DBG_CANON,"canon_flush_pass: linelength=%d, bufs[0].v[color]=%p,"
2626                  "bufs[0].v[color]+line * linelength=%p, empty=%d \n", linelength, bufs[0].v[color],
2627                   bufs[0].v[color] + line * linelength, (pd->emptylines));
2628*/
2629                  if ( pass->logicalpassstart - pd->last_pass_offset > 0 )
2630                    {
2631                      canon_advance_paper(v, papershift);
2632                      pd->last_pass_offset = pass->logicalpassstart;
2633                      if (pd->bidirectional)
2634                        {
2635                         pd->direction = (pd->direction +1) & 1;
2636                         canon_set_X72(v, pd->direction);
2637                         stp_deprintf(STP_DBG_CANON,"                      --set direction %d\n", pd->direction);
2638                        }
2639                    }
2640
2641                  written += canon_write(v, pd, pd->caps,
2642                               (unsigned char *)(bufs[0].v[color] + line * linelength),
2643                               linelength, idx[color],
2644                               &(pd->emptylines), pd->out_width,
2645                               pd->left, pd->weave_bits[color],0);
2646                  if (written) stp_deprintf(STP_DBG_CANON,"                        --written color %d,\n", color);
2647
2648                }
2649            }
2650        }
2651
2652      if ( written == 0 ) /* count unused nozzles */
2653        (pd->emptylines) += 1;
2654    }
2655
2656  for ( color = 0; color < pd->ncolors; color++ )
2657    {
2658      lineoffs[0].v[color] = 0;
2659      linecount[0].v[color] = 0;
2660    }
2661  stp_deprintf(STP_DBG_CANON,"                  --ended-- with empty=%d \n", (pd->emptylines));
2662}
2663
2664static stp_family_t print_canon_module_data =
2665  {
2666    &print_canon_printfuncs,
2667    NULL
2668  };
2669
2670
2671static int
2672print_canon_module_init(void)
2673{
2674  return stp_family_register(print_canon_module_data.printer_list);
2675}
2676
2677
2678static int
2679print_canon_module_exit(void)
2680{
2681  return stp_family_unregister(print_canon_module_data.printer_list);
2682}
2683
2684
2685/* Module header */
2686#define stp_module_version print_canon_LTX_stp_module_version
2687#define stp_module_data print_canon_LTX_stp_module_data
2688
2689stp_module_version_t stp_module_version = {0, 0};
2690
2691stp_module_t stp_module_data =
2692  {
2693    "canon",
2694    VERSION,
2695    "Canon family driver",
2696    STP_MODULE_CLASS_FAMILY,
2697    NULL,
2698    print_canon_module_init,
2699    print_canon_module_exit,
2700    (void *) &print_canon_module_data
2701  };
2702
2703