1/*
2 * "$Id: print-olympus.c,v 1.97 2010/12/05 21:38:15 rlk Exp $"
3 *
4 *   Print plug-in DyeSub driver (formerly Olympus driver) for the GIMP.
5 *
6 *   Copyright 2003 - 2006
7 *   Michael Mraka (Michael.Mraka@linux.cz)
8 *
9 *   The plug-in is based on the code of the RAW plugin for the GIMP of
10 *   Michael Sweet (mike@easysw.com) and Robert Krawitz (rlk@alum.mit.edu)
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#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35#include <gutenprint/gutenprint.h>
36#include "gutenprint-internal.h"
37#include <gutenprint/gutenprint-intl-internal.h>
38#include <string.h>
39#include <stdio.h>
40#include <limits.h>
41
42#ifdef __GNUC__
43#define inline __inline__
44#endif
45
46#define DYESUB_FEATURE_NONE		0x00000000
47#define DYESUB_FEATURE_FULL_WIDTH	0x00000001
48#define DYESUB_FEATURE_FULL_HEIGHT	0x00000002
49#define DYESUB_FEATURE_BLOCK_ALIGN	0x00000004
50#define DYESUB_FEATURE_BORDERLESS	0x00000008
51#define DYESUB_FEATURE_WHITE_BORDER	0x00000010
52#define DYESUB_FEATURE_PLANE_INTERLACE	0x00000020
53#define DYESUB_FEATURE_PLANE_LEFTTORIGHT	0x00000040
54
55#define DYESUB_PORTRAIT	0
56#define DYESUB_LANDSCAPE	1
57
58#ifndef MIN
59#  define MIN(a,b)	(((a) < (b)) ? (a) : (b))
60#endif /* !MIN */
61#ifndef MAX
62#  define MAX(a, b)	(((a) > (b)) ? (a) : (b))
63#endif /* !MAX */
64#define PX(pt,dpi)	((pt) * (dpi) / 72)
65#define PT(px,dpi)	((px) * 72 / (dpi))
66#define LIST(list_t, list_name, items_t, items_name) \
67	static const list_t list_name = \
68	{ \
69	  items_name, sizeof(items_name) / sizeof(items_t) \
70	}
71
72#define MAX_INK_CHANNELS	3
73#define MAX_BYTES_PER_CHANNEL	2
74#define SIZE_THRESHOLD		6
75
76typedef struct
77{
78  const char *output_type;
79  int output_channels;
80  const char *name;
81  const char *channel_order;
82} ink_t;
83
84typedef struct {
85  const ink_t *item;
86  size_t n_items;
87} ink_list_t;
88
89typedef struct {
90  const char* name;
91  int w_dpi;
92  int h_dpi;
93} dyesub_resolution_t;
94
95typedef struct {
96  const dyesub_resolution_t *item;
97  size_t n_items;
98} dyesub_resolution_list_t;
99
100typedef struct {
101  const char* name;
102  const char* text;
103  int width_pt;
104  int height_pt;
105  int border_pt_left;
106  int border_pt_right;
107  int border_pt_top;
108  int border_pt_bottom;
109  int print_mode;
110} dyesub_pagesize_t;
111
112typedef struct {
113  const dyesub_pagesize_t *item;
114  size_t n_items;
115} dyesub_pagesize_list_t;
116
117typedef struct {
118  const char* res_name;
119  const char* pagesize_name;
120  int width_px;
121  int height_px;
122} dyesub_printsize_t;
123
124typedef struct {
125  const dyesub_printsize_t *item;
126  size_t n_items;
127} dyesub_printsize_list_t;
128
129
130typedef struct {
131  const char *name;
132  const char *text;
133  const stp_raw_t seq;
134} laminate_t;
135
136typedef struct {
137  const laminate_t *item;
138  size_t n_items;
139} laminate_list_t;
140
141#define NPUTC_BUFSIZE (4096)
142
143typedef struct
144{
145  int w_dpi, h_dpi;
146  int w_size, h_size;
147  char plane;
148  int block_min_w, block_min_h;
149  int block_max_w, block_max_h;
150  const char* pagesize;
151  const laminate_t* laminate;
152  int print_mode;
153  char nputc_buf[NPUTC_BUFSIZE];
154} dyesub_privdata_t;
155
156static dyesub_privdata_t privdata;
157
158typedef struct {
159  int out_channels;
160  int ink_channels;
161  const char *ink_order;
162  int bytes_per_out_channel;
163  int bytes_per_ink_channel;
164  int plane_interlacing;
165  char empty_byte;
166  unsigned short **image_data;
167  int outh_px, outw_px, outt_px, outb_px, outl_px, outr_px;
168  int imgh_px, imgw_px;
169  int prnh_px, prnw_px, prnt_px, prnb_px, prnl_px, prnr_px;
170  int print_mode;	/* portrait or landscape */
171  int image_rows;
172  int plane_lefttoright;
173} dyesub_print_vars_t;
174
175typedef struct /* printer specific parameters */
176{
177  int model;		/* printer model number from printers.xml*/
178  const ink_list_t *inks;
179  const dyesub_resolution_list_t *resolution;
180  const dyesub_pagesize_list_t *pages;
181  const dyesub_printsize_list_t *printsize;
182  int block_size;
183  int features;
184  void (*printer_init_func)(stp_vars_t *);
185  void (*printer_end_func)(stp_vars_t *);
186  void (*plane_init_func)(stp_vars_t *);
187  void (*plane_end_func)(stp_vars_t *);
188  void (*block_init_func)(stp_vars_t *);
189  void (*block_end_func)(stp_vars_t *);
190  const char *adj_cyan;		/* default color adjustment */
191  const char *adj_magenta;
192  const char *adj_yellow;
193  const laminate_list_t *laminate;
194} dyesub_cap_t;
195
196
197static const dyesub_cap_t* dyesub_get_model_capabilities(int model);
198static const laminate_t* dyesub_get_laminate_pattern(stp_vars_t *v);
199static void  dyesub_nputc(stp_vars_t *v, char byte, int count);
200
201
202static const ink_t cmy_inks[] =
203{
204  { "CMY", 3, "CMY", "\1\2\3" },
205};
206
207LIST(ink_list_t, cmy_ink_list, ink_t, cmy_inks);
208
209static const ink_t ymc_inks[] =
210{
211  { "CMY", 3, "CMY", "\3\2\1" },
212};
213
214LIST(ink_list_t, ymc_ink_list, ink_t, ymc_inks);
215
216static const ink_t rgb_inks[] =
217{
218  { "RGB", 3, "RGB", "\1\2\3" },
219};
220
221LIST(ink_list_t, rgb_ink_list, ink_t, rgb_inks);
222
223static const ink_t bgr_inks[] =
224{
225  { "RGB", 3, "RGB", "\3\2\1" },
226};
227
228LIST(ink_list_t, bgr_ink_list, ink_t, bgr_inks);
229
230
231/* Olympus P-10 */
232static const dyesub_resolution_t res_310dpi[] =
233{
234  { "310x310", 310, 310},
235};
236
237LIST(dyesub_resolution_list_t, res_310dpi_list, dyesub_resolution_t, res_310dpi);
238
239static const dyesub_pagesize_t p10_page[] =
240{
241  { "w288h432", "4 x 6", 298, 430, 0, 0, 0, 0, DYESUB_PORTRAIT}, /* 4x6" */
242  { "B7", "3.5 x 5", 266, 370, 0, 0, 0, 0, DYESUB_PORTRAIT},	 /* 3.5x5" */
243  { "Custom", NULL, 298, 430, 28, 28, 48, 48, DYESUB_PORTRAIT},
244};
245
246LIST(dyesub_pagesize_list_t, p10_page_list, dyesub_pagesize_t, p10_page);
247
248static const dyesub_printsize_t p10_printsize[] =
249{
250  { "310x310", "w288h432", 1280, 1848},
251  { "310x310", "B7",  1144,  1591},
252  { "310x310", "Custom", 1280, 1848},
253};
254
255LIST(dyesub_printsize_list_t, p10_printsize_list, dyesub_printsize_t, p10_printsize);
256
257static void p10_printer_init_func(stp_vars_t *v)
258{
259  stp_zfwrite("\033R\033M\033S\2\033N\1\033D\1\033Y", 1, 15, v);
260  stp_write_raw(&(privdata.laminate->seq), v); /* laminate */
261  stp_zfwrite("\033Z\0", 1, 3, v);
262}
263
264static void p10_printer_end_func(stp_vars_t *v)
265{
266  stp_zfwrite("\033P", 1, 2, v);
267}
268
269static void p10_block_init_func(stp_vars_t *v)
270{
271  stp_zprintf(v, "\033T%c", privdata.plane);
272  stp_put16_le(privdata.block_min_w, v);
273  stp_put16_le(privdata.block_min_h, v);
274  stp_put16_le(privdata.block_max_w + 1, v);
275  stp_put16_le(privdata.block_max_h + 1, v);
276}
277
278static const laminate_t p10_laminate[] =
279{
280  {"Coated",  N_("Coated"),  {1, "\x00"}},
281  {"None",    N_("None"),    {1, "\x02"}},
282};
283
284LIST(laminate_list_t, p10_laminate_list, laminate_t, p10_laminate);
285
286
287/* Olympus P-200 series */
288static const dyesub_resolution_t res_320dpi[] =
289{
290  { "320x320", 320, 320},
291};
292
293LIST(dyesub_resolution_list_t, res_320dpi_list, dyesub_resolution_t, res_320dpi);
294
295static const dyesub_pagesize_t p200_page[] =
296{
297  { "ISOB7", "80x125mm", -1, -1, 16, 17, 33, 33, DYESUB_PORTRAIT},
298  { "Custom", NULL, -1, -1, 16, 17, 33, 33, DYESUB_PORTRAIT},
299};
300
301LIST(dyesub_pagesize_list_t, p200_page_list, dyesub_pagesize_t, p200_page);
302
303static const dyesub_printsize_t p200_printsize[] =
304{
305  { "320x320", "ISOB7", 960, 1280},
306  { "320x320", "Custom", 960, 1280},
307};
308
309LIST(dyesub_printsize_list_t, p200_printsize_list, dyesub_printsize_t, p200_printsize);
310
311static void p200_printer_init_func(stp_vars_t *v)
312{
313  stp_zfwrite("S000001\0S010001\1", 1, 16, v);
314}
315
316static void p200_plane_init_func(stp_vars_t *v)
317{
318  stp_zprintf(v, "P0%d9999", 3 - privdata.plane+1 );
319  stp_put32_be(privdata.w_size * privdata.h_size, v);
320}
321
322static void p200_printer_end_func(stp_vars_t *v)
323{
324  stp_zprintf(v, "P000001\1");
325}
326
327static const char p200_adj_any[] =
328  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
329  "<gutenprint>\n"
330  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
331  "<sequence count=\"33\" lower-bound=\"0\" upper-bound=\"1\">\n"
332  "0.000000 0.039216 0.078431 0.117647 0.152941 0.192157 0.231373 0.266667\n"
333  "0.301961 0.341176 0.376471 0.411765 0.447059 0.482353 0.513725 0.549020\n"
334  "0.580392 0.615686 0.647059 0.678431 0.709804 0.741176 0.768627 0.796078\n"
335  "0.827451 0.854902 0.878431 0.905882 0.929412 0.949020 0.972549 0.988235\n"
336  "1.000000\n"
337  "</sequence>\n"
338  "</curve>\n"
339  "</gutenprint>\n";
340
341
342/* Olympus P-300 series */
343static const dyesub_resolution_t p300_res[] =
344{
345  { "306x306", 306, 306},
346  { "153x153", 153, 153},
347};
348
349LIST(dyesub_resolution_list_t, p300_res_list, dyesub_resolution_t, p300_res);
350
351static const dyesub_pagesize_t p300_page[] =
352{
353  { "A6", NULL, -1, -1, 28, 28, 48, 48, DYESUB_PORTRAIT},
354  { "Custom", NULL, -1, -1, 28, 28, 48, 48, DYESUB_PORTRAIT},
355};
356
357LIST(dyesub_pagesize_list_t, p300_page_list, dyesub_pagesize_t, p300_page);
358
359static const dyesub_printsize_t p300_printsize[] =
360{
361  { "306x306", "A6", 1024, 1376},
362  { "153x153", "A6",  512,  688},
363  { "306x306", "Custom", 1024, 1376},
364  { "153x153", "Custom", 512, 688},
365};
366
367LIST(dyesub_printsize_list_t, p300_printsize_list, dyesub_printsize_t, p300_printsize);
368
369static void p300_printer_init_func(stp_vars_t *v)
370{
371  stp_zfwrite("\033\033\033C\033N\1\033F\0\1\033MS\xff\xff\xff"
372	      "\033Z", 1, 19, v);
373  stp_put16_be(privdata.w_dpi, v);
374  stp_put16_be(privdata.h_dpi, v);
375}
376
377static void p300_plane_end_func(stp_vars_t *v)
378{
379  const char *c = "CMY";
380  stp_zprintf(v, "\033\033\033P%cS", c[privdata.plane-1]);
381  stp_deprintf(STP_DBG_DYESUB, "dyesub: p300_plane_end_func: %c\n",
382	c[privdata.plane-1]);
383}
384
385static void p300_block_init_func(stp_vars_t *v)
386{
387  const char *c = "CMY";
388  stp_zprintf(v, "\033\033\033W%c", c[privdata.plane-1]);
389  stp_put16_be(privdata.block_min_h, v);
390  stp_put16_be(privdata.block_min_w, v);
391  stp_put16_be(privdata.block_max_h, v);
392  stp_put16_be(privdata.block_max_w, v);
393
394  stp_deprintf(STP_DBG_DYESUB, "dyesub: p300_block_init_func: %d-%dx%d-%d\n",
395	privdata.block_min_w, privdata.block_max_w,
396	privdata.block_min_h, privdata.block_max_h);
397}
398
399static const char p300_adj_cyan[] =
400  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
401  "<gutenprint>\n"
402  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
403  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
404  "0.078431 0.211765 0.250980 0.282353 0.309804 0.333333 0.352941 0.368627\n"
405  "0.388235 0.403922 0.427451 0.443137 0.458824 0.478431 0.498039 0.513725\n"
406  "0.529412 0.545098 0.556863 0.576471 0.592157 0.611765 0.627451 0.647059\n"
407  "0.666667 0.682353 0.701961 0.713725 0.725490 0.729412 0.733333 0.737255\n"
408  "</sequence>\n"
409  "</curve>\n"
410  "</gutenprint>\n";
411
412static const char p300_adj_magenta[] =
413  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
414  "<gutenprint>\n"
415  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
416  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
417  "0.047059 0.211765 0.250980 0.278431 0.305882 0.333333 0.349020 0.364706\n"
418  "0.380392 0.396078 0.415686 0.435294 0.450980 0.466667 0.482353 0.498039\n"
419  "0.513725 0.525490 0.541176 0.556863 0.572549 0.592157 0.611765 0.631373\n"
420  "0.650980 0.670588 0.694118 0.705882 0.721569 0.741176 0.745098 0.756863\n"
421  "</sequence>\n"
422  "</curve>\n"
423  "</gutenprint>\n";
424
425static const char p300_adj_yellow[] =
426  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
427  "<gutenprint>\n"
428  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
429  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
430  "0.047059 0.117647 0.203922 0.250980 0.274510 0.301961 0.321569 0.337255\n"
431  "0.352941 0.364706 0.380392 0.396078 0.407843 0.423529 0.439216 0.450980\n"
432  "0.466667 0.482353 0.498039 0.513725 0.533333 0.552941 0.572549 0.596078\n"
433  "0.615686 0.635294 0.650980 0.666667 0.682353 0.690196 0.701961 0.713725\n"
434  "</sequence>\n"
435  "</curve>\n"
436  "</gutenprint>\n";
437
438
439/* Olympus P-400 series */
440static const dyesub_resolution_t res_314dpi[] =
441{
442  { "314x314", 314, 314},
443};
444
445LIST(dyesub_resolution_list_t, res_314dpi_list, dyesub_resolution_t, res_314dpi);
446
447static const dyesub_pagesize_t p400_page[] =
448{
449  { "A4", NULL, -1, -1, 22, 22, 54, 54, DYESUB_PORTRAIT},
450  { "c8x10", "A5 wide", -1, -1, 58, 59, 84, 85, DYESUB_PORTRAIT},
451  { "C6", "2 Postcards (A4)", -1, -1, 9, 9, 9, 9, DYESUB_PORTRAIT},
452  { "Custom", NULL, -1, -1, 22, 22, 54, 54, DYESUB_PORTRAIT},
453};
454
455LIST(dyesub_pagesize_list_t, p400_page_list, dyesub_pagesize_t, p400_page);
456
457static const dyesub_printsize_t p400_printsize[] =
458{
459  { "314x314", "A4", 2400, 3200},
460  { "314x314", "c8x10", 2000, 2400},
461  { "314x314", "C6", 1328, 1920},
462  { "314x314", "Custom", 2400, 3200},
463};
464
465LIST(dyesub_printsize_list_t, p400_printsize_list, dyesub_printsize_t, p400_printsize);
466
467static void p400_printer_init_func(stp_vars_t *v)
468{
469  int wide = (strcmp(privdata.pagesize, "c8x10") == 0
470		  || strcmp(privdata.pagesize, "C6") == 0);
471
472  stp_zprintf(v, "\033ZQ"); dyesub_nputc(v, '\0', 61);
473  stp_zprintf(v, "\033FP"); dyesub_nputc(v, '\0', 61);
474  stp_zprintf(v, "\033ZF");
475  stp_putc((wide ? '\x40' : '\x00'), v); dyesub_nputc(v, '\0', 60);
476  stp_zprintf(v, "\033ZS");
477  if (wide)
478    {
479      stp_put16_be(privdata.h_size, v);
480      stp_put16_be(privdata.w_size, v);
481    }
482  else
483    {
484      stp_put16_be(privdata.w_size, v);
485      stp_put16_be(privdata.h_size, v);
486    }
487  dyesub_nputc(v, '\0', 57);
488  stp_zprintf(v, "\033ZP"); dyesub_nputc(v, '\0', 61);
489}
490
491static void p400_plane_init_func(stp_vars_t *v)
492{
493  stp_zprintf(v, "\033ZC"); dyesub_nputc(v, '\0', 61);
494}
495
496static void p400_plane_end_func(stp_vars_t *v)
497{
498  stp_zprintf(v, "\033P"); dyesub_nputc(v, '\0', 62);
499}
500
501static void p400_block_init_func(stp_vars_t *v)
502{
503  int wide = (strcmp(privdata.pagesize, "c8x10") == 0
504		  || strcmp(privdata.pagesize, "C6") == 0);
505
506  stp_zprintf(v, "\033Z%c", '3' - privdata.plane + 1);
507  if (wide)
508    {
509      stp_put16_be(privdata.h_size - privdata.block_max_h - 1, v);
510      stp_put16_be(privdata.w_size - privdata.block_max_w - 1, v);
511      stp_put16_be(privdata.block_max_h - privdata.block_min_h + 1, v);
512      stp_put16_be(privdata.block_max_w - privdata.block_min_w + 1, v);
513    }
514  else
515    {
516      stp_put16_be(privdata.block_min_w, v);
517      stp_put16_be(privdata.block_min_h, v);
518      stp_put16_be(privdata.block_max_w - privdata.block_min_w + 1, v);
519      stp_put16_be(privdata.block_max_h - privdata.block_min_h + 1, v);
520    }
521  dyesub_nputc(v, '\0', 53);
522}
523
524static const char p400_adj_cyan[] =
525  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
526  "<gutenprint>\n"
527  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
528  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
529  "0.003922 0.031373 0.058824 0.090196 0.125490 0.156863 0.184314 0.219608\n"
530  "0.250980 0.278431 0.309804 0.341176 0.376471 0.403922 0.439216 0.470588\n"
531  "0.498039 0.517647 0.533333 0.545098 0.564706 0.576471 0.596078 0.615686\n"
532  "0.627451 0.647059 0.658824 0.678431 0.690196 0.705882 0.721569 0.737255\n"
533  "</sequence>\n"
534  "</curve>\n"
535  "</gutenprint>\n";
536
537static const char p400_adj_magenta[] =
538  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
539  "<gutenprint>\n"
540  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
541  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
542  "0.003922 0.031373 0.062745 0.098039 0.125490 0.156863 0.188235 0.215686\n"
543  "0.250980 0.282353 0.309804 0.345098 0.376471 0.407843 0.439216 0.470588\n"
544  "0.501961 0.521569 0.549020 0.572549 0.592157 0.619608 0.643137 0.662745\n"
545  "0.682353 0.713725 0.737255 0.756863 0.784314 0.807843 0.827451 0.850980\n"
546  "</sequence>\n"
547  "</curve>\n"
548  "</gutenprint>\n";
549
550static const char p400_adj_yellow[] =
551  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
552  "<gutenprint>\n"
553  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
554  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
555  "0.003922 0.027451 0.054902 0.090196 0.121569 0.156863 0.184314 0.215686\n"
556  "0.250980 0.282353 0.309804 0.345098 0.372549 0.400000 0.435294 0.466667\n"
557  "0.498039 0.525490 0.552941 0.580392 0.607843 0.631373 0.658824 0.678431\n"
558  "0.698039 0.725490 0.760784 0.784314 0.811765 0.839216 0.866667 0.890196\n"
559  "</sequence>\n"
560  "</curve>\n"
561  "</gutenprint>\n";
562
563
564/* Olympus P-440 series */
565static const dyesub_pagesize_t p440_page[] =
566{
567  { "A4", NULL, -1, -1, 10, 9, 54, 54, DYESUB_PORTRAIT},
568  { "c8x10", "A5 wide", -1, -1, 58, 59, 72, 72, DYESUB_PORTRAIT},
569  { "C6", "2 Postcards (A4)", -1, -1, 9, 9, 9, 9, DYESUB_PORTRAIT},
570  { "w255h581", "A6 wide", -1, -1, 25, 25, 25, 24, DYESUB_PORTRAIT},
571  { "Custom", NULL, -1, -1, 22, 22, 54, 54, DYESUB_PORTRAIT},
572};
573
574LIST(dyesub_pagesize_list_t, p440_page_list, dyesub_pagesize_t, p440_page);
575
576static const dyesub_printsize_t p440_printsize[] =
577{
578  { "314x314", "A4", 2508, 3200},
579  { "314x314", "c8x10", 2000, 2508},
580  { "314x314", "C6", 1328, 1920},
581  { "314x314", "w255h581", 892, 2320},
582  { "314x314", "Custom", 2508, 3200},
583};
584
585LIST(dyesub_printsize_list_t, p440_printsize_list, dyesub_printsize_t, p440_printsize);
586
587static void p440_printer_init_func(stp_vars_t *v)
588{
589  int wide = ! (strcmp(privdata.pagesize, "A4") == 0
590		  || strcmp(privdata.pagesize, "Custom") == 0);
591
592  stp_zprintf(v, "\033FP"); dyesub_nputc(v, '\0', 61);
593  stp_zprintf(v, "\033Y");
594  stp_write_raw(&(privdata.laminate->seq), v); /* laminate */
595  dyesub_nputc(v, '\0', 61);
596  stp_zprintf(v, "\033FC"); dyesub_nputc(v, '\0', 61);
597  stp_zprintf(v, "\033ZF");
598  stp_putc((wide ? '\x40' : '\x00'), v); dyesub_nputc(v, '\0', 60);
599  stp_zprintf(v, "\033N\1"); dyesub_nputc(v, '\0', 61);
600  stp_zprintf(v, "\033ZS");
601  if (wide)
602    {
603      stp_put16_be(privdata.h_size, v);
604      stp_put16_be(privdata.w_size, v);
605    }
606  else
607    {
608      stp_put16_be(privdata.w_size, v);
609      stp_put16_be(privdata.h_size, v);
610    }
611  dyesub_nputc(v, '\0', 57);
612  if (strcmp(privdata.pagesize, "C6") == 0)
613    {
614      stp_zprintf(v, "\033ZC"); dyesub_nputc(v, '\0', 61);
615    }
616}
617
618static void p440_printer_end_func(stp_vars_t *v)
619{
620  stp_zprintf(v, "\033P"); dyesub_nputc(v, '\0', 62);
621}
622
623static void p440_block_init_func(stp_vars_t *v)
624{
625  int wide = ! (strcmp(privdata.pagesize, "A4") == 0
626		  || strcmp(privdata.pagesize, "Custom") == 0);
627
628  stp_zprintf(v, "\033ZT");
629  if (wide)
630    {
631      stp_put16_be(privdata.h_size - privdata.block_max_h - 1, v);
632      stp_put16_be(privdata.w_size - privdata.block_max_w - 1, v);
633      stp_put16_be(privdata.block_max_h - privdata.block_min_h + 1, v);
634      stp_put16_be(privdata.block_max_w - privdata.block_min_w + 1, v);
635    }
636  else
637    {
638      stp_put16_be(privdata.block_min_w, v);
639      stp_put16_be(privdata.block_min_h, v);
640      stp_put16_be(privdata.block_max_w - privdata.block_min_w + 1, v);
641      stp_put16_be(privdata.block_max_h - privdata.block_min_h + 1, v);
642    }
643  dyesub_nputc(v, '\0', 53);
644}
645
646static void p440_block_end_func(stp_vars_t *v)
647{
648  int pad = (64 - (((privdata.block_max_w - privdata.block_min_w + 1)
649	  * (privdata.block_max_h - privdata.block_min_h + 1) * 3) % 64)) % 64;
650  stp_deprintf(STP_DBG_DYESUB,
651		  "dyesub: max_x %d min_x %d max_y %d min_y %d\n",
652  		  privdata.block_max_w, privdata.block_min_w,
653	  	  privdata.block_max_h, privdata.block_min_h);
654  stp_deprintf(STP_DBG_DYESUB, "dyesub: olympus-p440 padding=%d\n", pad);
655  dyesub_nputc(v, '\0', pad);
656}
657
658
659/* Olympus P-S100 */
660static const dyesub_pagesize_t ps100_page[] =
661{
662  { "w288h432", "4 x 6", 296, 426, 0, 0, 0, 0, DYESUB_PORTRAIT},/* 4x6" */
663  { "B7", "3.5 x 5", 264, 366, 0, 0, 0, 0, DYESUB_PORTRAIT},	/* 3.5x5" */
664  { "Custom", NULL, 296, 426, 0, 0, 0, 0, DYESUB_PORTRAIT},
665};
666
667LIST(dyesub_pagesize_list_t, ps100_page_list, dyesub_pagesize_t, ps100_page);
668
669static const dyesub_printsize_t ps100_printsize[] =
670{
671  { "306x306", "w288h432", 1254, 1808},
672  { "306x306", "B7", 1120, 1554},
673  { "306x306", "Custom", 1254, 1808},
674};
675
676LIST(dyesub_printsize_list_t, ps100_printsize_list, dyesub_printsize_t, ps100_printsize);
677
678static void ps100_printer_init_func(stp_vars_t *v)
679{
680  stp_zprintf(v, "\033U"); dyesub_nputc(v, '\0', 62);
681
682  /* stp_zprintf(v, "\033ZC"); dyesub_nputc(v, '\0', 61); */
683
684  stp_zprintf(v, "\033W"); dyesub_nputc(v, '\0', 62);
685
686  stp_zfwrite("\x30\x2e\x00\xa2\x00\xa0\x00\xa0", 1, 8, v);
687  stp_put16_be(privdata.h_size, v);	/* paper height (px) */
688  stp_put16_be(privdata.w_size, v);	/* paper width (px) */
689  dyesub_nputc(v, '\0', 3);
690  stp_putc('\1', v);	/* number of copies */
691  dyesub_nputc(v, '\0', 8);
692  stp_putc('\1', v);
693  dyesub_nputc(v, '\0', 15);
694  stp_putc('\6', v);
695  dyesub_nputc(v, '\0', 23);
696
697  stp_zfwrite("\033ZT\0", 1, 4, v);
698  stp_put16_be(0, v);			/* image width offset (px) */
699  stp_put16_be(0, v);			/* image height offset (px) */
700  stp_put16_be(privdata.w_size, v);	/* image width (px) */
701  stp_put16_be(privdata.h_size, v);	/* image height (px) */
702  dyesub_nputc(v, '\0', 52);
703}
704
705static void ps100_printer_end_func(stp_vars_t *v)
706{
707  int pad = (64 - (((privdata.block_max_w - privdata.block_min_w + 1)
708	  * (privdata.block_max_h - privdata.block_min_h + 1) * 3) % 64)) % 64;
709  stp_deprintf(STP_DBG_DYESUB,
710		  "dyesub: max_x %d min_x %d max_y %d min_y %d\n",
711  		  privdata.block_max_w, privdata.block_min_w,
712	  	  privdata.block_max_h, privdata.block_min_h);
713  stp_deprintf(STP_DBG_DYESUB, "dyesub: olympus-ps100 padding=%d\n", pad);
714  dyesub_nputc(v, '\0', pad);		/* padding to 64B blocks */
715
716  stp_zprintf(v, "\033PY"); dyesub_nputc(v, '\0', 61);
717  stp_zprintf(v, "\033u"); dyesub_nputc(v, '\0', 62);
718}
719
720
721/* Canon CP-10 */
722static const dyesub_resolution_t res_300dpi[] =
723{
724  { "300x300", 300, 300},
725};
726
727LIST(dyesub_resolution_list_t, res_300dpi_list, dyesub_resolution_t, res_300dpi);
728
729static const dyesub_pagesize_t cp10_page[] =
730{
731  { "w155h244", "Card 54x86mm", 159, 250, 6, 6, 29, 29, DYESUB_PORTRAIT},
732  { "Custom", NULL, -1, -1, 6, 6, 29, 29, DYESUB_PORTRAIT},
733};
734
735LIST(dyesub_pagesize_list_t, cp10_page_list, dyesub_pagesize_t, cp10_page);
736
737static const dyesub_printsize_t cp10_printsize[] =
738{
739  { "300x300", "w155h244", 662, 1040},
740  { "300x300", "Custom", 662, 1040},
741};
742
743LIST(dyesub_printsize_list_t, cp10_printsize_list, dyesub_printsize_t, cp10_printsize);
744
745
746/* Canon CP-100 series */
747static const dyesub_pagesize_t cpx00_page[] =
748{
749  { "Postcard", "Postcard 100x148mm", 296, 434, 13, 13, 16, 19, DYESUB_PORTRAIT},
750  { "w253h337", "CP_L 89x119mm", 264, 350, 13, 13, 15, 15, DYESUB_PORTRAIT},
751  { "w155h244", "Card 54x86mm", 162, 250, 13, 13, 15, 15, DYESUB_LANDSCAPE},
752  { "Custom", NULL, 296, 434, 13, 13, 16, 19, DYESUB_PORTRAIT},
753};
754
755LIST(dyesub_pagesize_list_t, cpx00_page_list, dyesub_pagesize_t, cpx00_page);
756
757static const dyesub_printsize_t cpx00_printsize[] =
758{
759  { "300x300", "Postcard", 1232, 1808},
760  { "300x300", "w253h337", 1100, 1456},
761  { "300x300", "w155h244", 672, 1040},
762  { "300x300", "Custom", 1232, 1808},
763};
764
765LIST(dyesub_printsize_list_t, cpx00_printsize_list, dyesub_printsize_t, cpx00_printsize);
766
767static void cpx00_printer_init_func(stp_vars_t *v)
768{
769  char pg = (strcmp(privdata.pagesize, "Postcard") == 0 ? '\1' :
770		(strcmp(privdata.pagesize, "w253h337") == 0 ? '\2' :
771		(strcmp(privdata.pagesize, "w155h244") == 0 ?
772			(strcmp(stp_get_driver(v),"canon-cp10") == 0 ?
773				'\0' : '\3' ) :
774		(strcmp(privdata.pagesize, "w283h566") == 0 ? '\4' :
775		 '\1' ))));
776
777  stp_put16_be(0x4000, v);
778  stp_putc('\0', v);
779  stp_putc(pg, v);
780  dyesub_nputc(v, '\0', 8);
781}
782
783static void cpx00_plane_init_func(stp_vars_t *v)
784{
785  stp_put16_be(0x4001, v);
786  stp_put16_le(3 - privdata.plane, v);
787  stp_put32_le(privdata.w_size * privdata.h_size, v);
788  dyesub_nputc(v, '\0', 4);
789}
790
791static const char cpx00_adj_cyan[] =
792  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
793  "<gutenprint>\n"
794  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
795  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
796  "0.000000 0.035294 0.070588 0.101961 0.117647 0.168627 0.180392 0.227451\n"
797  "0.258824 0.286275 0.317647 0.341176 0.376471 0.411765 0.427451 0.478431\n"
798  "0.505882 0.541176 0.576471 0.611765 0.654902 0.678431 0.705882 0.737255\n"
799  "0.764706 0.792157 0.811765 0.839216 0.862745 0.894118 0.909804 0.925490\n"
800  "</sequence>\n"
801  "</curve>\n"
802  "</gutenprint>\n";
803
804static const char cpx00_adj_magenta[] =
805  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
806  "<gutenprint>\n"
807  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
808  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
809  "0.011765 0.019608 0.035294 0.047059 0.054902 0.101961 0.133333 0.156863\n"
810  "0.192157 0.235294 0.274510 0.321569 0.360784 0.403922 0.443137 0.482353\n"
811  "0.521569 0.549020 0.584314 0.619608 0.658824 0.705882 0.749020 0.792157\n"
812  "0.831373 0.890196 0.933333 0.964706 0.988235 0.992157 0.992157 0.996078\n"
813  "</sequence>\n"
814  "</curve>\n"
815  "</gutenprint>\n";
816
817static const char cpx00_adj_yellow[] =
818  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
819  "<gutenprint>\n"
820  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
821  "<sequence count=\"32\" lower-bound=\"0\" upper-bound=\"1\">\n"
822  "0.003922 0.015686 0.015686 0.023529 0.027451 0.054902 0.094118 0.129412\n"
823  "0.180392 0.219608 0.250980 0.286275 0.317647 0.341176 0.388235 0.427451\n"
824  "0.470588 0.509804 0.552941 0.596078 0.627451 0.682353 0.768627 0.796078\n"
825  "0.890196 0.921569 0.949020 0.968627 0.984314 0.992157 0.992157 1.000000\n"
826  "</sequence>\n"
827  "</curve>\n"
828  "</gutenprint>\n";
829
830
831/* Canon CP-220 series */
832static const dyesub_pagesize_t cp220_page[] =
833{
834  { "Postcard", "Postcard 100x148mm", 296, 434, 13, 13, 16, 19, DYESUB_PORTRAIT},
835  { "w253h337", "CP_L 89x119mm", 264, 350, 13, 13, 15, 15, DYESUB_PORTRAIT},
836  { "w155h244", "Card 54x86mm", 162, 250, 13, 13, 15, 15, DYESUB_LANDSCAPE},
837  { "w283h566", "Wide 100x200mm", 296, 580, 13, 13, 20, 20, DYESUB_PORTRAIT},
838  { "Custom", NULL, 296, 434, 13, 13, 16, 19, DYESUB_PORTRAIT},
839};
840
841LIST(dyesub_pagesize_list_t, cp220_page_list, dyesub_pagesize_t, cp220_page);
842
843static const dyesub_printsize_t cp220_printsize[] =
844{
845  { "300x300", "Postcard", 1232, 1808},
846  { "300x300", "w253h337", 1100, 1456},
847  { "300x300", "w155h244", 672, 1040},
848  { "300x300", "w283h566", 1232, 2416},
849  { "300x300", "Custom", 1232, 1808},
850};
851
852LIST(dyesub_printsize_list_t, cp220_printsize_list, dyesub_printsize_t, cp220_printsize);
853
854
855/* Canon SELPHY CP-520 */
856static void cp520_printer_init_func(stp_vars_t *v)
857{
858  char pg = (strcmp(privdata.pagesize, "Postcard") == 0 ? '\1' :
859		(strcmp(privdata.pagesize, "w253h337") == 0 ? '\2' :
860		(strcmp(privdata.pagesize, "w155h244") == 0 ? '\3' :
861		(strcmp(privdata.pagesize, "w283h566") == 0 ? '\4' :
862		 '\1' ))));
863
864  stp_put16_be(0x4000, v);
865  stp_putc('\0', v);
866  stp_putc(pg, v);
867  dyesub_nputc(v, '\0', 8);
868  /* The CP520 does not want the printer_init and plane_init command to be sent
869     in the same USB-packet so we fill up first USB-Packet  with '\0'. */
870  dyesub_nputc(v, '\0', 1012);
871}
872
873static void cp520_plane_init_func(stp_vars_t *v)
874{
875  stp_put16_be(0x4001, v);
876  stp_putc(3 - privdata.plane, v);  /* The CP520 differs from the cp-printer
877                                       in that it reqires the plane in the 3rd
878                                       byte not in the 4th */
879  stp_putc('\0', v);
880  stp_put32_le(privdata.w_size * privdata.h_size, v);
881  dyesub_nputc(v, '\0', 4);
882}
883
884
885/* Canon SELPHY ES series */
886static void es1_printer_init_func(stp_vars_t *v)
887{
888  char pg = (strcmp(privdata.pagesize, "Postcard") == 0 ? 0x11 :
889	     (strcmp(privdata.pagesize, "w253h337") == 0 ? '\2' :
890	      (strcmp(privdata.pagesize, "w155h244") == 0 ? '\3' : 0x11 )));
891
892  /*
893   differs from cp-220 in that after the 0x4000, the next character
894   seems to be 0x01 instead of 0x00, and the P card size code is
895   '0x11' instead of '0x1'
896   codes for other paper types are unknown.
897  */
898
899  stp_put16_be(0x4000, v);
900  stp_putc(0x10, v);
901  stp_putc(pg, v);
902  dyesub_nputc(v, '\0', 8);
903}
904
905static void es1_plane_init_func(stp_vars_t *v)
906{
907  unsigned char plane = 0;
908
909  switch (privdata.plane) {
910  case 3: /* Y */
911    plane = 0x01;
912    break;
913  case 2: /* M */
914    plane = 0x03;
915    break;
916  case 1: /* C */
917    plane = 0x07;
918    break;
919  }
920
921  stp_put16_be(0x4001, v);
922  stp_putc(0x1, v);
923  stp_putc(plane, v);
924  stp_put32_le(privdata.w_size * privdata.h_size, v);
925  dyesub_nputc(v, '\0', 4);
926}
927
928/* Sony DPP-EX5, DPP-EX7 */
929static const dyesub_resolution_t res_403dpi[] =
930{
931  { "403x403", 403, 403},
932};
933
934LIST(dyesub_resolution_list_t, res_403dpi_list, dyesub_resolution_t, res_403dpi);
935
936/* only Postcard pagesize is supported */
937static const dyesub_pagesize_t dppex5_page[] =
938{
939  { "w288h432", "Postcard", PT(1664,403)+1, PT(2466,403)+1, 13, 14, 18, 17,
940  							DYESUB_PORTRAIT},
941  { "Custom", NULL, PT(1664,403)+1, PT(2466,403)+1, 13, 14, 18, 17,
942  							DYESUB_PORTRAIT},
943};
944
945LIST(dyesub_pagesize_list_t, dppex5_page_list, dyesub_pagesize_t, dppex5_page);
946
947static const dyesub_printsize_t dppex5_printsize[] =
948{
949  { "403x403", "w288h432", 1664, 2466},
950  { "403x403", "Custom", 1664, 2466},
951};
952
953LIST(dyesub_printsize_list_t, dppex5_printsize_list, dyesub_printsize_t, dppex5_printsize);
954
955static void dppex5_printer_init(stp_vars_t *v)
956{
957  stp_zfwrite("DPEX\0\0\0\x80", 1, 8, v);
958  stp_zfwrite("DPEX\0\0\0\x82", 1, 8, v);
959  stp_zfwrite("DPEX\0\0\0\x84", 1, 8, v);
960  stp_put32_be(privdata.w_size, v);
961  stp_put32_be(privdata.h_size, v);
962  stp_zfwrite("S\0o\0n\0y\0 \0D\0P\0P\0-\0E\0X\0\x35\0", 1, 24, v);
963  dyesub_nputc(v, '\0', 40);
964  stp_zfwrite("\1\4\0\4\xdc\0\x24\0\3\3\1\0\1\0\x82\0", 1, 16, v);
965  stp_zfwrite("\xf4\5\xf8\3\x64\0\1\0\x0e\0\x93\1\2\0\1\0", 1, 16, v);
966  stp_zfwrite("\x93\1\1\0\0\0", 1, 6, v);
967  stp_zfwrite("P\0o\0s\0t\0 \0c\0a\0r\0d\0", 1, 18, v);
968  dyesub_nputc(v, '\0', 46);
969  stp_zfwrite("\x93\1\x18", 1, 3, v);
970  dyesub_nputc(v, '\0', 19);
971  stp_zfwrite("\2\0\0\0\3\0\0\0\1\0\0\0\1", 1, 13, v);
972  dyesub_nputc(v, '\0', 19);
973  stp_zprintf(v, "5EPD");
974  dyesub_nputc(v, '\0', 4);
975  stp_zfwrite((privdata.laminate->seq).data, 1,
976			(privdata.laminate->seq).bytes, v); /*laminate pattern*/
977  stp_zfwrite("\0d\0d\0d", 1, 6, v);
978  dyesub_nputc(v, '\0', 21);
979}
980
981static void dppex5_block_init(stp_vars_t *v)
982{
983  stp_zfwrite("DPEX\0\0\0\x85", 1, 8, v);
984  stp_put32_be((privdata.block_max_w - privdata.block_min_w + 1)
985  		* (privdata.block_max_h - privdata.block_min_h + 1) * 3, v);
986}
987
988static void dppex5_printer_end(stp_vars_t *v)
989{
990  stp_zfwrite("DPEX\0\0\0\x83", 1, 8, v);
991  stp_zfwrite("DPEX\0\0\0\x81", 1, 8, v);
992}
993
994static const laminate_t dppex5_laminate[] =
995{
996  {"Glossy",  N_("Glossy"),  {1, "\x00"}},
997  {"Texture", N_("Texture"), {1, "\x01"}},
998};
999
1000LIST(laminate_list_t, dppex5_laminate_list, laminate_t, dppex5_laminate);
1001
1002
1003/* Sony UP-DP10 */
1004static const dyesub_pagesize_t updp10_page[] =
1005{
1006  { "w288h432", "UPC-10P23 (4x6)", -1, -1, 12, 12, 18, 18, DYESUB_LANDSCAPE},
1007  { "w288h387", "UPC-10P34 (4x5)", -1, 384, 12, 12, 16, 16, DYESUB_LANDSCAPE},
1008#if 0
1009  /* We can't have two paper sizes that are the same size --rlk 20080813 */
1010  { "w288h432", "UPC-10S01 (Sticker)", -1, -1, 12, 12, 18, 18, DYESUB_LANDSCAPE},
1011#endif
1012  { "Custom", NULL, -1, -1, 12, 12, 0, 0, DYESUB_LANDSCAPE},
1013};
1014
1015LIST(dyesub_pagesize_list_t, updp10_page_list, dyesub_pagesize_t, updp10_page);
1016
1017static const dyesub_printsize_t updp10_printsize[] =
1018{
1019  { "300x300", "w288h432", 1200, 1800},
1020  { "300x300", "w288h387", 1200, 1600},
1021  { "300x300", "Custom", 1200, 1800},
1022};
1023
1024LIST(dyesub_printsize_list_t, updp10_printsize_list, dyesub_printsize_t, updp10_printsize);
1025
1026static void updp10_printer_init_func(stp_vars_t *v)
1027{
1028  stp_zfwrite("\x98\xff\xff\xff\xff\xff\xff\xff"
1029	      "\x09\x00\x00\x00\x1b\xee\x00\x00"
1030	      "\x00\x02\x00\x00\x01\x12\x00\x00"
1031	      "\x00\x1b\xe1\x00\x00\x00\x0b\x00"
1032	      "\x00\x04", 1, 34, v);
1033  stp_zfwrite((privdata.laminate->seq).data, 1,
1034			(privdata.laminate->seq).bytes, v); /*laminate pattern*/
1035  stp_zfwrite("\x00\x00\x00\x00", 1, 4, v);
1036  stp_put16_be(privdata.w_size, v);
1037  stp_put16_be(privdata.h_size, v);
1038  stp_zfwrite("\x14\x00\x00\x00\x1b\x15\x00\x00"
1039	      "\x00\x0d\x00\x00\x00\x00\x00\x07"
1040	      "\x00\x00\x00\x00", 1, 20, v);
1041  stp_put16_be(privdata.w_size, v);
1042  stp_put16_be(privdata.h_size, v);
1043  stp_put32_le(privdata.w_size*privdata.h_size*3+11, v);
1044  stp_zfwrite("\x1b\xea\x00\x00\x00\x00", 1, 6, v);
1045  stp_put32_be(privdata.w_size*privdata.h_size*3, v);
1046  stp_zfwrite("\x00", 1, 1, v);
1047}
1048
1049static void updp10_printer_end_func(stp_vars_t *v)
1050{
1051	stp_zfwrite("\xff\xff\xff\xff\x07\x00\x00\x00"
1052		    "\x1b\x0a\x00\x00\x00\x00\x00\xfd"
1053		    "\xff\xff\xff\xff\xff\xff\xff"
1054		    , 1, 23, v);
1055}
1056
1057static const laminate_t updp10_laminate[] =
1058{
1059  {"Glossy",  N_("Glossy"),  {1, "\x00"}},
1060  {"Texture", N_("Texture"), {1, "\x08"}},
1061  {"Matte",   N_("Matte"),   {1, "\x0c"}},
1062};
1063
1064LIST(laminate_list_t, updp10_laminate_list, laminate_t, updp10_laminate);
1065
1066static const char updp10_adj_cyan[] =
1067  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1068  "<gutenprint>\n"
1069  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
1070  "<sequence count=\"33\" lower-bound=\"0\" upper-bound=\"1\">\n"
1071  "0.113725 0.188235 0.247059 0.286275 0.317647 0.345098 0.368627 0.384314\n"
1072  "0.400000 0.407843 0.423529 0.439216 0.450980 0.466667 0.482353 0.498039\n"
1073  "0.509804 0.525490 0.545098 0.560784 0.580392 0.596078 0.619608 0.643137\n"
1074  "0.662745 0.686275 0.709804 0.729412 0.756863 0.780392 0.811765 0.843137\n"
1075  "1.000000\n"
1076  "</sequence>\n"
1077  "</curve>\n"
1078  "</gutenprint>\n";
1079
1080static const char updp10_adj_magenta[] =
1081  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1082  "<gutenprint>\n"
1083  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
1084  "<sequence count=\"33\" lower-bound=\"0\" upper-bound=\"1\">\n"
1085  "0.105882 0.211765 0.286275 0.333333 0.364706 0.388235 0.403922 0.415686\n"
1086  "0.427451 0.439216 0.450980 0.462745 0.478431 0.494118 0.505882 0.521569\n"
1087  "0.537255 0.552941 0.568627 0.584314 0.600000 0.619608 0.643137 0.662745\n"
1088  "0.682353 0.709804 0.733333 0.760784 0.792157 0.823529 0.858824 0.890196\n"
1089  "1.000000\n"
1090  "</sequence>\n"
1091  "</curve>\n"
1092  "</gutenprint>\n";
1093
1094static const char updp10_adj_yellow[] =
1095  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1096  "<gutenprint>\n"
1097  "<curve wrap=\"nowrap\" type=\"spline\" gamma=\"0\">\n"
1098  "<sequence count=\"33\" lower-bound=\"0\" upper-bound=\"1\">\n"
1099  "0.101961 0.160784 0.196078 0.227451 0.243137 0.254902 0.266667 0.286275\n"
1100  "0.309804 0.337255 0.368627 0.396078 0.423529 0.443137 0.462745 0.478431\n"
1101  "0.501961 0.517647 0.537255 0.556863 0.576471 0.596078 0.619608 0.643137\n"
1102  "0.666667 0.690196 0.709804 0.737255 0.760784 0.780392 0.796078 0.803922\n"
1103  "1.000000\n"
1104  "</sequence>\n"
1105  "</curve>\n"
1106  "</gutenprint>\n";
1107
1108
1109/* Sony UP-DR100 */
1110static const dyesub_pagesize_t updr100_page[] =
1111{
1112  { "w288h432",	"4x6", 298, 442, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1113  { "B7",	"3.5x5", 261, 369, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1114  { "w360h504",	"5x7", 369, 514, 0, 0, 0, 0, DYESUB_PORTRAIT},
1115  { "w432h576",	"6x8", 442, 588, 0, 0, 0, 0, DYESUB_PORTRAIT},
1116  { "Custom", NULL, 298, 442, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1117};
1118
1119LIST(dyesub_pagesize_list_t, updr100_page_list, dyesub_pagesize_t, updr100_page);
1120
1121static const dyesub_printsize_t updr100_printsize[] =
1122{
1123  { "334x334", "w288h432", 1382, 2048},
1124  { "334x334", "B7", 1210, 1710},
1125  { "334x334", "w360h504", 1710, 2380},
1126  { "334x334", "w432h576", 2048, 2724},
1127  { "334x334", "Custom", 1382, 2048},
1128};
1129
1130LIST(dyesub_printsize_list_t, updr100_printsize_list, dyesub_printsize_t, updr100_printsize);
1131
1132static void updr100_printer_init_func(stp_vars_t *v)
1133{
1134  int dim1 = (privdata.print_mode == DYESUB_LANDSCAPE ?
1135  		privdata.h_size : privdata.w_size);
1136  int dim2 = (privdata.print_mode == DYESUB_LANDSCAPE ?
1137  		privdata.w_size : privdata.h_size);
1138
1139  stp_zfwrite("UPD8D\x00\x00\x00\x10\x03\x00\x00", 1, 12, v);
1140  stp_put32_le(dim1, v);
1141  stp_put32_le(dim2, v);
1142  stp_zfwrite("\x1e\x00\x03\x00\x01\x00\x4e\x01\x00\x00", 1, 10, v);
1143  stp_write_raw(&(privdata.laminate->seq), v); /* laminate pattern */
1144  dyesub_nputc(v, '\0', 13);
1145  stp_zfwrite("\x01\x00\x01\x00\x03", 1, 5, v);
1146  dyesub_nputc(v, '\0', 19);
1147}
1148
1149static void updr100_printer_end_func(stp_vars_t *v)
1150{
1151  stp_zfwrite("UPD8D\x00\x00\x00\x02", 1, 9, v);
1152  dyesub_nputc(v, '\0', 25);
1153  stp_zfwrite("\x9d\x02\x00\x04\x00\x00\xc0\xe7"
1154  	      "\x9d\x02\x54\xe9\x9d\x02\x9d\x71"
1155	      "\x00\x73\xfa\x71\x00\x73\xf4\xea"
1156	      "\x9d\x02\xa8\x3e\x00\x73\x9c\xeb\x9d\x02"
1157	      , 1, 34, v);
1158}
1159
1160static const laminate_t updr100_laminate[] =
1161{
1162  {"Glossy",  N_("Glossy"),  {1, "\x01"}},
1163  {"Texture", N_("Texture"), {1, "\x03"}},
1164  {"Matte",   N_("Matte"),   {1, "\x04"}},
1165};
1166
1167LIST(laminate_list_t, updr100_laminate_list, laminate_t, updr100_laminate);
1168
1169
1170/* Sony UP-DR150 */
1171static const dyesub_resolution_t res_334dpi[] =
1172{
1173  { "334x334", 334, 334},
1174};
1175
1176LIST(dyesub_resolution_list_t, res_334dpi_list, dyesub_resolution_t, res_334dpi);
1177
1178static const dyesub_pagesize_t updr150_page[] =
1179{
1180  { "w288h432",	"2UPC-153 (4x6)", 298, 442, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1181  { "B7",	"2UPC-154 (3.5x5)", 261, 373, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1182  { "w360h504",	"2UPC-155 (5x7)", 373, 514, 0, 0, 0, 0, DYESUB_PORTRAIT},
1183  { "w432h576",	"2UPC-156 (6x8)", 442, 588, 0, 0, 0, 0, DYESUB_PORTRAIT},
1184  { "Custom", NULL, 298, 442, 0, 0, 0, 0, DYESUB_LANDSCAPE},
1185};
1186
1187LIST(dyesub_pagesize_list_t, updr150_page_list, dyesub_pagesize_t, updr150_page);
1188
1189static const dyesub_printsize_t updr150_printsize[] =
1190{
1191  { "334x334", "w288h432", 1382, 2048},
1192  { "334x334", "B7", 1210, 1728},
1193  { "334x334", "w360h504", 1728, 2380},
1194  { "334x334", "w432h576", 2048, 2724},
1195  { "334x334", "Custom", 1382, 2048},
1196};
1197
1198LIST(dyesub_printsize_list_t, updr150_printsize_list, dyesub_printsize_t, updr150_printsize);
1199
1200static void updr150_printer_init_func(stp_vars_t *v)
1201{
1202  char pg = '\0';
1203  int dim1 = (privdata.print_mode == DYESUB_LANDSCAPE ?
1204  		privdata.w_size : privdata.h_size);
1205  int dim2 = (privdata.print_mode == DYESUB_LANDSCAPE ?
1206  		privdata.h_size : privdata.w_size);
1207
1208  stp_zfwrite("\x6a\xff\xff\xff\xef\xff\xff\xff", 1, 8, v);
1209  if (strcmp(privdata.pagesize,"B7") == 0)
1210    pg = '\x01';
1211  else if (strcmp(privdata.pagesize,"w288h432") == 0)
1212    pg = '\x02';
1213  else if (strcmp(privdata.pagesize,"w360h504") == 0)
1214    pg = '\x03';
1215  else if (strcmp(privdata.pagesize,"w432h576") == 0)
1216    pg = '\x04';
1217  stp_putc(pg, v);
1218
1219  stp_zfwrite("\x00\x00\x00\xfc\xff\xff\xff"
1220	      "\xfb\xff\xff\xff\xf4\xff\xff\xff"
1221	      "\xf5\xff\xff\xff\x01\x00\x00\x00"
1222	      "\x07\x00\x00\x00\x1b\xe5\x00\x00"
1223	      "\x00\x08\x00\x08\x00\x00\x00\x00"
1224	      "\x00\x00\x00\x00\x00\x01\x00\xed"
1225	      "\xff\xff\xff\x07\x00\x00\x00\x1b"
1226	      "\xee\x00\x00\x00\x02\x00\x02\x00"
1227	      "\x00\x00\x00\x01\x07\x00\x00\x00"
1228	      "\x1b\x15\x00\x00\x00\x0d\x00\x0d"
1229	      "\x00\x00\x00\x00\x00\x00\x00\x07"
1230	      "\x00\x00\x00\x00", 1, 91, v);
1231  stp_put16_be(dim1, v);
1232  stp_put16_be(dim2, v);
1233  stp_zfwrite("\xf9\xff\xff\xff\x07\x00\x00\x00"
1234	      "\x1b\xe1\x00\x00\x00\x0b\x00\x0b"
1235	      "\x00\x00\x00\x00\x80\x00\x00\x00"
1236	      "\x00\x00", 1, 26, v);
1237  stp_put16_be(dim1, v);
1238  stp_put16_be(dim2, v);
1239  stp_zfwrite("\xf8\xff\xff\xff\x0b\x00\x00\x00\x1b\xea"
1240	      "\x00\x00\x00\x00", 1, 14, v);
1241  stp_put32_be(privdata.w_size*privdata.h_size*3, v);
1242  stp_zfwrite("\x00", 1, 1, v);
1243  stp_put32_le(privdata.w_size*privdata.h_size*3, v);
1244}
1245
1246static void updr150_printer_end_func(stp_vars_t *v)
1247{
1248	stp_zfwrite("\xfc\xff\xff"
1249		    "\xff\xfa\xff\xff\xff\x07\x00\x00"
1250		    "\x00\x1b\x0a\x00\x00\x00\x00\x00"
1251		    "\x07\x00\x00\x00\x1b\x17\x00\x00"
1252		    "\x00\x00\x00\xf3\xff\xff\xff"
1253		    , 1, 34, v);
1254}
1255
1256
1257/* Fujifilm CX-400 */
1258static const dyesub_pagesize_t cx400_page[] =
1259{
1260  { "w288h432", NULL, 295, 428, 24, 24, 23, 22, DYESUB_PORTRAIT},
1261  { "w288h387", "4x5 3/8", 295, 386, 24, 24, 23, 23, DYESUB_PORTRAIT},
1262  { "w288h504", NULL, 295, 513, 24, 24, 23, 22, DYESUB_PORTRAIT},
1263  { "Custom", NULL, 295, 428, 0, 0, 0, 0, DYESUB_PORTRAIT},
1264};
1265
1266LIST(dyesub_pagesize_list_t, cx400_page_list, dyesub_pagesize_t, cx400_page);
1267
1268static const dyesub_printsize_t cx400_printsize[] =
1269{
1270  { "310x310", "w288h387", 1268, 1658},
1271  { "310x310", "w288h432", 1268, 1842},
1272  { "310x310", "w288h504", 1268, 2208},
1273  { "310x310", "Custom", 1268, 1842},
1274};
1275
1276LIST(dyesub_printsize_list_t, cx400_printsize_list, dyesub_printsize_t, cx400_printsize);
1277
1278static void cx400_printer_init_func(stp_vars_t *v)
1279{
1280  char pg = '\0';
1281  const char *pname = "XXXXXX";
1282
1283  stp_deprintf(STP_DBG_DYESUB,
1284	"dyesub: fuji driver %s\n", stp_get_driver(v));
1285  if (strcmp(stp_get_driver(v),"fujifilm-cx400") == 0)
1286    pname = "NX1000";
1287  else if (strcmp(stp_get_driver(v),"fujifilm-cx550") == 0)
1288    pname = "QX200\0";
1289
1290  stp_zfwrite("FUJIFILM", 1, 8, v);
1291  stp_zfwrite(pname, 1, 6, v);
1292  stp_putc('\0', v);
1293  stp_put16_le(privdata.w_size, v);
1294  stp_put16_le(privdata.h_size, v);
1295  if (strcmp(privdata.pagesize,"w288h504") == 0)
1296    pg = '\x0d';
1297  else if (strcmp(privdata.pagesize,"w288h432") == 0)
1298    pg = '\x0c';
1299  else if (strcmp(privdata.pagesize,"w288h387") == 0)
1300    pg = '\x0b';
1301  stp_putc(pg, v);
1302  stp_zfwrite("\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00"
1303		  "\x00\x00\x2d\x00\x00\x00\x00", 1, 19, v);
1304  stp_zfwrite("FUJIFILM", 1, 8, v);
1305  stp_zfwrite(pname, 1, 6, v);
1306  stp_putc('\1', v);
1307}
1308
1309
1310/* Fujifilm NX-500 */
1311static const dyesub_resolution_t res_306dpi[] =
1312{
1313  { "306x306", 306, 306},
1314};
1315
1316LIST(dyesub_resolution_list_t, res_306dpi_list, dyesub_resolution_t, res_306dpi);
1317
1318static const dyesub_pagesize_t nx500_page[] =
1319{
1320  { "Postcard", NULL, -1, -1, 21, 21, 29, 29, DYESUB_PORTRAIT},
1321  { "Custom", NULL, -1, -1, 21, 21, 29, 29, DYESUB_PORTRAIT},
1322};
1323
1324LIST(dyesub_pagesize_list_t, nx500_page_list, dyesub_pagesize_t, nx500_page);
1325
1326static const dyesub_printsize_t nx500_printsize[] =
1327{
1328  { "306x306", "Postcard", 1024, 1518},
1329  { "306x306", "Custom", 1024, 1518},
1330};
1331
1332LIST(dyesub_printsize_list_t, nx500_printsize_list, dyesub_printsize_t, nx500_printsize);
1333
1334static void nx500_printer_init_func(stp_vars_t *v)
1335{
1336  stp_zfwrite("INFO-QX-20--MKS\x00\x00\x00M\x00W\00A\x00R\00E", 1, 27, v);
1337  dyesub_nputc(v, '\0', 21);
1338  stp_zfwrite("\x80\x00\x02", 1, 3, v);
1339  dyesub_nputc(v, '\0', 20);
1340  stp_zfwrite("\x02\x01\x01", 1, 3, v);
1341  dyesub_nputc(v, '\0', 2);
1342  stp_put16_le(privdata.h_size, v);
1343  stp_put16_le(privdata.w_size, v);
1344  stp_zfwrite("\x00\x02\x00\x70\x2f", 1, 5, v);
1345  dyesub_nputc(v, '\0', 43);
1346}
1347
1348
1349/* Kodak Easyshare Dock family */
1350static const dyesub_pagesize_t kodak_dock_page[] =
1351{
1352  { "w288h432", NULL, PT(1248,300)+1, PT(1856,300)+1, 0, 0, 0, 0,
1353  						DYESUB_PORTRAIT}, /* 4x6 */
1354  { "Custom", NULL, PT(1248,300)+1, PT(1856,300)+1, 0, 0, 0, 0,
1355  						DYESUB_PORTRAIT}, /* 4x6 */
1356};
1357
1358LIST(dyesub_pagesize_list_t, kodak_dock_page_list, dyesub_pagesize_t, kodak_dock_page);
1359
1360static const dyesub_printsize_t kodak_dock_printsize[] =
1361{
1362  { "300x300", "w288h432", 1248, 1856},
1363  { "300x300", "Custom", 1248, 1856},
1364};
1365
1366LIST(dyesub_printsize_list_t, kodak_dock_printsize_list, dyesub_printsize_t, kodak_dock_printsize);
1367
1368static void kodak_dock_printer_init(stp_vars_t *v)
1369{
1370  stp_put16_be(0x3000, v);
1371  dyesub_nputc(v, '\0', 10);
1372}
1373
1374static void kodak_dock_plane_init(stp_vars_t *v)
1375{
1376  stp_put16_be(0x3001, v);
1377  stp_put16_le(3 - privdata.plane, v);
1378  stp_put32_le(privdata.w_size*privdata.h_size, v);
1379  dyesub_nputc(v, '\0', 4);
1380}
1381
1382
1383/* Shinko CHC-S9045 (experimental) */
1384static const dyesub_pagesize_t shinko_chcs9045_page[] =
1385{
1386  { "w288h432",	"4x6", PT(1240,300)+1, PT(1844,300)+1, 0, 0, 0, 0,
1387  							DYESUB_LANDSCAPE},
1388  { "B7",	"3.5x5", PT(1088,300)+1, PT(1548,300)+1, 0, 0, 0, 0,
1389  							DYESUB_LANDSCAPE},
1390  { "w360h504",	"5x7", PT(1548,300)+1, PT(2140,300)+1, 0, 0, 0, 0,
1391  							DYESUB_PORTRAIT},
1392  { "w432h576",	"6x9", PT(1844,300)+1, PT(2740,300)+1, 0, 0, 0, 0,
1393  							DYESUB_PORTRAIT},
1394  { "w283h425",	"Sticker paper", PT(1092,300)+1, PT(1726,300)+1, 0, 0, 0, 0,
1395  							DYESUB_LANDSCAPE},
1396  { "Custom",   NULL, PT(1240,300)+1, PT(1844,300)+1, 0, 0, 0, 0,
1397  							DYESUB_LANDSCAPE},
1398};
1399
1400LIST(dyesub_pagesize_list_t, shinko_chcs9045_page_list, dyesub_pagesize_t, shinko_chcs9045_page);
1401
1402static const dyesub_printsize_t shinko_chcs9045_printsize[] =
1403{
1404  { "300x300", "w288h432", 1240, 1844},
1405  { "300x300", "B7", 1088, 1548},
1406  { "300x300", "w360h504", 1548, 2140},
1407  { "300x300", "w432h576", 1844, 2740},
1408  { "300x300", "w283h425", 1092, 1726},
1409  { "300x300", "Custom", 1240, 1844},
1410};
1411
1412LIST(dyesub_printsize_list_t, shinko_chcs9045_printsize_list, dyesub_printsize_t, shinko_chcs9045_printsize);
1413
1414static void shinko_chcs9045_printer_init(stp_vars_t *v)
1415{
1416  char pg = '\0';
1417  char sticker = '\0';
1418
1419  stp_zprintf(v, "\033CHC\n");
1420  stp_put16_be(1, v);
1421  stp_put16_be(1, v);
1422  stp_put16_be(privdata.w_size, v);
1423  stp_put16_be(privdata.h_size, v);
1424  if (strcmp(privdata.pagesize,"B7") == 0)
1425    pg = '\1';
1426  else if (strcmp(privdata.pagesize,"w360h504") == 0)
1427    pg = '\3';
1428  else if (strcmp(privdata.pagesize,"w432h576") == 0)
1429    pg = '\5';
1430  else if (strcmp(privdata.pagesize,"w283h425") == 0)
1431    sticker = '\3';
1432  stp_putc(pg, v);
1433  stp_putc('\0', v);
1434  stp_putc(sticker, v);
1435  dyesub_nputc(v, '\0', 4338);
1436}
1437
1438
1439/* Dai Nippon Printing DS40 */
1440static const dyesub_pagesize_t dnpds40_dock_page[] =
1441{
1442  { "w288h432", "4x6", PT(1920,300)+1, PT(1240,300)+1, 0, 0, 0, 0,
1443						DYESUB_PORTRAIT},
1444  { "w432h576", "6x9", PT(1920,300)+1, PT(2740,300)+1, 0, 0, 0, 0,
1445							DYESUB_PORTRAIT},
1446  { "A5", "6x8", PT(1920,300)+1, PT(2436,300)+1, 0, 0, 0, 0,
1447						DYESUB_PORTRAIT},
1448};
1449
1450LIST(dyesub_pagesize_list_t, dnpds40_dock_page_list, dyesub_pagesize_t, dnpds40_dock_page);
1451
1452static const dyesub_printsize_t dnpds40_dock_printsize[] =
1453{
1454  { "300x300", "w288h432", 1920, 1240},
1455  { "300x300", "w432h576", 1920, 2740},
1456  { "300x300", "A5", 1920, 2436},
1457};
1458
1459LIST(dyesub_printsize_list_t, dnpds40_dock_printsize_list, dyesub_printsize_t, dnpds40_dock_printsize);
1460
1461static void dnpds40_printer_end(stp_vars_t *v)
1462{
1463  stp_zprintf(v, "\033PCNTRL START"); dyesub_nputc(v, ' ', 19);
1464}
1465
1466static void dnpds40_plane_init(stp_vars_t *v)
1467{
1468  char p = (privdata.plane == 3 ? 'Y' :
1469	    (privdata.plane == 2 ? 'M' :
1470	     'C' ));
1471
1472  long RFSize = (privdata.w_size*privdata.h_size) + 1024 + 54;
1473  long AdSize = (32 - (RFSize % 32));
1474  long FSize = RFSize + AdSize;
1475
1476  stp_zprintf(v, "\033PCNTRL RETENTION       0000000800000000");
1477  stp_zprintf(v, "\033PIMAGE %cPLANE", p); dyesub_nputc(v, ' ', 10);
1478
1479  stp_zprintf(v, "0%ld", FSize);
1480  stp_zprintf(v, "BM");
1481  stp_put32_le(FSize, v);
1482  dyesub_nputc(v, '\0', 4);
1483  stp_put32_le(1088, v);
1484  stp_put32_le(40, v);
1485  stp_put32_le(privdata.w_size, v);
1486  stp_put32_le(privdata.h_size, v);
1487  stp_put16_le(1, v);
1488  stp_put16_le(8, v);
1489  dyesub_nputc(v, '\0', 24);
1490  dyesub_nputc(v, '\0', 1024);   /*RGB Array*/
1491  dyesub_nputc(v, '\0', AdSize); /*Locate to 32bit border */
1492}
1493
1494
1495
1496/* Dai Nippon Printing DS80 */
1497static const dyesub_pagesize_t dnpds80_dock_page[] =
1498{
1499  { "c8x10", "8x10", PT(2560,300)+1, PT(3036,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1500  { "C6", "8x4", PT(2560,300)+1, PT(1236,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},/* 8x4 */
1501  { "C5", "8x5", PT(2560,300)+1, PT(1536,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1502  { "C4", "8x6", PT(2560,300)+1, PT(1836,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1503  { "C3", "8x8", PT(2560,300)+1, PT(2436,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1504  { "C2", "8x12", PT(2560,300)+1, PT(3636,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1505  { "C1", "A4 Length", PT(2560,300)+1, PT(3544,300)+1, 0, 0, 0, 0, DYESUB_PORTRAIT},
1506};
1507
1508LIST(dyesub_pagesize_list_t, dnpds80_dock_page_list, dyesub_pagesize_t, dnpds80_dock_page);
1509
1510static const dyesub_printsize_t dnpds80_dock_printsize[] =
1511{
1512  { "300x300", "c8x10", 2560, 3036},
1513  { "300x300", "C6", 2560, 1236},
1514  { "300x300", "C5", 2560, 1536},
1515  { "300x300", "C4", 2560, 1836},
1516  { "300x300", "C3", 2560, 2436},
1517  { "300x300", "C2", 2560, 3636},
1518  { "300x300", "C1", 2560, 3544},
1519};
1520
1521LIST(dyesub_printsize_list_t, dnpds80_dock_printsize_list, dyesub_printsize_t, dnpds80_dock_printsize);
1522
1523/* Model capabilities */
1524
1525static const dyesub_cap_t dyesub_model_capabilities[] =
1526{
1527  { /* Olympus P-10, P-11 */
1528    2,
1529    &rgb_ink_list,
1530    &res_310dpi_list,
1531    &p10_page_list,
1532    &p10_printsize_list,
1533    SHRT_MAX,
1534    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1535      | DYESUB_FEATURE_PLANE_INTERLACE,
1536    &p10_printer_init_func, &p10_printer_end_func,
1537    NULL, NULL,
1538    &p10_block_init_func, NULL,
1539    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1540    &p10_laminate_list,
1541  },
1542  { /* Olympus P-200 */
1543    4,
1544    &ymc_ink_list,
1545    &res_320dpi_list,
1546    &p200_page_list,
1547    &p200_printsize_list,
1548    SHRT_MAX,
1549    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_BLOCK_ALIGN
1550      | DYESUB_FEATURE_PLANE_INTERLACE,
1551    &p200_printer_init_func, &p200_printer_end_func,
1552    &p200_plane_init_func, NULL,
1553    NULL, NULL,
1554    p200_adj_any, p200_adj_any, p200_adj_any,
1555    NULL,
1556  },
1557  { /* Olympus P-300 */
1558    0,
1559    &ymc_ink_list,
1560    &p300_res_list,
1561    &p300_page_list,
1562    &p300_printsize_list,
1563    16,
1564    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_BLOCK_ALIGN
1565      | DYESUB_FEATURE_PLANE_INTERLACE,
1566    &p300_printer_init_func, NULL,
1567    NULL, &p300_plane_end_func,
1568    &p300_block_init_func, NULL,
1569    p300_adj_cyan, p300_adj_magenta, p300_adj_yellow,
1570    NULL,
1571  },
1572  { /* Olympus P-400 */
1573    1,
1574    &ymc_ink_list,
1575    &res_314dpi_list,
1576    &p400_page_list,
1577    &p400_printsize_list,
1578    180,
1579    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1580      | DYESUB_FEATURE_PLANE_INTERLACE,
1581    &p400_printer_init_func, NULL,
1582    &p400_plane_init_func, &p400_plane_end_func,
1583    &p400_block_init_func, NULL,
1584    p400_adj_cyan, p400_adj_magenta, p400_adj_yellow,
1585    NULL,
1586  },
1587  { /* Olympus P-440 */
1588    3,
1589    &bgr_ink_list,
1590    &res_314dpi_list,
1591    &p440_page_list,
1592    &p440_printsize_list,
1593    128,
1594    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1595    &p440_printer_init_func, &p440_printer_end_func,
1596    NULL, NULL,
1597    &p440_block_init_func, &p440_block_end_func,
1598    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1599    &p10_laminate_list,
1600  },
1601  { /* Olympus P-S100 */
1602    20,
1603    &bgr_ink_list,
1604    &res_306dpi_list,
1605    &ps100_page_list,
1606    &ps100_printsize_list,
1607    1808,
1608    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1609    &ps100_printer_init_func, &ps100_printer_end_func,
1610    NULL, NULL,
1611    NULL, NULL,
1612    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1613    NULL,
1614  },
1615  { /* Canon CP-10 */
1616    1002,
1617    &ymc_ink_list,
1618    &res_300dpi_list,
1619    &cp10_page_list,
1620    &cp10_printsize_list,
1621    SHRT_MAX,
1622    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1623      | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER
1624      | DYESUB_FEATURE_PLANE_INTERLACE,
1625    &cpx00_printer_init_func, NULL,
1626    &cpx00_plane_init_func, NULL,
1627    NULL, NULL,
1628    cpx00_adj_cyan, cpx00_adj_magenta, cpx00_adj_yellow,
1629    NULL,
1630  },
1631  { /* Canon CP-100, CP-200, CP-300 */
1632    1000,
1633    &ymc_ink_list,
1634    &res_300dpi_list,
1635    &cpx00_page_list,
1636    &cpx00_printsize_list,
1637    SHRT_MAX,
1638    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1639      | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER
1640      | DYESUB_FEATURE_PLANE_INTERLACE,
1641    &cpx00_printer_init_func, NULL,
1642    &cpx00_plane_init_func, NULL,
1643    NULL, NULL,
1644    cpx00_adj_cyan, cpx00_adj_magenta, cpx00_adj_yellow,
1645    NULL,
1646  },
1647  { /* Canon CP-220, CP-330, SELPHY CP-400, SELPHY CP-500, SELPHY CP-510,
1648       SELPHY CP-600, SELPHY CP-710, SELPHY CP-720, SELPHY CP-730,
1649       SELPHY CP-740, SELPHY CP-750 */
1650    1001,
1651    &ymc_ink_list,
1652    &res_300dpi_list,
1653    &cp220_page_list,
1654    &cp220_printsize_list,
1655    SHRT_MAX,
1656    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1657      | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER
1658      | DYESUB_FEATURE_PLANE_INTERLACE,
1659    &cpx00_printer_init_func, NULL,
1660    &cpx00_plane_init_func, NULL,
1661    NULL, NULL,
1662    cpx00_adj_cyan, cpx00_adj_magenta, cpx00_adj_yellow,
1663    NULL,
1664  },
1665  { /* Canon CP-520, SELPHY CP-530 */
1666    1004,
1667    &ymc_ink_list,
1668    &res_300dpi_list,
1669    &cp220_page_list,
1670    &cp220_printsize_list,
1671    SHRT_MAX,
1672    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1673      | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER
1674      | DYESUB_FEATURE_PLANE_INTERLACE,
1675    &cp520_printer_init_func, NULL,
1676    &cp520_plane_init_func, NULL,
1677    NULL, NULL,
1678    cpx00_adj_cyan, cpx00_adj_magenta, cpx00_adj_yellow,
1679    NULL,
1680  },
1681  { /* Canon SELPHY ES1, ES2, ES20 (!experimental) */
1682    1003,
1683    &ymc_ink_list,
1684    &res_300dpi_list,
1685    &cpx00_page_list,
1686    &cpx00_printsize_list,
1687    SHRT_MAX,
1688    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1689      | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER
1690      | DYESUB_FEATURE_PLANE_INTERLACE,
1691    &es1_printer_init_func, NULL,
1692    &es1_plane_init_func, NULL,
1693    NULL, NULL,
1694    cpx00_adj_cyan, cpx00_adj_magenta, cpx00_adj_yellow,
1695    NULL,
1696  },
1697  { /* Sony DPP-EX5, DPP-EX7 */
1698    2002,
1699    &rgb_ink_list,
1700    &res_403dpi_list,
1701    &dppex5_page_list,
1702    &dppex5_printsize_list,
1703    100,
1704    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1705      | DYESUB_FEATURE_BORDERLESS,
1706    &dppex5_printer_init, &dppex5_printer_end,
1707    NULL, NULL,
1708    &dppex5_block_init, NULL,
1709    NULL, NULL, NULL,
1710    &dppex5_laminate_list,
1711  },
1712  { /* Sony UP-DP10  */
1713    2000,
1714    &cmy_ink_list,
1715    &res_300dpi_list,
1716    &updp10_page_list,
1717    &updp10_printsize_list,
1718    SHRT_MAX,
1719    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1720      | DYESUB_FEATURE_BORDERLESS,
1721    &updp10_printer_init_func, &updp10_printer_end_func,
1722    NULL, NULL,
1723    NULL, NULL,
1724    updp10_adj_cyan, updp10_adj_magenta, updp10_adj_yellow,
1725    &updp10_laminate_list,
1726  },
1727  { /* Sony UP-DR100 */
1728    2003,
1729    &rgb_ink_list,
1730    &res_334dpi_list,
1731    &updr100_page_list,
1732    &updr100_printsize_list,
1733    SHRT_MAX,
1734    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1735    &updr100_printer_init_func, &updr100_printer_end_func,
1736    NULL, NULL,
1737    NULL, NULL,
1738    NULL, NULL, NULL,
1739    &updr100_laminate_list,
1740  },
1741  { /* Sony UP-DR150 */
1742    2001,
1743    &rgb_ink_list,
1744    &res_334dpi_list,
1745    &updr150_page_list,
1746    &updr150_printsize_list,
1747    SHRT_MAX,
1748    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1749    &updr150_printer_init_func, &updr150_printer_end_func,
1750    NULL, NULL,
1751    NULL, NULL,
1752    NULL, NULL, NULL,
1753    NULL,
1754  },
1755  { /* Fujifilm Printpix CX-400  */
1756    3000,
1757    &rgb_ink_list,
1758    &res_310dpi_list,
1759    &cx400_page_list,
1760    &cx400_printsize_list,
1761    SHRT_MAX,
1762    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1763      | DYESUB_FEATURE_BORDERLESS,
1764    &cx400_printer_init_func, NULL,
1765    NULL, NULL,
1766    NULL, NULL,
1767    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1768    NULL,
1769  },
1770  { /* Fujifilm Printpix CX-550  */
1771    3001,
1772    &rgb_ink_list,
1773    &res_310dpi_list,
1774    &cx400_page_list,
1775    &cx400_printsize_list,
1776    SHRT_MAX,
1777    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1778      | DYESUB_FEATURE_BORDERLESS,
1779    &cx400_printer_init_func, NULL,
1780    NULL, NULL,
1781    NULL, NULL,
1782    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1783    NULL,
1784  },
1785  { /* Fujifilm FinePix NX-500  */
1786    3002,
1787    &rgb_ink_list,
1788    &res_306dpi_list,
1789    &nx500_page_list,
1790    &nx500_printsize_list,
1791    SHRT_MAX,
1792    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1793    &nx500_printer_init_func, NULL,
1794    NULL, NULL,
1795    NULL, NULL,
1796    NULL, NULL, NULL,	/* color profile/adjustment is built into printer */
1797    NULL,
1798  },
1799  { /* Kodak Easyshare Dock family */
1800    4000,
1801    &ymc_ink_list,
1802    &res_300dpi_list,
1803    &kodak_dock_page_list,
1804    &kodak_dock_printsize_list,
1805    SHRT_MAX,
1806    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1807      | DYESUB_FEATURE_PLANE_INTERLACE,
1808    &kodak_dock_printer_init, NULL,
1809    &kodak_dock_plane_init, NULL,
1810    NULL, NULL,
1811    NULL, NULL, NULL,
1812    NULL,
1813  },
1814  { /* Shinko CHC-S9045 (experimental) */
1815    5000,
1816    &rgb_ink_list,
1817    &res_300dpi_list,
1818    &shinko_chcs9045_page_list,
1819    &shinko_chcs9045_printsize_list,
1820    SHRT_MAX,
1821    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT,
1822    &shinko_chcs9045_printer_init, NULL,
1823    NULL, NULL,
1824    NULL, NULL,
1825    NULL, NULL, NULL,
1826    NULL,
1827  },
1828  { /* Dai Nippon Printing DS40 */
1829    6000,
1830    &rgb_ink_list,
1831    &res_300dpi_list,
1832    &dnpds40_dock_page_list,
1833    &dnpds40_dock_printsize_list,
1834    SHRT_MAX,
1835    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1836      | DYESUB_FEATURE_PLANE_INTERLACE | DYESUB_FEATURE_PLANE_LEFTTORIGHT,
1837    NULL, &dnpds40_printer_end,
1838    &dnpds40_plane_init, NULL,
1839    NULL, NULL,
1840    NULL, NULL, NULL,
1841    NULL,
1842  },
1843  { /* Dai Nippon Printing DS80 */
1844    6001,
1845    &rgb_ink_list,
1846    &res_300dpi_list,
1847    &dnpds80_dock_page_list,
1848    &dnpds80_dock_printsize_list,
1849    SHRT_MAX,
1850    DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT
1851      | DYESUB_FEATURE_PLANE_INTERLACE | DYESUB_FEATURE_PLANE_LEFTTORIGHT,
1852    NULL, &dnpds40_printer_end,
1853    &dnpds40_plane_init, NULL,
1854    NULL, NULL,
1855    NULL, NULL, NULL,
1856    NULL,
1857  },
1858};
1859
1860static const stp_parameter_t the_parameters[] =
1861{
1862  {
1863    "PageSize", N_("Page Size"), "Color=No,Category=Basic Printer Setup",
1864    N_("Size of the paper being printed to"),
1865    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
1866    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1867  },
1868  {
1869    "MediaType", N_("Media Type"), "Color=Yes,Category=Basic Printer Setup",
1870    N_("Type of media (plain paper, photo paper, etc.)"),
1871    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
1872    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1873  },
1874  {
1875    "InputSlot", N_("Media Source"), "Color=No,Category=Basic Printer Setup",
1876    N_("Source (input slot) of the media"),
1877    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
1878    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1879  },
1880  {
1881    "Resolution", N_("Resolution"), "Color=Yes,Category=Basic Printer Setup",
1882    N_("Resolution and quality of the print"),
1883    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
1884    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1885  },
1886  {
1887    "InkType", N_("Ink Type"), "Color=Yes,Category=Advanced Printer Setup",
1888    N_("Type of ink in the printer"),
1889    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
1890    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1891  },
1892  {
1893    /* TRANSLATORS: Some dye sublimation printers are able to achieve */
1894    /* better durability of output by covering it with transparent */
1895    /* laminate surface. This surface can be of different patterns: */
1896    /* common are matte, glossy or texture. */
1897    "Laminate", N_("Laminate Pattern"), "Color=Yes,Category=Advanced Printer Setup",
1898    N_("Laminate Pattern"),
1899    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE,
1900    STP_PARAMETER_LEVEL_BASIC, 1, 0, STP_CHANNEL_NONE, 1, 0
1901  },
1902  {
1903    "Borderless", N_("Borderless"), "Color=No,Category=Advanced Printer Setup",
1904    N_("Print without borders"),
1905    STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE,
1906    STP_PARAMETER_LEVEL_BASIC, 1, 0, STP_CHANNEL_NONE, 1, 0
1907  },
1908  {
1909    "PrintingMode", N_("Printing Mode"), "Color=Yes,Category=Core Parameter",
1910    N_("Printing Output Mode"),
1911    STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
1912    STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
1913  },
1914};
1915
1916static int the_parameter_count =
1917sizeof(the_parameters) / sizeof(const stp_parameter_t);
1918
1919typedef struct
1920{
1921  const stp_parameter_t param;
1922  double min;
1923  double max;
1924  double defval;
1925  int color_only;
1926} float_param_t;
1927
1928static const float_param_t float_parameters[] =
1929{
1930  {
1931    {
1932      "CyanDensity", N_("Cyan Balance"), N_("Output Level Adjustment"),
1933      N_("Adjust the cyan balance"),
1934      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
1935      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 1, 1, 0
1936    }, 0.0, 2.0, 1.0, 1
1937  },
1938  {
1939    {
1940      "MagentaDensity", N_("Magenta Balance"), N_("Output Level Adjustment"),
1941      N_("Adjust the magenta balance"),
1942      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
1943      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 2, 1, 0
1944    }, 0.0, 2.0, 1.0, 1
1945  },
1946  {
1947    {
1948      "YellowDensity", N_("Yellow Balance"), N_("Output Level Adjustment"),
1949      N_("Adjust the yellow balance"),
1950      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
1951      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 3, 1, 0
1952    }, 0.0, 2.0, 1.0, 1
1953  },
1954  {
1955    {
1956      "BlackDensity", N_("Black Balance"), N_("Output Level Adjustment"),
1957      N_("Adjust the black balance"),
1958      STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
1959      STP_PARAMETER_LEVEL_ADVANCED, 0, 1, 0, 1, 0
1960    }, 0.0, 2.0, 1.0, 1
1961  },
1962};
1963
1964static const int float_parameter_count =
1965sizeof(float_parameters) / sizeof(const float_param_t);
1966
1967static const dyesub_cap_t* dyesub_get_model_capabilities(int model)
1968{
1969  int i;
1970  int models = sizeof(dyesub_model_capabilities) / sizeof(dyesub_cap_t);
1971
1972  for (i=0; i<models; i++)
1973    {
1974      if (dyesub_model_capabilities[i].model == model)
1975        return &(dyesub_model_capabilities[i]);
1976    }
1977  stp_deprintf(STP_DBG_DYESUB,
1978  	"dyesub: model %d not found in capabilities list.\n", model);
1979  return &(dyesub_model_capabilities[0]);
1980}
1981
1982static const laminate_t* dyesub_get_laminate_pattern(stp_vars_t *v)
1983{
1984  const char *lpar = stp_get_string_parameter(v, "Laminate");
1985  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
1986		  				stp_get_model_id(v));
1987  const laminate_list_t *llist = caps->laminate;
1988  const laminate_t *l = NULL;
1989  int i;
1990
1991  for (i = 0; i < llist->n_items; i++)
1992    {
1993      l = &(llist->item[i]);
1994      if (strcmp(l->name, lpar) == 0)
1995	 break;
1996    }
1997  return l;
1998}
1999
2000static void
2001dyesub_printsize(const stp_vars_t *v,
2002		   int  *width,
2003		   int  *height)
2004{
2005  int i;
2006  const char *page = stp_get_string_parameter(v, "PageSize");
2007  const char *resolution = stp_get_string_parameter(v, "Resolution");
2008  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2009		  				stp_get_model_id(v));
2010  const dyesub_printsize_list_t *p = caps->printsize;
2011
2012  for (i = 0; i < p->n_items; i++)
2013    {
2014      if (strcmp(p->item[i].res_name,resolution) == 0 &&
2015          strcmp(p->item[i].pagesize_name,page) == 0)
2016        {
2017          *width  = p->item[i].width_px;
2018	  *height = p->item[i].height_px;
2019          return;
2020        }
2021    }
2022  stp_erprintf("dyesub_printsize: printsize not found (%s, %s)\n",
2023	       page, resolution);
2024}
2025
2026static int
2027dyesub_feature(const dyesub_cap_t *caps, int feature)
2028{
2029  return ((caps->features & feature) == feature);
2030}
2031
2032static stp_parameter_list_t
2033dyesub_list_parameters(const stp_vars_t *v)
2034{
2035  stp_parameter_list_t *ret = stp_parameter_list_create();
2036  int i;
2037
2038  for (i = 0; i < the_parameter_count; i++)
2039    stp_parameter_list_add_param(ret, &(the_parameters[i]));
2040  for (i = 0; i < float_parameter_count; i++)
2041    stp_parameter_list_add_param(ret, &(float_parameters[i].param));
2042  return ret;
2043}
2044
2045static void
2046dyesub_parameters(const stp_vars_t *v, const char *name,
2047	       stp_parameter_t *description)
2048{
2049  int	i;
2050  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2051		  				stp_get_model_id(v));
2052
2053  description->p_type = STP_PARAMETER_TYPE_INVALID;
2054  if (name == NULL)
2055    return;
2056
2057  description->deflt.str = NULL;
2058  for (i = 0; i < float_parameter_count; i++)
2059    if (strcmp(name, float_parameters[i].param.name) == 0)
2060      {
2061	stp_fill_parameter_settings(description,
2062				     &(float_parameters[i].param));
2063	description->deflt.dbl = float_parameters[i].defval;
2064	description->bounds.dbl.upper = float_parameters[i].max;
2065	description->bounds.dbl.lower = float_parameters[i].min;
2066      }
2067
2068  for (i = 0; i < the_parameter_count; i++)
2069    if (strcmp(name, the_parameters[i].name) == 0)
2070      {
2071	stp_fill_parameter_settings(description, &(the_parameters[i]));
2072	break;
2073      }
2074  if (strcmp(name, "PageSize") == 0)
2075    {
2076      int default_specified = 0;
2077      const dyesub_pagesize_list_t *p = caps->pages;
2078      const char* text;
2079
2080      description->bounds.str = stp_string_list_create();
2081      for (i = 0; i < p->n_items; i++)
2082	{
2083          const stp_papersize_t *pt = stp_get_papersize_by_name(
2084			  p->item[i].name);
2085
2086	  text = (p->item[i].text ? p->item[i].text : pt->text);
2087	  stp_string_list_add_string(description->bounds.str,
2088			  p->item[i].name, gettext(text));
2089	  if (! default_specified && pt && pt->width > 0 && pt->height > 0)
2090	    {
2091	      description->deflt.str = p->item[i].name;
2092	      default_specified = 1;
2093	    }
2094	}
2095      if (!default_specified)
2096	description->deflt.str =
2097	  stp_string_list_param(description->bounds.str, 0)->name;
2098    }
2099  else if (strcmp(name, "MediaType") == 0)
2100    {
2101      description->bounds.str = stp_string_list_create();
2102      description->is_active = 0;
2103    }
2104  else if (strcmp(name, "InputSlot") == 0)
2105    {
2106      description->bounds.str = stp_string_list_create();
2107      description->is_active = 0;
2108    }
2109  else if (strcmp(name, "Resolution") == 0)
2110    {
2111      char res_text[24];
2112      const dyesub_resolution_list_t *r = caps->resolution;
2113
2114      description->bounds.str = stp_string_list_create();
2115      for (i = 0; i < r->n_items; i++)
2116        {
2117	  sprintf(res_text, "%s DPI", r->item[i].name);
2118	  stp_string_list_add_string(description->bounds.str,
2119		r->item[i].name, gettext(res_text));
2120	}
2121      if (r->n_items < 1)
2122        description->is_active = 0;
2123      description->deflt.str =
2124	stp_string_list_param(description->bounds.str, 0)->name;
2125    }
2126  else if (strcmp(name, "InkType") == 0)
2127    {
2128      description->bounds.str = stp_string_list_create();
2129      for (i = 0; i < caps->inks->n_items; i++)
2130	stp_string_list_add_string(description->bounds.str,
2131			  caps->inks->item[i].name, gettext(caps->inks->item[i].name));
2132      description->deflt.str =
2133	stp_string_list_param(description->bounds.str, 0)->name;
2134      if (caps->inks->n_items < 2)
2135        description->is_active = 0;
2136    }
2137  else if (strcmp(name, "Laminate") == 0)
2138    {
2139      description->bounds.str = stp_string_list_create();
2140      if (caps->laminate)
2141        {
2142          const laminate_list_t *llist = caps->laminate;
2143
2144          for (i = 0; i < llist->n_items; i++)
2145            {
2146              const laminate_t *l = &(llist->item[i]);
2147	      stp_string_list_add_string(description->bounds.str,
2148			  	l->name, gettext(l->text));
2149	    }
2150          description->deflt.str =
2151	  stp_string_list_param(description->bounds.str, 0)->name;
2152          description->is_active = 1;
2153        }
2154    }
2155  else if (strcmp(name, "Borderless") == 0)
2156    {
2157      if (dyesub_feature(caps, DYESUB_FEATURE_BORDERLESS))
2158        description->is_active = 1;
2159    }
2160  else if (strcmp(name, "PrintingMode") == 0)
2161    {
2162      description->bounds.str = stp_string_list_create();
2163      stp_string_list_add_string
2164	(description->bounds.str, "Color", _("Color"));
2165      description->deflt.str =
2166	stp_string_list_param(description->bounds.str, 0)->name;
2167    }
2168  else
2169    description->is_active = 0;
2170}
2171
2172
2173static const dyesub_pagesize_t*
2174dyesub_current_pagesize(const stp_vars_t *v)
2175{
2176  const char *page = stp_get_string_parameter(v, "PageSize");
2177  const stp_papersize_t *pt = stp_get_papersize_by_name(page);
2178  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2179		  				stp_get_model_id(v));
2180  const dyesub_pagesize_list_t *p = caps->pages;
2181  int i;
2182
2183  for (i = 0; i < p->n_items; i++)
2184    {
2185      if (strcmp(p->item[i].name,pt->name) == 0)
2186          return &(p->item[i]);
2187    }
2188  return NULL;
2189}
2190
2191static void
2192dyesub_media_size(const stp_vars_t *v,
2193		int *width,
2194		int *height)
2195{
2196  const dyesub_pagesize_t *p = dyesub_current_pagesize(v);
2197  stp_default_media_size(v, width, height);
2198
2199  if (p && p->width_pt > 0)
2200    *width = p->width_pt;
2201  if (p && p->height_pt > 0)
2202    *height = p->height_pt;
2203}
2204
2205static void
2206dyesub_imageable_area_internal(const stp_vars_t *v,
2207				int  use_maximum_area,
2208				int  *left,
2209				int  *right,
2210				int  *bottom,
2211				int  *top,
2212				int  *print_mode)
2213{
2214  int width, height;
2215  const dyesub_pagesize_t *p = dyesub_current_pagesize(v);
2216  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2217		  				stp_get_model_id(v));
2218
2219  dyesub_media_size(v, &width, &height);
2220  if (use_maximum_area
2221      || (dyesub_feature(caps, DYESUB_FEATURE_BORDERLESS) &&
2222          stp_get_boolean_parameter(v, "Borderless"))
2223      || !p)
2224    {
2225      *left = 0;
2226      *top  = 0;
2227      *right  = width;
2228      *bottom = height;
2229    }
2230  else
2231    {
2232      *left = p->border_pt_left;
2233      *top  = p->border_pt_top;
2234      *right  = width  - p->border_pt_right;
2235      *bottom = height - p->border_pt_bottom;
2236    }
2237  if (p)
2238    *print_mode = p->print_mode;
2239  else
2240    *print_mode = DYESUB_PORTRAIT;
2241}
2242
2243static void
2244dyesub_imageable_area(const stp_vars_t *v,
2245		       int  *left,
2246		       int  *right,
2247		       int  *bottom,
2248		       int  *top)
2249{
2250  int not_used;
2251  dyesub_imageable_area_internal(v, 0, left, right, bottom, top, &not_used);
2252}
2253
2254static void
2255dyesub_maximum_imageable_area(const stp_vars_t *v,
2256			       int  *left,
2257			       int  *right,
2258			       int  *bottom,
2259			       int  *top)
2260{
2261  int not_used;
2262  dyesub_imageable_area_internal(v, 1, left, right, bottom, top, &not_used);
2263}
2264
2265static void
2266dyesub_limit(const stp_vars_t *v,			/* I */
2267	    int *width, int *height,
2268	    int *min_width, int *min_height)
2269{
2270  *width  = SHRT_MAX;
2271  *height = SHRT_MAX;
2272  *min_width  = 1;
2273  *min_height =	1;
2274}
2275
2276static void
2277dyesub_describe_resolution(const stp_vars_t *v, int *x, int *y)
2278{
2279  const char *resolution = stp_get_string_parameter(v, "Resolution");
2280  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2281  							stp_get_model_id(v));
2282  const dyesub_resolution_list_t *r = caps->resolution;
2283  int i;
2284
2285  *x = -1;
2286  *y = -1;
2287  if (resolution)
2288    {
2289      for (i = 0; i < r->n_items; i++)
2290	{
2291	  if (strcmp(resolution, r->item[i].name) == 0)
2292	    {
2293	      *x = r->item[i].w_dpi;
2294	      *y = r->item[i].h_dpi;
2295	      break;
2296	    }
2297	}
2298    }
2299  return;
2300}
2301
2302static const char *
2303dyesub_describe_output_internal(const stp_vars_t *v, dyesub_print_vars_t *pv)
2304{
2305  const char *ink_type      = stp_get_string_parameter(v, "InkType");
2306  const dyesub_cap_t *caps = dyesub_get_model_capabilities(
2307  							stp_get_model_id(v));
2308  const char *output_type;
2309  int i;
2310
2311  pv->ink_channels = 1;
2312  pv->ink_order = NULL;
2313  output_type = "CMY";
2314
2315  if (ink_type)
2316    {
2317      for (i = 0; i < caps->inks->n_items; i++)
2318	if (strcmp(ink_type, caps->inks->item[i].name) == 0)
2319	  {
2320	    output_type = caps->inks->item[i].output_type;
2321	    pv->ink_channels = caps->inks->item[i].output_channels;
2322	    pv->ink_order = caps->inks->item[i].channel_order;
2323	    break;
2324	  }
2325    }
2326
2327  return output_type;
2328}
2329
2330static const char *
2331dyesub_describe_output(const stp_vars_t *v)
2332{
2333  dyesub_print_vars_t ipv;
2334  return dyesub_describe_output_internal(v, &ipv);
2335}
2336
2337static void
2338dyesub_nputc(stp_vars_t *v, char byte, int count)
2339{
2340  if (count == 1)
2341    stp_putc(byte, v);
2342  else
2343    {
2344      int i;
2345      char *buf = privdata.nputc_buf;
2346      int size = count;
2347      int blocks = size / NPUTC_BUFSIZE;
2348      int leftover = size % NPUTC_BUFSIZE;
2349      if (size > NPUTC_BUFSIZE)
2350	size = NPUTC_BUFSIZE;
2351      (void) memset(buf, byte, size);
2352      if (blocks)
2353	for (i = 0; i < blocks; i++)
2354	  stp_zfwrite(buf, size, 1, v);
2355      if (leftover)
2356	stp_zfwrite(buf, leftover, 1, v);
2357    }
2358}
2359
2360static void
2361dyesub_swap_ints(int *a, int *b)
2362{
2363  int t = *a;
2364  *a = *b;
2365  *b = t;
2366}
2367
2368static void
2369dyesub_adjust_curve(stp_vars_t *v,
2370		const char *color_adj,
2371		const char *color_curve)
2372{
2373  stp_curve_t   *adjustment = NULL;
2374
2375  if (color_adj &&
2376        !stp_check_curve_parameter(v, color_curve, STP_PARAMETER_ACTIVE))
2377    {
2378      adjustment = stp_curve_create_from_string(color_adj);
2379      stp_set_curve_parameter(v, color_curve, adjustment);
2380      stp_set_curve_parameter_active(v, color_curve, STP_PARAMETER_ACTIVE);
2381      stp_curve_destroy(adjustment);
2382    }
2383}
2384
2385static void
2386dyesub_exec(stp_vars_t *v,
2387		void (*func)(stp_vars_t *),
2388		const char *debug_string)
2389{
2390  if (func)
2391    {
2392      stp_deprintf(STP_DBG_DYESUB, "dyesub: %s\n", debug_string);
2393      (*func)(v);
2394    }
2395}
2396
2397static int
2398dyesub_interpolate(int oldval, int oldsize, int newsize)
2399{
2400  /*
2401   * This is simple linear interpolation algorithm.
2402   * When imagesize <> printsize I need rescale image somehow... :-/
2403   */
2404  return (int)(oldval * newsize / oldsize);
2405}
2406
2407static void
2408dyesub_free_image(dyesub_print_vars_t *pv, stp_image_t *image)
2409{
2410  unsigned short** image_data = pv->image_data;
2411  int image_px_height = pv->image_rows;
2412  int i;
2413
2414  for (i = 0; i< image_px_height; i++)
2415    if (image_data[i])
2416      stp_free(image_data[i]);
2417  if (image_data)
2418    stp_free(image_data);
2419}
2420
2421static unsigned short **
2422dyesub_read_image(stp_vars_t *v,
2423		dyesub_print_vars_t *pv,
2424		stp_image_t *image)
2425{
2426  int image_px_width  = stp_image_width(image);
2427  int image_px_height = stp_image_height(image);
2428  int row_size = image_px_width * pv->ink_channels * pv->bytes_per_out_channel;
2429  unsigned short **image_data;
2430  unsigned int zero_mask;
2431  int i;
2432
2433  image_data = stp_zalloc(image_px_height * sizeof(unsigned short *));
2434  pv->image_rows = 0;
2435  if (!image_data)
2436    return NULL;	/* ? out of memory ? */
2437
2438  for (i = 0; i < image_px_height; i++)
2439    {
2440      if (stp_color_get_row(v, image, i, &zero_mask))
2441        {
2442	  stp_deprintf(STP_DBG_DYESUB,
2443	  	"dyesub_read_image: "
2444		"stp_color_get_row(..., %d, ...) == 0\n", i);
2445	  dyesub_free_image(pv, image);
2446	  return NULL;
2447	}
2448      image_data[i] = stp_malloc(row_size);
2449      pv->image_rows = i+1;
2450      if (!image_data[i])
2451        {
2452	  stp_deprintf(STP_DBG_DYESUB,
2453	  	"dyesub_read_image: "
2454		"(image_data[%d] = stp_malloc()) == NULL\n", i);
2455	  dyesub_free_image(pv, image);
2456	  return NULL;
2457	}
2458      memcpy(image_data[i], stp_channel_get_output(v), row_size);
2459    }
2460  return image_data;
2461}
2462
2463static int
2464dyesub_print_pixel(stp_vars_t *v,
2465		dyesub_print_vars_t *pv,
2466		int row,
2467		int col,
2468		int plane)
2469{
2470  unsigned short ink[MAX_INK_CHANNELS * MAX_BYTES_PER_CHANNEL], *out;
2471  unsigned char *ink_u8;
2472  int i, j, b;
2473
2474  if (pv->print_mode == DYESUB_LANDSCAPE)
2475    { /* "rotate" image */
2476      dyesub_swap_ints(&col, &row);
2477      row = (pv->imgw_px - 1) - row;
2478    }
2479
2480  out = &(pv->image_data[row][col * pv->out_channels]);
2481
2482  for (i = 0; i < pv->ink_channels; i++)
2483    {
2484      if (pv->out_channels == pv->ink_channels)
2485        { /* copy out_channel (image) to equiv ink_channel (printer) */
2486          ink[i] = out[i];
2487        }
2488      else if (pv->out_channels < pv->ink_channels)
2489        { /* several ink_channels (printer) "share" same out_channel (image) */
2490          ink[i] = out[i * pv->out_channels / pv->ink_channels];
2491        }
2492      else /* (pv->out_channels > pv->ink_channels) */
2493        { /* merge several out_channels (image) into ink_channel (printer) */
2494          int avg = 0;
2495          for (j = 0; j < pv->out_channels / pv->ink_channels; j++)
2496            avg += out[j + i * pv->out_channels / pv->ink_channels];
2497	  ink[i] = avg * pv->ink_channels / pv->out_channels;
2498	}
2499    }
2500
2501  if (pv->bytes_per_ink_channel == 1) /* convert 16bits to 8bit */
2502    {
2503      ink_u8 = (unsigned char *) ink;
2504      for (i = 0; i < pv->ink_channels; i++)
2505        ink_u8[i] = ink[i] / 257;
2506    }
2507
2508  if (pv->plane_interlacing)
2509    stp_zfwrite((char *) ink + plane, pv->bytes_per_ink_channel, 1, v);
2510  else
2511/*  stp_zfwrite((char *) ink, pv->bytes_per_ink_channel, pv->ink_channels, v);*/
2512      /* print inks in right order, eg. RGB  BGR */
2513      for (b = 0; b < pv->ink_channels; b++)
2514	stp_zfwrite((char *) ink + (pv->ink_order[b]-1), pv->bytes_per_ink_channel, 1, v);
2515
2516  return 1;
2517}
2518
2519static int
2520dyesub_print_row(stp_vars_t *v,
2521		dyesub_print_vars_t *pv,
2522		int row,
2523		int plane)
2524{
2525  int ret = 0;
2526  int w, col;
2527
2528  for (w = 0; w < pv->outw_px; w++)
2529    {
2530      col = dyesub_interpolate(w, pv->outw_px, pv->imgw_px);
2531      if (pv->plane_lefttoright)
2532	ret = dyesub_print_pixel(v, pv, row, pv->imgw_px - col - 1, plane);
2533      else
2534	ret = dyesub_print_pixel(v, pv, row, col, plane);
2535      if (ret > 1)
2536      	break;
2537    }
2538  return ret;
2539}
2540
2541static int
2542dyesub_print_plane(stp_vars_t *v,
2543		dyesub_print_vars_t *pv,
2544		const dyesub_cap_t *caps,
2545		int plane)
2546{
2547  int ret = 0;
2548  int h, row;
2549  int out_bytes = (pv->plane_interlacing ? 1 : pv->ink_channels)
2550  					* pv->bytes_per_ink_channel;
2551
2552
2553  for (h = 0; h <= pv->prnb_px - pv->prnt_px; h++)
2554    {
2555      if (h % caps->block_size == 0)
2556        { /* block init */
2557	  privdata.block_min_h = h + pv->prnt_px;
2558	  privdata.block_min_w = pv->prnl_px;
2559	  privdata.block_max_h = MIN(h + pv->prnt_px + caps->block_size - 1,
2560	  					pv->prnb_px);
2561	  privdata.block_max_w = pv->prnr_px;
2562
2563	  dyesub_exec(v, caps->block_init_func, "caps->block_init");
2564	}
2565
2566      if (h + pv->prnt_px < pv->outt_px || h + pv->prnt_px >= pv->outb_px)
2567        { /* empty part above or below image area */
2568          dyesub_nputc(v, pv->empty_byte, out_bytes * pv->prnw_px);
2569	}
2570      else
2571        {
2572	  if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH)
2573	  	&& pv->outl_px > 0)
2574	    { /* empty part left of image area */
2575              dyesub_nputc(v, pv->empty_byte, out_bytes * pv->outl_px);
2576	    }
2577
2578	  row = dyesub_interpolate(h + pv->prnt_px - pv->outt_px,
2579	  					pv->outh_px, pv->imgh_px);
2580	  stp_deprintf(STP_DBG_DYESUB,
2581	  	"dyesub_print_plane: h = %d, row = %d\n", h, row);
2582	  ret = dyesub_print_row(v, pv, row, plane);
2583
2584	  if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH)
2585	  	&& pv->outr_px < pv->prnw_px)
2586	    { /* empty part right of image area */
2587              dyesub_nputc(v, pv->empty_byte, out_bytes
2588	      				* (pv->prnw_px - pv->outr_px));
2589	    }
2590	}
2591
2592      if (h + pv->prnt_px == privdata.block_max_h)
2593        { /* block end */
2594	  dyesub_exec(v, caps->block_end_func, "caps->block_end");
2595	}
2596    }
2597  return ret;
2598}
2599
2600/*
2601 * dyesub_print()
2602 */
2603static int
2604dyesub_do_print(stp_vars_t *v, stp_image_t *image)
2605{
2606  int i;
2607  dyesub_print_vars_t pv;
2608  int status = 1;
2609
2610  const int model           = stp_get_model_id(v);
2611  const char *ink_type;
2612  const dyesub_cap_t *caps = dyesub_get_model_capabilities(model);
2613  int max_print_px_width = 0;
2614  int max_print_px_height = 0;
2615  int w_dpi, h_dpi;	/* Resolution */
2616
2617  /* output in 1/72" */
2618  int out_pt_width  = stp_get_width(v);
2619  int out_pt_height = stp_get_height(v);
2620  int out_pt_left   = stp_get_left(v);
2621  int out_pt_top    = stp_get_top(v);
2622
2623  /* page in 1/72" */
2624  int page_pt_width  = stp_get_page_width(v);
2625  int page_pt_height = stp_get_page_height(v);
2626  int page_pt_left = 0;
2627  int page_pt_right = 0;
2628  int page_pt_top = 0;
2629  int page_pt_bottom = 0;
2630  int page_mode;
2631
2632  int pl;
2633
2634
2635
2636  if (!stp_verify(v))
2637    {
2638      stp_eprintf(v, _("Print options not verified; cannot print.\n"));
2639      return 0;
2640    }
2641  (void) memset(&pv, 0, sizeof(pv));
2642
2643  stp_image_init(image);
2644  pv.imgw_px = stp_image_width(image);
2645  pv.imgh_px = stp_image_height(image);
2646
2647  stp_describe_resolution(v, &w_dpi, &h_dpi);
2648  dyesub_printsize(v, &max_print_px_width, &max_print_px_height);
2649
2650  privdata.pagesize = stp_get_string_parameter(v, "PageSize");
2651  if (caps->laminate)
2652	  privdata.laminate = dyesub_get_laminate_pattern(v);
2653
2654  dyesub_imageable_area_internal(v,
2655  	(dyesub_feature(caps, DYESUB_FEATURE_WHITE_BORDER) ? 1 : 0),
2656	&page_pt_left, &page_pt_right, &page_pt_bottom, &page_pt_top,
2657	&page_mode);
2658
2659  pv.prnw_px = MIN(max_print_px_width,
2660		  	PX(page_pt_right - page_pt_left, w_dpi));
2661  pv.prnh_px = MIN(max_print_px_height,
2662			PX(page_pt_bottom - page_pt_top, h_dpi));
2663  pv.outw_px = PX(out_pt_width, w_dpi);
2664  pv.outh_px = PX(out_pt_height, h_dpi);
2665
2666
2667  /* if image size is close enough to output size send out original size */
2668  if (abs(pv.outw_px - pv.imgw_px) < SIZE_THRESHOLD)
2669      pv.outw_px  = pv.imgw_px;
2670  if (abs(pv.outh_px - pv.imgh_px) < SIZE_THRESHOLD)
2671      pv.outh_px = pv.imgh_px;
2672
2673  pv.outw_px = MIN(pv.outw_px, pv.prnw_px);
2674  pv.outh_px = MIN(pv.outh_px, pv.prnh_px);
2675  pv.outl_px = MIN(PX(out_pt_left - page_pt_left, w_dpi),
2676			pv.prnw_px - pv.outw_px);
2677  pv.outt_px = MIN(PX(out_pt_top  - page_pt_top, h_dpi),
2678			pv.prnh_px - pv.outh_px);
2679  pv.outr_px = pv.outl_px + pv.outw_px;
2680  pv.outb_px = pv.outt_px  + pv.outh_px;
2681
2682
2683  stp_deprintf(STP_DBG_DYESUB,
2684	      "paper (pt)   %d x %d\n"
2685	      "image (px)   %d x %d\n"
2686	      "image (pt)   %d x %d\n"
2687	      "* out (pt)   %d x %d\n"
2688	      "* out (px)   %d x %d\n"
2689	      "* left x top (pt) %d x %d\n"
2690	      "* left x top (px) %d x %d\n"
2691	      "border (pt) (%d - %d) = %d x (%d - %d) = %d\n"
2692	      "printable pixels (px)   %d x %d\n"
2693	      "res (dpi)               %d x %d\n",
2694	      page_pt_width, page_pt_height,
2695	      pv.imgw_px, pv.imgh_px,
2696	      PT(pv.imgw_px, w_dpi), PT(pv.imgh_px, h_dpi),
2697	      out_pt_width, out_pt_height,
2698	      pv.outw_px, pv.outh_px,
2699	      out_pt_left, out_pt_top,
2700	      pv.outl_px, pv.outt_px,
2701	      page_pt_right, page_pt_left, page_pt_right - page_pt_left,
2702	      page_pt_bottom, page_pt_top, page_pt_bottom - page_pt_top,
2703	      pv.prnw_px, pv.prnh_px,
2704	      w_dpi, h_dpi
2705	      );
2706
2707
2708  /* FIXME: move this into print_init_drv */
2709  ink_type = dyesub_describe_output_internal(v, &pv);
2710  stp_set_string_parameter(v, "STPIOutputType", ink_type);
2711  stp_channel_reset(v);
2712  for (i = 0; i < pv.ink_channels; i++)
2713    stp_channel_add(v, i, 0, 1.0);
2714  pv.out_channels = stp_color_init(v, image, 65536);
2715  pv.bytes_per_ink_channel = 1;		/* FIXME: this is printer dependent */
2716  pv.bytes_per_out_channel = 2;		/* FIXME: this is ??? */
2717  pv.image_data = dyesub_read_image(v, &pv, image);
2718  pv.empty_byte = (ink_type &&
2719 		(strcmp(ink_type, "RGB") == 0 || strcmp(ink_type, "BGR") == 0)
2720		? '\xff' : '\0');
2721  pv.plane_interlacing = dyesub_feature(caps, DYESUB_FEATURE_PLANE_INTERLACE);
2722  pv.plane_lefttoright = dyesub_feature(caps, DYESUB_FEATURE_PLANE_LEFTTORIGHT);
2723  pv.print_mode = page_mode;
2724  if (!pv.image_data)
2725    {
2726      stp_image_conclude(image);
2727      return 2;
2728    }
2729  /* /FIXME */
2730
2731
2732  dyesub_adjust_curve(v, caps->adj_cyan, "CyanCurve");
2733  dyesub_adjust_curve(v, caps->adj_magenta, "MagentaCurve");
2734  dyesub_adjust_curve(v, caps->adj_yellow, "YellowCurve");
2735  stp_set_float_parameter(v, "Density", 1.0);
2736
2737  if (dyesub_feature(caps, DYESUB_FEATURE_FULL_HEIGHT))
2738    {
2739      pv.prnt_px = 0;
2740      pv.prnb_px = pv.prnh_px - 1;
2741    }
2742  else if (dyesub_feature(caps, DYESUB_FEATURE_BLOCK_ALIGN))
2743    {
2744      pv.prnt_px = pv.outt_px - (pv.outt_px % caps->block_size);
2745      				/* floor to multiple of block_size */
2746      pv.prnb_px = (pv.outb_px - 1) + (caps->block_size - 1)
2747      		- ((pv.outb_px - 1) % caps->block_size);
2748				/* ceil to multiple of block_size */
2749    }
2750  else
2751    {
2752      pv.prnt_px = pv.outt_px;
2753      pv.prnb_px = pv.outb_px - 1;
2754    }
2755
2756  if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH))
2757    {
2758      pv.prnl_px = 0;
2759      pv.prnr_px = pv.prnw_px - 1;
2760    }
2761  else
2762    {
2763      pv.prnl_px = pv.outl_px;
2764      pv.prnr_px = pv.outr_px;
2765    }
2766
2767  if (pv.print_mode == DYESUB_LANDSCAPE)
2768    {
2769      dyesub_swap_ints(&pv.outh_px, &pv.outw_px);
2770      dyesub_swap_ints(&pv.outt_px, &pv.outl_px);
2771      dyesub_swap_ints(&pv.outb_px, &pv.outr_px);
2772
2773      dyesub_swap_ints(&pv.prnh_px, &pv.prnw_px);
2774      dyesub_swap_ints(&pv.prnt_px, &pv.prnl_px);
2775      dyesub_swap_ints(&pv.prnb_px, &pv.prnr_px);
2776
2777      dyesub_swap_ints(&pv.imgh_px, &pv.imgw_px);
2778    }
2779
2780	/* assign private data *after* swaping image dimensions */
2781  privdata.w_dpi = w_dpi;
2782  privdata.h_dpi = h_dpi;
2783  privdata.w_size = pv.prnw_px;
2784  privdata.h_size = pv.prnh_px;
2785  privdata.print_mode = pv.print_mode;
2786
2787  /* printer init */
2788  dyesub_exec(v, caps->printer_init_func, "caps->printer_init");
2789
2790  for (pl = 0; pl < (pv.plane_interlacing ? pv.ink_channels : 1); pl++)
2791    {
2792      privdata.plane = pv.ink_order[pl];
2793      stp_deprintf(STP_DBG_DYESUB, "dyesub: plane %d\n", privdata.plane);
2794
2795      /* plane init */
2796      dyesub_exec(v, caps->plane_init_func, "caps->plane_init");
2797
2798      dyesub_print_plane(v, &pv, caps, (int) pv.ink_order[pl] - 1);
2799
2800      /* plane end */
2801      dyesub_exec(v, caps->plane_end_func, "caps->plane_end");
2802    }
2803
2804  /* printer end */
2805  dyesub_exec(v, caps->printer_end_func, "caps->printer_end");
2806
2807  dyesub_free_image(&pv, image);
2808  stp_image_conclude(image);
2809  return status;
2810}
2811
2812static int
2813dyesub_print(const stp_vars_t *v, stp_image_t *image)
2814{
2815  int status;
2816  stp_vars_t *nv = stp_vars_create_copy(v);
2817  stp_prune_inactive_options(nv);
2818  status = dyesub_do_print(nv, image);
2819  stp_vars_destroy(nv);
2820  return status;
2821}
2822
2823static const stp_printfuncs_t print_dyesub_printfuncs =
2824{
2825  dyesub_list_parameters,
2826  dyesub_parameters,
2827  dyesub_media_size,
2828  dyesub_imageable_area,
2829  dyesub_maximum_imageable_area,
2830  dyesub_limit,
2831  dyesub_print,
2832  dyesub_describe_resolution,
2833  dyesub_describe_output,
2834  stp_verify_printer_params,
2835  NULL,
2836  NULL,
2837  NULL
2838};
2839
2840
2841
2842
2843static stp_family_t print_dyesub_module_data =
2844  {
2845    &print_dyesub_printfuncs,
2846    NULL
2847  };
2848
2849
2850static int
2851print_dyesub_module_init(void)
2852{
2853  return stp_family_register(print_dyesub_module_data.printer_list);
2854}
2855
2856
2857static int
2858print_dyesub_module_exit(void)
2859{
2860  return stp_family_unregister(print_dyesub_module_data.printer_list);
2861}
2862
2863
2864/* Module header */
2865#define stp_module_version print_dyesub_LTX_stp_module_version
2866#define stp_module_data print_dyesub_LTX_stp_module_data
2867
2868stp_module_version_t stp_module_version = {0, 0};
2869
2870stp_module_t stp_module_data =
2871  {
2872    "dyesub",
2873    VERSION,
2874    "DyeSub family driver",
2875    STP_MODULE_CLASS_FAMILY,
2876    NULL,
2877    print_dyesub_module_init,
2878    print_dyesub_module_exit,
2879    (void *) &print_dyesub_module_data
2880  };
2881
2882