1/*
2 * "$Id: escp2-channels.c,v 1.91 2010/12/19 02:51:37 rlk Exp $"
3 *
4 *   Print plug-in EPSON ESC/P2 driver for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU General Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27#include <gutenprint/gutenprint.h>
28#include "gutenprint-internal.h"
29#include <gutenprint/gutenprint-intl-internal.h>
30#include "print-escp2.h"
31
32static inkgroup_t *default_black_inkgroup;
33
34static void
35load_subchannel(stp_mxml_node_t *node, stp_mxml_node_t *root, physical_subchannel_t *icl)
36{
37  const char *name;
38  stp_mxml_node_t *child = node->child;
39  name = stp_mxmlElementGetAttr(node, "color");
40  if (name)
41    icl->color = stp_xmlstrtol(name);
42  name = stp_mxmlElementGetAttr(node, "subchannel");
43  if (name)
44    icl->subchannel = stp_xmlstrtol(name);
45  else
46    icl->subchannel = -1;
47  name = stp_mxmlElementGetAttr(node, "headOffset");
48  if (name)
49    icl->head_offset = stp_xmlstrtol(name);
50  name = stp_mxmlElementGetAttr(node, "name");
51  if (name)
52    icl->name = stp_strdup(name);
53  name = stp_mxmlElementGetAttr(node, "text");
54  if (name)
55    icl->text = stp_strdup(name);
56  while (child)
57    {
58      if (child->type == STP_MXML_ELEMENT)
59	{
60	  const char *param = child->value.element.name;
61	  name = stp_mxmlElementGetAttr(child, "name");
62	  if (name && !strcmp(param, "ChannelDensityParam"))
63	    icl->channel_density = stp_strdup(name);
64	  else if (name && !strcmp(param, "SubchannelTransitionParam"))
65	    icl->subchannel_transition = stp_strdup(name);
66	  else if (name && !strcmp(param, "SubchannelValueParam"))
67	    icl->subchannel_value = stp_strdup(name);
68	  else if (name && !strcmp(param, "SubchannelScaleParam"))
69	    icl->subchannel_scale = stp_strdup(name);
70	  else if (!strcmp(param, "SplitChannels"))
71	    {
72	      if (stp_mxmlElementGetAttr(child, "count"))
73		icl->split_channel_count =
74		  stp_xmlstrtoul(stp_mxmlElementGetAttr(child, "count"));
75	      if (icl->split_channel_count > 0)
76		{
77		  char *endptr;
78		  int count = 0;
79		  stp_mxml_node_t *cchild = child->child;
80		  icl->split_channels =
81		    stp_zalloc(sizeof(short) * icl->split_channel_count);
82		  while (cchild && count < icl->split_channel_count)
83		    {
84		      if (cchild->type == STP_MXML_TEXT)
85			{
86			  unsigned val =
87			    strtoul(cchild->value.text.string, &endptr, 0);
88			  if (endptr)
89			    icl->split_channels[count++] = val;
90			}
91		      cchild = cchild->next;
92		    }
93		}
94	    }
95	}
96      child = child->next;
97    }
98}
99
100static void
101load_channel(stp_mxml_node_t *node, stp_mxml_node_t *root, ink_channel_t *icl)
102{
103  const char *name;
104  stp_mxml_node_t *child = node->child;
105  int count = 0;
106  while (child)
107    {
108      if (child->type == STP_MXML_ELEMENT &&
109	  !strcmp(child->value.element.name, "subchannel"))
110	count++;
111      child = child->next;
112    }
113  name = stp_mxmlElementGetAttr(node, "name");
114  if (name)
115    icl->name = stp_strdup(name);
116  icl->n_subchannels = count;
117  icl->subchannels = stp_zalloc(sizeof(physical_subchannel_t) * count);
118  count = 0;
119  child = node->child;
120  while (child)
121    {
122      if (child->type == STP_MXML_ELEMENT)
123	{
124	  if (!strcmp(child->value.element.name, "subchannel"))
125	    load_subchannel(child, root, &(icl->subchannels[count++]));
126	  else if (!strcmp(child->value.element.name, "HueCurve"))
127	    {
128	      stp_mxml_node_t *cchild = child->child;
129	      stp_curve_t *curve;
130	      const char *cref = stp_mxmlElementGetAttr(child, "ref");
131	      if (cref)
132		{
133		  cchild = stp_mxmlFindElement(root, root, "curve", "name",
134					       cref, STP_MXML_DESCEND);
135		  STPI_ASSERT(cchild, NULL);
136		}
137	      else
138		{
139		  while (cchild && cchild->type != STP_MXML_ELEMENT)
140		    cchild = cchild->next;
141		  STPI_ASSERT(cchild, NULL);
142		}
143	      curve = stp_curve_create_from_xmltree(cchild);
144	      icl->hue_curve = curve;
145	    }
146	  else if (!strcmp(child->value.element.name, "HueCurveParam"))
147	    {
148	      name = stp_mxmlElementGetAttr(child, "name");
149	      if (name)
150		icl->hue_curve_name = stp_strdup(name);
151	    }
152	}
153      child = child->next;
154    }
155}
156
157static void
158load_inkname(stp_mxml_node_t *node, stp_mxml_node_t *root, inkname_t *inl,
159	     inklist_t *ikl)
160{
161  const char *name;
162  stp_mxml_node_t *child = node->child;
163  int channel_count = 0;
164  int aux_channel_count = 0;
165
166  while (child)
167    {
168      if (child->type == STP_MXML_ELEMENT)
169	{
170	  if (!strcmp(child->value.element.name, "Channels"))
171	    {
172	      stp_mxml_node_t *cchild = child->child;
173	      while (cchild)
174		{
175		  if (cchild->type == STP_MXML_ELEMENT &&
176		      !strcmp(cchild->value.element.name, "channel"))
177		    {
178		      name = stp_mxmlElementGetAttr(cchild, "index");
179		      if (name)
180			{
181			  unsigned idx = stp_xmlstrtoul(name);
182			  if (idx + 1 > channel_count)
183			    channel_count = idx + 1;
184			}
185		    }
186		  cchild = cchild->next;
187		}
188	    }
189	  else if (!strcmp(child->value.element.name, "AuxChannels"))
190	    {
191	      stp_mxml_node_t *cchild = child->child;
192	      while (cchild)
193		{
194		  if (cchild->type == STP_MXML_ELEMENT &&
195		      !strcmp(cchild->value.element.name, "channel"))
196		    {
197		      name = stp_mxmlElementGetAttr(cchild, "index");
198		      if (name)
199			{
200			  unsigned idx = stp_xmlstrtoul(name);
201			  if (idx + 1 > aux_channel_count)
202			    aux_channel_count = idx + 1;
203			}
204		    }
205		  cchild = cchild->next;
206		}
207	    }
208	}
209      child = child->next;
210    }
211  inl->channel_count = channel_count;
212  if (channel_count > 0)
213    inl->channels = stp_zalloc(sizeof(ink_channel_t) * channel_count);
214  inl->aux_channel_count = aux_channel_count;
215  if (aux_channel_count > 0)
216    inl->aux_channels = stp_zalloc(sizeof(ink_channel_t) * aux_channel_count);
217  name = stp_mxmlElementGetAttr(node, "name");
218  if (name)
219    inl->name = stp_strdup(name);
220  name = stp_mxmlElementGetAttr(node, "text");
221  if (name)
222    inl->text = stp_strdup(name);
223  name = stp_mxmlElementGetAttr(node, "InkID");
224  if (name)
225    {
226      if (!strcmp(name, "CMYK"))
227	inl->inkset = INKSET_CMYK;
228      else if (!strcmp(name, "CcMmYK"))
229	inl->inkset = INKSET_CcMmYK;
230      else if (!strcmp(name, "CcMmYyK"))
231	inl->inkset = INKSET_CcMmYyK;
232      else if (!strcmp(name, "CcMmYKk"))
233	inl->inkset = INKSET_CcMmYKk;
234      else if (!strcmp(name, "Quadtone"))
235	inl->inkset = INKSET_QUADTONE;
236      else if (!strcmp(name, "Hextone"))
237	inl->inkset = INKSET_HEXTONE;
238      else if (!strcmp(name, "OTHER"))
239	inl->inkset = INKSET_OTHER;
240      else if (!strcmp(name, "Extended"))
241	inl->inkset = INKSET_EXTENDED;
242    }
243
244  channel_count = 0;
245  aux_channel_count = 0;
246  child = node->child;
247  while (child)
248    {
249      if (child->type == STP_MXML_ELEMENT)
250	{
251	  if (!strcmp(child->value.element.name, "Channels"))
252	    {
253	      stp_mxml_node_t *cchild = child->child;
254	      while (cchild)
255		{
256		  if (cchild->type == STP_MXML_ELEMENT &&
257		      !strcmp(cchild->value.element.name, "channel"))
258		    {
259		      name = stp_mxmlElementGetAttr(cchild, "index");
260		      if (name)
261			{
262			  unsigned idx = stp_xmlstrtoul(name);
263			  load_channel(cchild, root, &(inl->channels[idx]));
264			}
265		    }
266		  cchild = cchild->next;
267		}
268	    }
269	  else if (!strcmp(child->value.element.name, "AuxChannels"))
270	    {
271	      stp_mxml_node_t *cchild = child->child;
272	      while (cchild)
273		{
274		  if (cchild->type == STP_MXML_ELEMENT &&
275		      !strcmp(cchild->value.element.name, "channel"))
276		    {
277		      name = stp_mxmlElementGetAttr(cchild, "index");
278		      if (name)
279			{
280			  unsigned idx = stp_xmlstrtoul(name);
281			  load_channel(cchild, root, &(inl->aux_channels[idx]));
282			}
283		    }
284		  cchild = cchild->next;
285		}
286	    }
287	  else if (!strcmp(child->value.element.name, "initSequence") &&
288		   child->child && child->child->type == STP_MXML_TEXT)
289	    ikl->init_sequence = stp_xmlstrtoraw(child->child->value.text.string);
290	  else if (!strcmp(child->value.element.name, "deinitSequence") &&
291		   child->child && child->child->type == STP_MXML_TEXT)
292	    ikl->deinit_sequence = stp_xmlstrtoraw(child->child->value.text.string);
293	}
294      child = child->next;
295    }
296}
297
298static void
299load_shades(stp_mxml_node_t *node, stp_mxml_node_t *root, inklist_t *ikl)
300{
301  stp_mxml_node_t *child = node->child;
302  int count = 0;
303
304  while (child)
305    {
306      if (child->type == STP_MXML_ELEMENT &&
307	  !strcmp(child->value.element.name, "shade"))
308	count++;
309      child = child->next;
310    }
311  ikl->n_shades = count;
312  ikl->shades = stp_zalloc(sizeof(shade_t) * count);
313  count = 0;
314  child = node->child;
315  while (child)
316    {
317      if (child->type == STP_MXML_ELEMENT &&
318	  !strcmp(child->value.element.name, "shade"))
319	{
320	  if (stp_mxmlElementGetAttr(child, "count"))
321	    {
322	      unsigned nshades =
323		stp_xmlstrtoul(stp_mxmlElementGetAttr(child, "count"));
324	      ikl->shades[count].n_shades = nshades;
325	      if (nshades > 0)
326		{
327		  char *endptr;
328		  stp_mxml_node_t *cchild = child->child;
329		  ikl->shades[count].shades = stp_zalloc(sizeof(double) * nshades);
330		  nshades = 0;
331		  while (cchild && nshades < ikl->shades[count].n_shades)
332		    {
333		      if (cchild->type == STP_MXML_TEXT)
334			{
335			  double val =
336			    strtod(cchild->value.text.string, &endptr);
337			  if (endptr)
338			    ikl->shades[count].shades[nshades++] = val;
339			}
340		      cchild = cchild->next;
341		    }
342		}
343	    }
344	  count++;
345	}
346      child = child->next;
347    }
348}
349
350static void
351load_inklist(stp_mxml_node_t *node, stp_mxml_node_t *root, inklist_t *ikl)
352{
353  const char *name;
354  stp_mxml_node_t *child = node->child;
355  int count = 0;
356
357  while (child)
358    {
359      if (child->type == STP_MXML_ELEMENT)
360	{
361	  if (!strcmp(child->value.element.name, "InkName"))
362	    count++;
363	  else if (!strcmp(child->value.element.name, "initSequence") &&
364		   child->child && child->child->type == STP_MXML_TEXT)
365	    ikl->init_sequence = stp_xmlstrtoraw(child->child->value.text.string);
366	  else if (!strcmp(child->value.element.name, "deinitSequence") &&
367		   child->child && child->child->type == STP_MXML_TEXT)
368	    ikl->deinit_sequence = stp_xmlstrtoraw(child->child->value.text.string);
369	}
370      child = child->next;
371    }
372  name = stp_mxmlElementGetAttr(node, "name");
373  if (name)
374    ikl->name = stp_strdup(name);
375  name = stp_mxmlElementGetAttr(node, "text");
376  if (name)
377    ikl->text = stp_strdup(name);
378  ikl->n_inks = count;
379  ikl->inknames = stp_zalloc(sizeof(inkname_t) * count);
380  count = 0;
381  child = node->child;
382  while (child)
383    {
384      if (child->type == STP_MXML_ELEMENT)
385	{
386	  if (!strcmp(child->value.element.name, "InkName"))
387	    {
388	      inkname_t *inl = &(ikl->inknames[count++]);
389	      inl->init_sequence = ikl->init_sequence;
390	      inl->deinit_sequence = ikl->deinit_sequence;
391	      load_inkname(child, root, inl, ikl);
392	    }
393	  else if (!strcmp(child->value.element.name, "Shades"))
394	    load_shades(child, root, ikl);
395	}
396      child = child->next;
397    }
398}
399
400static inkgroup_t *
401load_inkgroup(const char *name)
402{
403  stp_list_t *dirlist = stpi_data_path();
404  stp_list_item_t *item;
405  inkgroup_t *igl = NULL;
406  item = stp_list_get_start(dirlist);
407  while (item)
408    {
409      const char *dn = (const char *) stp_list_item_get_data(item);
410      char *ffn = stpi_path_merge(dn, name);
411      stp_mxml_node_t *inkgroup =
412	stp_mxmlLoadFromFile(NULL, ffn, STP_MXML_NO_CALLBACK);
413      stp_free(ffn);
414      if (inkgroup)
415	{
416	  int count = 0;
417	  stp_mxml_node_t *node = stp_mxmlFindElement(inkgroup, inkgroup,
418						      "escp2:InkGroup", NULL,
419						      NULL, STP_MXML_DESCEND);
420	  if (node)
421	    {
422	      stp_mxml_node_t *child = node->child;
423	      igl = stp_zalloc(sizeof(inkgroup_t));
424	      while (child)
425		{
426		  if (child->type == STP_MXML_ELEMENT &&
427		      !strcmp(child->value.element.name, "InkList"))
428		    count++;
429		  child = child->next;
430		}
431	      igl->n_inklists = count;
432	      if (stp_mxmlElementGetAttr(node, "name"))
433		igl->name = stp_strdup(stp_mxmlElementGetAttr(node, "name"));
434	      else
435		igl->name = stp_strdup(name);
436	      igl->inklists = stp_zalloc(sizeof(inklist_t) * count);
437	      child = node->child;
438	      count = 0;
439	      while (child)
440		{
441		  if (child->type == STP_MXML_ELEMENT &&
442		      !strcmp(child->value.element.name, "InkList"))
443		    load_inklist(child, node, &(igl->inklists[count++]));
444		  child = child->next;
445		}
446	    }
447	  stp_mxmlDelete(inkgroup);
448	  break;
449	}
450      item = stp_list_item_next(item);
451    }
452  stp_list_destroy(dirlist);
453  return igl;
454}
455
456int
457stp_escp2_load_inkgroup(const stp_vars_t *v, const char *name)
458{
459  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
460  inkgroup_t *igl = load_inkgroup(name);
461  STPI_ASSERT(igl, v);
462  printdef->inkgroup = igl;
463  return (igl != NULL);
464}
465
466const inkname_t *
467stpi_escp2_get_default_black_inkset(void)
468{
469  if (! default_black_inkgroup)
470    {
471      default_black_inkgroup = load_inkgroup("escp2/inks/defaultblack.xml");
472      STPI_ASSERT(default_black_inkgroup &&
473		  default_black_inkgroup->n_inklists >= 1 &&
474		  default_black_inkgroup->inklists[0].n_inks >= 1, NULL);
475    }
476  return &(default_black_inkgroup->inklists[0].inknames[0]);
477}
478