/*
Copyright (c) 2004-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/



/**	@file dkfigpdf.c	PDF output driver module.
*/



/**	Inside the dkfigpdf module.
*/
#define DKFIGPDF_C 1



#include "dkfig.h"




#line 55 "dkfigpdf.ctr"




/**	Flag: Stroke color known.
*/
#define HAVE_STROKE_COLOR	1

/**	Flag: Fill color (non-stroke) color known.
*/
#define HAVE_NON_STROKE_COLOR	2

/**	Flag: Dash style known.
*/
#define HAVE_DASH		4

/**	Flag: Line width known.
*/
#define HAVE_LINEWIDTH		8

/**	Flag: Linecap known.
*/
#define HAVE_LINECAP		16

/**	Flag: Linejoin known.
*/
#define HAVE_LINEJOIN		32



/**	String pointer.
*/
typedef char *PCHAR;



/**	Output keywords used by this module.
*/
static char *kw[] = {
  /*   0 */ "\r\n",
  /*   1 */ " ",
  /*   2 */ "%PDF-1.4",
  /*   3 */ " 0 obj",
  /*   4 */ "endobj",
  /*   5 */ "<<",
  /*   6 */ ">>",
  /*   7 */ "xref",
  /*   8 */ "f",
  /*   9 */ "n",
  /*  10 */ "trailer",
  /*  11 */ "/Size",
  /*  12 */ "/Root",
  /*  13 */ "R",
  /*  14 */ "/Info",
  /*  15 */ "startxref",
  /*  16 */ "%%EOF",
  /*  17 */ "0000000000 65535 f",
  /*  18 */ " 00000 n",
  /*  19 */ "0",
  /*  20 */ "/Producer (fig2vect, see http://dktools.sourceforge.net/fig2vect.html)",
  /*  21 */ "/Type /Catalog /Pages 3 0 R",
  /*  22 */ "/Type /Pages /Kids [4 0 R] /Count 1",
  /*  23 */ "/Type /Page",
  /*  24 */ "/MediaBox [",
  /*  25 */ "]",
  /*  26 */ "/Rotate 0",
  /*  27 */ "/Parent 3 0 R",
  /*  28 */ "/Resources",
  /*  29 */ "/ProcSet [",
  /*  30 */ "/PDF",
  /*  31 */ "/ImageC",
  /*  32 */ "/ImageG",
  /*  33 */ "/XObject",
  /*  34 */ "/Pattern",
  /*  35 */ "/",
  /*  36 */ "/Contents 5 0 R",
  /*  37 */ "q",
  /*  38 */ "Q",
  /*  39 */ "/Length",
  /*  40 */ "/Filter [/ASCII85Decode /FlateDecode]",
  /*  41 */ "stream",
  /*  42 */ "endstream",
  /*  43 */ " /PageMode /FullScreen",
  /*  44 */ "/Font",
  /*  45 */ "Obj",
  /*  46 */"/Type /Font /Subtype /Type1 /Encoding /WinAnsiEncoding /BaseFont /",
  /*  47 */ "BT",
  /*  48 */ "ET",
  /*  49 */ "Tf",
  /*  50 */ "Td",
  /*  51 */ "Tj",
  /*  52 */ "(",
  /*  53 */ ")",
  /*  54 */ "/Text",
  /*  55 */ "cm",
  /*  56 */ "1",
  /*  57 */ "-",
  /*  58 */ "/ImageB",
  /*  59 */ "/ImageC",
  /*  60 */ "rg",
  /*  61 */ "RG",
  /*  62 */ "/Type /Pattern /PatternType 1 /PaintType 1 /TilingType 1",
  /*  63 */ "/BBox [0 0 ",
  /*  64 */ "/XStep",
  /*  65 */ "/YStep",
  /*  66 */ "m",		/* moveto */
  /*  67 */ "l",		/* lineto */
  /*  68 */ "h",		/* closepath */
  /*  69 */ "f",		/* fill (nonzero) */
  /*  70 */ "S",		/* stroke */
  /*  71 */ "w",		/* setlinewidth */
  /*  72 */ "/Pattern cs ",
  /*  73 */ "scn",		/* set color non-stroking */
  /*  74 */ "d",		/* setdash */
  /*  75 */ "[",
  /*  76 */ "J",		/* setlinecap */
  /*  77 */ "j",		/* setlinejoin */
  /*  78 */ "h B",		/* close, fill (nonzero), stroke */
  /*  79 */ "h B*",		/* close, fill (eo), stroke */
  /*  80 */ "h f",		/* close, fill (nonzero) */
  /*  81 */ "h f*",		/* close, fill (eo) */
  /*  82 */ "s",		/* close, stroke */
  /*  83 */ "c",		/* bezierto */
  /*  84 */ "% text ",
  /*  85 */ "% polyline ",
  /*  86 */ "% ellipse ",
  /*  87 */ "% spline ",
  /*  88 */ "% arc ",
  /*  89 */ "pdf",
  /*  90 */ "/Subtype /Image",
  /*  91 */ "/ColorSpace",
  /*  92 */ "/DeviceRGB",
  /*  93 */ "/DeviceGray",
  /*  94 */ "/BitsPerComponent 8",
  /*  95 */ "/Width",
  /*  96 */ "/Height",
  /*  97 */ "/Interpolate true",
  /*  98 */ "/SMask",
  /*  99 */ "0 R",
  /* 100 */ "/Type /XObject",
  /* 101 */ "Do",
  /* 102 */ "/CropBox [",
  /* 103 */ "h W n",
  /* 104 */ "/Group << /S /Transparency /I true /CS /DeviceRGB >>",
  /* 105 */ "g",
  /* 106 */ "G",
};

/**	Number of keywords in the kw array.
*/
static size_t nkw = sizeof(kw)/sizeof(PCHAR);



/**	Names of the standard PDF fonts.
*/
static char *pdf_font_names[] = {
  "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
  "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
  "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
  "Symbol", "ZapfDingbats",
  NULL
};



/**	Open mode: Read file binary.
*/
static char str_open_read_binary[] = { "rb" };

/**	Open mode: Write file binary.
*/
static char str_open_write_binary[] = { "wb" };





/**	A struct to support arc / circle interpolations using
	  Bezier splines.

	x(phi) = rx * cos(phi)
	y(phi) = ry * sin(phi)
	dx / dphi = - rx * sin (phi)
	dy / dphi =   ry * cos (phi)
*/
typedef struct {
  double xm;		/**< Center x. */
  double ym;		/**< Center y. */
  double rx;		/**< Radius x. */
  double ry;		/**< Radius y. */
  double phi0;		/**< Arc start. */
  double phi1;		/**< Arc end. */
  unsigned segs;	/**< Number of bezier segments. */
  double x0;		/**< Start point x. */
  double y0;		/**< Start point y. */
  double x1;		/**< End point x. */
  double y1;		/**< End point y. */
} pdf_arc_calc;



/**	Abbreviation.
*/
typedef dkfig_pdf_output_instruction OI;

/**	Abbreviation.
*/
typedef dkfig_pdf_object_position OPOS;

/**	Abbreviation.
*/
typedef dkfig_pdf_pattern PAT;



/**	Restrict digits for double number.
*/
#define drd(v,o,w) dkfig_tool2_drd(v,o,w)

/**	Multiplication of double values.
*/
#define MULD(a,b,c) dkma_mul_double_ok(a,b,c)

/**	Division of double values.
*/
#define DIVD(a,b,c) dkma_div_double_ok(a,b,c)

/**	Addition of double values.
*/
#define ADDD(a,b,c) dkma_add_double_ok(a,b,c)

/**	Substraction of double values.
*/
#define SUBD(a,b,c) dkma_sub_double_ok(a,b,c)



/**	Create a new driver-specific extension data structure for text objects.
	@return	Pointer to new extension data on success, NULL on error.
*/
static
dkfig_pdf_drve_text *new_drve DK_P0()
{
  dkfig_pdf_drve_text *back = NULL;
  
  back = dk_new(dkfig_pdf_drve_text,1);
  if(back) {
    back->fn = 0;
    back->p = NULL;
    back->i = NULL;
  } 
  return back;
}



/**	Delete driver-specific extension, release memory.
	@param	p	Pointer to driver-specific extension data.
*/
static
void delete_drve DK_P1(dkfig_pdf_drve_text *,p)
{
  
  if(p) {
    p->fn = 0; p->p = NULL; p->i = NULL;
    dk_delete(p);
  } 
}



/**	Delete image extension data.
	@param	iptr	Image extension data.
*/
static
void delete_image DK_P1(dkfig_pdf_image *,iptr)
{
  char *ptr;
  
  if(iptr) {
    if(iptr->inputfilename) {
      
      ptr = iptr->inputfilename;
      dk_delete((void *)ptr);
    } iptr->inputfilename = NULL;
    if(iptr->ofn) {
      dksf_remove_file(iptr->ofn);
      ptr = iptr->ofn;
      dk_delete((void *)ptr);
    } iptr->ofn = NULL;
    if(iptr->afn) {
      dksf_remove_file(iptr->afn);
      ptr = iptr->afn;
      dk_delete((void *)ptr);
    } iptr->afn = NULL;
    iptr->w = iptr->h = 0UL; iptr->bpp = iptr->ch = 0;
    dk_delete(iptr);
  } 
}



/**	Create image extension data.
	@param	ifn	Image file name.
	@return	Pointer to new image extension data on success, NULL on error.
*/
static
dkfig_pdf_image *new_image DK_P1(char *,ifn)
{
  dkfig_pdf_image *back = NULL;
  
  if(ifn) {
    back = dk_new(dkfig_pdf_image,1);
    if(back) {
      DK_MEMRES(back,sizeof(dkfig_pdf_image));
      back->inputfilename = dkstr_dup(ifn);
      if(back->inputfilename) {
        back->flipped = 0;
        back->ofn = back->afn = NULL;
	back->w = back->h = 0UL;
	back->bpp = back->ch = 0;
	back->ol = back->al = 0UL;
      } else {
        dk_delete(back); back = NULL;
      }
    }
  } 
  return back;
}



/**	Comparison function for sorted storage (compare images).
	@param	l	Pointer to image extension.
	@param	r	Pointer to image extension.
	@param	cr	Comparison criteria (ignored).
	@return	Result of file name comparison and flip check
		(0 means the same XObject can be used for both images).
*/
static
int compare_images DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  dkfig_pdf_image *pr, *pl;
  
  if(l) {
    if(r) {
      pl = (dkfig_pdf_image *)l; pr = (dkfig_pdf_image *)r;
      if(pl->inputfilename) {
        if(pr->inputfilename) {
	  
#if DK_HAVE_FNCASEINS
          back = dkstr_casecmp(pl->inputfilename, pr->inputfilename);
#else
          back = strcmp(pl->inputfilename, pr->inputfilename);
#endif
	} else { back = 1; }
      } else {
        if(pr->inputfilename) { back = -1; }
      }
      if(!back) {
        if(pl->flipped > pr->flipped) {
	  back = 1;
	} else {
	  if(pl->flipped < pr->flipped) {
	    back = -1;
	  }
	}
      }
    } else { back = 1; }
  } else {
    if(r) { back = -1; }
  } 
  return back;
}



/**	Convert coordinates double x to PDF.
	@param	oi	Output instruction.
	@param	x	Value to convert.
	@return	Converted value.
*/
static double ccdx DK_P2(OI *,oi, double,x)
{
  double back;
  back = dkma_add_double_ok(
    dkma_mul_double_ok(oi->xfactor, x, &(oi->me)),
    oi->xadd,
    &(oi->me)
  );
  return back;
}



/**	Convert coordinates double y to PDF.
	@param	oi	Output instruction.
	@param	y	Value to convert.
	@return	Converted value.
*/
static double ccdy DK_P2(OI *,oi, double,y)
{
  double back;
  back = dkma_add_double_ok(
    dkma_mul_double_ok(oi->yfactor, y, &(oi->me)),
    oi->yadd,
    &(oi->me)
  );
  return back;
}



/**	Convert coordinates long x to PDF.
	@param	oi	Output instruction.
	@param	x	Value to convert.
	@return	Converted value.
*/
static double cclx DK_P2(OI *,oi, long,x)
{
  return(ccdx(oi, dkma_l_to_double(x)));
}



/**	Convert coordinates long y to PDF.
	@param	oi	Output instruction.
	@param	y	Value to convert.
	@return	Converted value.
*/
static double ccly DK_P2(OI *,oi, long,y)
{
  return(ccdy(oi, dkma_l_to_double(y)));
}



/**	Initialize OI.
	@param	oi	OI to initialize.
*/
static
void null_oi DK_P1(OI *,oi)
{
  DK_MEMRES(oi, sizeof(OI));
  oi->c    = NULL;
  oi->d    = NULL;
  oi->s    = NULL; oi->gcs = NULL;
  oi->pdfo = NULL; oi->pdfoi = NULL;
  oi->fl   = NULL;  oi->fli = NULL;
  oi->ec   = 0;
  oi->me   = 0;
  oi->patl = NULL; oi->patli = NULL;
  oi->imgl = NULL; oi->imgli = NULL;
  oi->co = NULL;
  oi->fu = NULL;
  oi->no   = 1UL; oi->nostr = (size_t)0;
  oi->me = 0; oi->procs = 0; oi->flags = 0;
  oi->xfactor = 0.06;
  oi->yfactor = 0.06;
  oi->xadd = 0.0; oi->yadd = 0.0;
  oi->xleft = oi->xright = oi->ybottom = oi->ytop = 0.0;
  (oi->strok).red = (oi->strok).green = (oi->strok).blue = 0.0;
  (oi->nonst).red = (oi->nonst).green = (oi->nonst).blue = 0.0;
  oi->spcpass = 0;
  oi->errprinted = 0;
}



/**	Comparison for sorted storage (compare object position structures
	by object number).
	@param	l	Left object position structure.
	@param	r	Right object position structure.
	@param	c	Comparison criteria (ignored).
	@return	Comparison result.
*/
static
int
compare_object_positions DK_P3(void *,l, void *,r, int,c)
{
  int back = 0;
  OPOS *pl, *pr;
  pl = (OPOS *)l; pr = (OPOS *)r;
  if(pl) {
    if(pr) {
      if(pl->objno > pr->objno) {
        back = 1;
      } else {
        if(pl->objno < pr->objno) {
	  back = -1;
	}
      }
    } else {
      back = 1;
    }
  } else {
    if(pr) {
      back = -1;
    }
  }
  return back;
}



/**	Compare patterns for sorted storage (pattern number,
	background color, forground color, tiling).
	@param	l	Left pattern structure.
	@param	r	Right pattern structure.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
static
int
compare_pattern DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  dkfig_pdf_pattern *pl, *pr;
  pl = (dkfig_pdf_pattern *)l; pr = (dkfig_pdf_pattern *)r;
  if(l) {
    if(r) {
      if(pl->patno > pr->patno) {
        back = 1;
      } else {
        if(pl->patno < pr->patno) {
	  back = -1;
	}
      }
      if(!back) {
        if(pl->bgcol > pr->bgcol) {
	  back = 1;
	} else {
	  if(pl->bgcol < pr->bgcol) {
	    back = -1;
	  }
	}
      }
      if(!back) {
        if(pl->fgcol > pr->fgcol) {
	  back = 1;
	} else {
	  if(pl->fgcol < pr->fgcol) {
	    back = -1;
	  }
	}
      }
      /* 
      if(!back) {
        if(pl->lt > pr->lt) {
	  back = 1;
	} else {
	  if(pl->lt < pr->lt) {
	    back = -1;
	  }
	}
      }
      */
      if(!back) {
        if(pl->tile > pr->tile) {
	  back = 1;
	} else {
	  if(pl->tile < pr->tile) {
	    back = -1;
	  }
	}
      }
    } else {
      back = 1;
    }
  } else {
    if(r) {
      back = -1;
    }
  }
  return back;
}



/**	Write keyword to output stream.
	@param	oi	OI structure.
	@param	n	Index of keyword in kw array.
*/
static
void kw_out DK_P2(OI *,oi, size_t,n)
{
  if(oi) {
    if(oi->s) {
      if(n < nkw) {
        dkstream_puts(oi->s, kw[n]);
      }
    }
  }
}



/**	Check whether to print a character directory or to encode octal.
	@param	c	Character to check.
	@return	Flag, 1=print literally, 0=encode octally.
*/
static int
is_literal DK_P1(char,c)
{
  int back = 0;
  if((c >= 'A') && (c <= 'Z')) {
    back = 1;
  } else {
    if((c >= 'a') && (c <= 'z')) {
      back = 1;
    } else {
      if((c >= '0') && (c <= '9')) {
        back = 1;
      } else {
        switch(c) {
	  case ' ':
	  {
	    back = 1;
	  } break;
	}
      }
    }
  }
  return back;
}



/**	Write keyword to graphics contents stream (gcs).
	@param	oi	OI structure.
	@param	n	Index of keyword in the kw array.
*/
static
void gcs_out DK_P2(OI *,oi, size_t,n)
{
  if(oi) {
    if(oi->gcs) {
      if(n < nkw) {
        dkstream_puts(oi->gcs, kw[n]);
      }
    }
  }
}



/**	Write utf-8 encoded string to gcs.
	@param	oi	OI structure.
	@param	s	Output stream.
	@param	str	String to write.
*/
static
void pdf_encode_utf8 DK_P3(OI *,oi, dk_stream_t *,s, char *,str)
{
  int cc;
  dk_udword ucb; unsigned char uc; char chr; int i;
  size_t max, avail, used, step;
  char buffer[128];
  
  dkstream_puts(s, kw[52]);
  cc = 1; max = strlen(str); avail = max; used = 0; step = 0;
  while(cc) {
    cc = 0;
    if(avail) {
      step = 0;
      cc = dkenc_utf82uc(&ucb, (unsigned char *)(&(str[used])), avail, &step);
      if(cc) {
        used = used + step;
	if(avail > step) {
	  avail = avail - step;
	} else {
	  avail = 0;
	}
	uc = (unsigned char)ucb; chr = (char)uc; i = (int)chr;
	if(ucb < 256UL) {
	  
	  if(is_literal(chr)) {
	    buffer[0] = uc; buffer[1] = '\0';
	  } else {
	    if(i < 0) { i = i + 256; }
	    if(i < 0) { i = 0; }
	    if(i > 255) { i = 255; }
#if DK_HAVE_SNPRINTF
              snprintf(buffer, sizeof(buffer), "\\%03o", i);
	      buffer[sizeof(buffer)-1] = '\0';
#else
              sprintf(buffer, "\\%03o", i);
#endif
	  } 
	  dkstream_puts(s, buffer);
	}
      }
    }
  }
  dkstream_puts(s, kw[53]);
  
}



/**	Write latin-1 encoded string to gcs.
	@param	oi	OI structure.
	@param	s	Output stream to write to.
	@param	str	String to write.
*/
static
void pdf_encode_str DK_P3(OI *,oi, dk_stream_t *,s, char *,str)
{
  char buffer[128];
  char c, *ptr;
  int  i;
  
  if(str) { 
  }
  ptr = str;
  dkstream_puts(s, kw[52]);
  while(*ptr) {
    c = *(ptr++); 
    if(is_literal(c)) {
      buffer[0] = c; buffer[1] = '\0';
    } else {
      i = c;
      if(i < 0) { i = 256 + i; }
      if(i < 0) { i = 0; }
      if(i > 255) { i = 255; }
#if DK_HAVE_SNPRINTF
      snprintf(buffer, sizeof(buffer), "\\%03o", i);
      buffer[sizeof(buffer)-1] = '\0';
#else
      sprintf(buffer, "\\%03o", i);
#endif
    } 
    dkstream_puts(s, buffer);
  }
  dkstream_puts(s, kw[53]);
  
}



/**	Check whether or not two double values are nearly equal.
	@param	d1	One value.
	@param	d2	Other value.
	@return	Flag, 1=nearly equal, 0=not equal.

*/
static int
double_nearly_equal DK_P2(double,d1,double,d2)
{
  int back = 0;
  int me = 0;
  double diff;
  diff = fabs(dkma_sub_double_ok(d1,d2,&me));
  if(!me) {
    if(diff < DKFIG_EPSILON) {
      back = 1;
    }
  }
  return back;
}



/**	Write DCC color triple to graphics stream.
	@param	oi	OI structure.
	@param	dcc	Color cell.
*/
static
void write_dcc_triple DK_P2(OI *,oi, dk_fig_dcc *,dcc)
{
  dkstream_puts_double(oi->gcs, drd(dcc->red, oi->c, 0));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(dcc->green, oi->c, 0));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(dcc->blue, oi->c, 0));
  gcs_out(oi, 1);
}



/**	Set stroke properties.
	@param	oi	OI structure.
	@param	dcc	Color cell.
*/
static
void set_stroking DK_P2(OI *,oi, dk_fig_dcc *,dcc)
{
  int must_set = 1;
  int use_color = 1;
  double g;
  if((oi->flags) & HAVE_STROKE_COLOR) {
    if(double_nearly_equal((oi->strok).red, dcc->red)) {
    if(double_nearly_equal((oi->strok).green, dcc->green)) {
    if(double_nearly_equal((oi->strok).blue, dcc->blue)) {
      must_set = 0;
    } } }
  }
  if(must_set) {
    oi->flags |= HAVE_STROKE_COLOR;
    (oi->strok).red = dcc->red;
    (oi->strok).green = dcc->green;
    (oi->strok).blue = dcc->blue;
    if(oi->c) {
      if(!(((oi->c)->opt2) & DKFIG_OPT_COLOR)) {
        use_color = 0;
      }
    }
    if(use_color) {
      write_dcc_triple(oi, dcc);
      gcs_out(oi, 61);
    } else {
      g = 0.3 * dcc->red + 0.59 * dcc->green + 0.11 * dcc->blue;
      dkstream_puts_double(oi->gcs, drd(g, oi->c, 0));
      gcs_out(oi, 1);
      gcs_out(oi, 106);
    }
    gcs_out(oi, 0);
  }
}



/**	Set non-stroking (filling and text) properties.
	@param	oi	OI structure.
	@param	dcc	Color cell structure.
*/
static
void set_nonstroking DK_P2(OI *,oi, dk_fig_dcc *,dcc)
{
  int must_set = 1;
  int use_color = 1;
  double g;
  if((oi->flags) & HAVE_NON_STROKE_COLOR) {
    if(double_nearly_equal((oi->nonst).red, dcc->red)) {
    if(double_nearly_equal((oi->nonst).green, dcc->green)) {
    if(double_nearly_equal((oi->nonst).blue, dcc->blue)) {
      must_set = 0;
    } } }
  }
  if(must_set) {
    if(oi->c) {
      if(!(((oi->c)->opt2) & DKFIG_OPT_COLOR)) {
        use_color = 0;
      }
    }
    oi->flags |= HAVE_NON_STROKE_COLOR;
    (oi->nonst).red = dcc->red;
    (oi->nonst).green = dcc->green;
    (oi->nonst).blue = dcc->blue;
    if(use_color) {
      write_dcc_triple(oi, dcc);
      gcs_out(oi, 60);
    } else {
      g = 0.3 * dcc->red + 0.59 * dcc->green + 0.11 * dcc->blue;
      dkstream_puts_double(oi->gcs, drd(g, oi->c, 0));
      gcs_out(oi, 1);
      gcs_out(oi, 105);
    }
    gcs_out(oi, 0);
  }
}



/**	Get object linewidth.
	@param	oi	OI structure.
	@return	Line width for object stroke.
*/
static
double get_object_linewidth DK_P1(OI *,oi)
{
  double back = 0.0;
  back = dkma_mul_double_ok(
    0.9,
    dkma_l_to_double(((oi->co)->fpd).lt),
    &(oi->me)
  );
  if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
    back = 0.5 * back;
  }
  return back;
}



/**	Set linecap (low level).
	@param	oi	OI structure.
	@param	lc	New linecap.
*/
static
void ll_set_linecap DK_P2(OI *,oi, int,lc)
{
  dkstream_puts_long(oi->gcs, (long)lc);
  gcs_out(oi, 1); gcs_out(oi, 76); gcs_out(oi, 0);
}


/**	Set linecap (call low level function only if necessary).
	@param	oi	OI structure.
	@param	lc	New linecap.
*/
static
void set_linecap DK_P2(OI *,oi, int,lc)
{
  int must_set = 1;
  if((oi->flags) & HAVE_LINECAP) {
  if(oi->lc == lc) {
    must_set = 0;
  } }
  if(must_set) {
    oi->flags |= HAVE_LINECAP;
    oi->lc = lc;
    ll_set_linecap(oi, lc);
  }
}



/**	Set line join (low level operation).
	@param	oi	OI structure.
	@param	lj	New linejoin.
*/
static
void ll_set_linejoin DK_P2(OI *,oi, int,lj)
{
  dkstream_puts_long(oi->gcs, (long)lj);
  gcs_out(oi, 1); gcs_out(oi, 77); gcs_out(oi, 0);
}



/**	Set line join (call low-level function only if necessary).
	@param	oi	OI structure.
	@param	lj	New linejoin.
*/
static
void set_linejoin DK_P2(OI *,oi, int,lj)
{
  int must_set = 1;
  if((oi->flags) & HAVE_LINEJOIN) {
  if(oi->lj == lj) {
    must_set = 0;
  } }
  if(must_set) {
    oi->flags |= HAVE_LINEJOIN;
    oi->lj = lj;
    ll_set_linejoin(oi,lj);
  }
}



/**	Set dash style.
	@param	oi	OI structure.
	@param	ls	New line dash style.
	@param	sv	New style value.
*/
static
void set_dash DK_P3(OI *,oi, int,ls, double,sv)
{
  int must_set = 1;
  if((oi->flags) & HAVE_DASH) {
    if(oi->dash == ls) {
    if(double_nearly_equal(sv, oi->dasv)) {
      must_set = 0;
    } }
  }
  if(must_set) {
    double s, l;
    oi->flags |= HAVE_DASH;
    oi->dash = ls; oi->dasv = sv;
    s = 0.9 * sv;
    l = get_object_linewidth(oi);
    gcs_out(oi, 75);
    switch(ls) {
      case 2: {
        if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	  dkstream_puts_double(oi->gcs, drd(l, oi->c, 1));
	} else {
	  dkstream_puts_long(oi->gcs, 0L);
	}
	gcs_out(oi, 1);
	dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
      } break;
      case 1: case 3: case 4: case 5: {
        dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
	gcs_out(oi, 1);
	dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
	if(ls > 1) {
          gcs_out(oi, 1);
          if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	    dkstream_puts_double(oi->gcs, drd(l, oi->c, 1));
	  } else {
	    dkstream_puts_long(oi->gcs, 0L);
	  }
	  gcs_out(oi, 1);
	  dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
	  if(ls > 3) {
	    gcs_out(oi, 1);
	    if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	      dkstream_puts_double(oi->gcs, drd(l, oi->c, 1));
	    } else {
	      dkstream_puts_long(oi->gcs, 0L);
	    }
	    gcs_out(oi, 1);
	    dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
	    if(ls > 4) {
	      gcs_out(oi, 1);
	      if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	        dkstream_puts_double(oi->gcs, drd(l, oi->c, 1));
	      } else {
	        dkstream_puts_long(oi->gcs, 0L);
	      }
	      gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, drd(s, oi->c, 1));
	    }
	  }
	}
      } break;
    }
    gcs_out(oi, 25); gcs_out(oi, 1);
    gcs_out(oi, 19); gcs_out(oi, 1);
    gcs_out(oi, 74); gcs_out(oi, 0);
  }
}



/**	Set linewidth (low level).
	@param	oi	OI structure.
	@param	lw	Line width.
*/
static
void ll_set_linewidth DK_P2(OI *,oi, double,lw)
{
  dkstream_puts_double(oi->gcs, drd(lw, oi->c, 1));
  gcs_out(oi, 1); gcs_out(oi, 71); gcs_out(oi, 0);
}



/**	Set linewidth (call low-level function only if necessary).
	@param	oi	OI structure.
	@param	lw	Linewidth.
*/
static
void set_linewidth DK_P2(OI *,oi, double,lw)
{
  int must_set = 1;
  if((oi->flags) & HAVE_LINEWIDTH) {
    if(double_nearly_equal(oi->lw, lw)) {
      must_set = 0;
    }
  }
  if(must_set) {
    oi->lw = lw;
    oi->flags |= HAVE_LINEWIDTH;
    ll_set_linewidth(oi, lw);
  }
}



/**	Begin new PDF object, save start position.
	@param	oi	OI structure.
	@param	objno	Number of the new object.
	@return	1 on success, 0 on error.
*/
static
int begin_object DK_P2(OI *,oi, unsigned long,objno)
{
  int back = 0;
  OPOS pos, *pp;
  pos.objno = objno;
  pos.pos = dkstream_get_bytes_written(oi->s);
  if(!(dksto_it_find_like(oi->pdfoi, (void *)(&pos), 0))) {
    pp = dk_new(OPOS, 1);
    if(pp) {
      pp->objno = objno;
      pp->pos = pos.pos;
      if(dksto_add(oi->pdfo, (void *)pp)) {
        back = 1;
	dkstream_puts_ul(oi->s, objno);
	kw_out(oi, 3);
	kw_out(oi, 0);
      } else {
        dk_delete(pp);
	if((oi->c)->app) {
	  dkapp_err_memory((oi->c)->app, sizeof(dk_storage_node_t), 1);
	}
      }
    } else {
      if((oi->c)->app) {
        dkapp_err_memory((oi->c)->app, sizeof(OPOS), 1);
      }
    }
  }
  return back;
}



/**	End PDF object.
	@param	oi	OI structure.
*/
static
void end_object DK_P1(OI *,oi)
{
  kw_out(oi, 4);
  kw_out(oi, 0);
}



/**	Finalize PDF (create xref table etc).
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int finalize_pdf DK_P1(OI *,oi)
{
  int back = 0;
  OPOS *p;
  unsigned long xrefpos;
  char buffer[32];
  xrefpos = dkstream_get_bytes_written(oi->s);
  kw_out(oi, 7); kw_out(oi, 0);
  dkstream_puts_ul(oi->s, 0UL);
  kw_out(oi, 1);
  dkstream_puts_ul(oi->s, oi->no);
  kw_out(oi, 0);
  kw_out(oi, 17); kw_out(oi, 0);
  dksto_it_reset(oi->pdfoi);
  while((p = (OPOS *)dksto_it_next(oi->pdfoi)) != NULL) {
#if DK_HAVE_SNPRINTF
    snprintf(buffer, sizeof(buffer), "%010lu", p->pos);
    buffer[sizeof(buffer)-1] = '\0';
#else
    sprintf(buffer, "%010lu", p->pos);
#endif
    dkstream_puts(oi->s, buffer);
    kw_out(oi, 18); kw_out(oi, 0);
  }
  kw_out(oi, 10); kw_out(oi, 0);
  kw_out(oi, 5); kw_out(oi, 1);
  kw_out(oi, 11); kw_out(oi, 1);
  dkstream_puts_ul(oi->s, oi->no);
  kw_out(oi, 1);
  kw_out(oi, 14); kw_out(oi, 1); dkstream_puts_ul(oi->s, 1UL);
  kw_out(oi, 1); kw_out(oi, 19); kw_out(oi, 1); kw_out(oi, 13);
  kw_out(oi, 1);
  kw_out(oi, 12); kw_out(oi, 1); dkstream_puts_ul(oi->s, 2UL);
  kw_out(oi, 1); kw_out(oi, 19); kw_out(oi, 1); kw_out(oi, 13);
  kw_out(oi, 1);
  kw_out(oi, 6); kw_out(oi, 0);
  kw_out(oi, 15); kw_out(oi, 0);
  dkstream_puts_ul(oi->s, xrefpos); kw_out(oi, 0);
  kw_out(oi, 16); kw_out(oi, 0);
  back = 1;
  return back;
}



/**	Find coefficients for coordinates transformations.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int establish_coord_transformation DK_P1(OI *,oi)
{
  int back = 1;
  double xmin = 0.0, ymin = 0.0, xmax = 0.0, ymax = 0.0;
  double cxmin, cxmax, cymin, cymax;
  
  oi->me = 0;
  xmin = dkfig_tool_bb_get_xmin(&((oi->d)->dbb));
  xmax = dkfig_tool_bb_get_xmax(&((oi->d)->dbb));
  ymin = dkfig_tool_bb_get_ymin(&((oi->d)->dbb));
  ymax = dkfig_tool_bb_get_ymax(&((oi->d)->dbb));
  oi->xfactor = dkma_div_double_ok(72.0, (oi->d)->fres, &(oi->me));
  oi->yfactor = dkma_div_double_ok(72.0, (oi->d)->fres, &(oi->me));
  if(dkfig_tool_invert_y(oi->d)) {
    oi->yfactor = 0.0 - oi->yfactor;
  }
  xmin = dkma_mul_double_ok(xmin, oi->xfactor, &(oi->me));
  xmax = dkma_mul_double_ok(xmax, oi->xfactor, &(oi->me));
  ymin = dkma_mul_double_ok(ymin, oi->yfactor, &(oi->me));
  ymax = dkma_mul_double_ok(ymax, oi->yfactor, &(oi->me));
  if(xmax < xmin) { double cx; cx = xmax; xmax = xmin; xmin = cx; }
  if(ymax < ymin) { double cy; cy = ymax; ymax = ymin; ymin = cy; }
  cxmin = floor(xmin); cxmax = ceil(xmax);
  cymin = floor(ymin); cymax = ceil(ymax);
  oi->xleft = 0.0; oi->ybottom = 0.0;
  oi->xright = dkma_sub_double_ok(cxmax, cxmin, &(oi->me));
  oi->ytop =   dkma_sub_double_ok(cymax, cymin, &(oi->me));
  oi->xadd = 0.5 * dkma_sub_double_ok(
    oi->xright,
    dkma_sub_double_ok(cxmax, cxmin, &(oi->me)),
    &(oi->me)
  );
  oi->yadd = 0.5 * dkma_sub_double_ok(
    oi->ytop,
    dkma_sub_double_ok(cymax, cymin, &(oi->me)),
    &(oi->me)
  );
  oi->xadd = dkma_sub_double_ok(oi->xadd, cxmin, &(oi->me));
  oi->yadd = dkma_sub_double_ok(oi->yadd, cymin, &(oi->me));
  if(oi->me) {
    back = 0;
    dkfig_tool2_simple_error_message(oi->c, 13);
  }
  
  
  return back;
}



/**	Save information from inspecting one text object.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int gather_text DK_P1(OI *,oi)
{
  int back = 0;
  int is_special = 0;
  int font_no = 0;
  int font_features = 0;
  dk_fig_fonth_t *fhptr = NULL;
  
  if((oi->co)->data) {
    dk_fig_text *t;
    t = (dk_fig_text *)((oi->co)->data);
    fhptr = t->font_handling;
    if(fhptr) {
      back = 1;
      switch(fhptr->handling) {
        case 2: case 3: case 4: case 5: {
	  is_special = 1;
	} break;
      }
      if(!is_special) {
        if((((oi->co)->fpd).st) == 0) {
          if(fhptr->fontno >= 0) {
	    if(fhptr->fontno < 35) {
	      oi->procs |= DKFIG_PDF_PROCSET_TEXT;
	      font_features = dkfont_get_features(fhptr->fontno);
	      switch(font_features & DK_FONT_FEATURE_FAMILY) {
	        case DK_FONT_FEATURE_TT: {
	          font_no = 8;
	        } break;
	        case DK_FONT_FEATURE_SF: {
	          font_no = 4;
	        } break;
	        default: {
	          font_no = 0;
	        } break;
	      }
	      if(font_features & DK_FONT_FEATURE_IT) {
	        font_no += 2;
	      }
	      if(font_features & DK_FONT_FEATURE_BD) {
	        font_no += 1;
	      }
	      switch(fhptr->fontno) {
	        case 32: { font_no = 12; }
	        case 34: { font_no = 13; }
	      } 
	      (oi->fu)[font_no] = 1UL;
	      (oi->co)->drve = (void *)new_drve();
	      if((oi->co)->drve) {
	        dkfig_pdf_drve_text *ext;
	        ext = (dkfig_pdf_drve_text *)((oi->co)->drve);
	        ext->fn = font_no;
	      } else {
	        back = 0;
	      }
	    } else {
	      back = 0;
	      dkfig_tool2_simple_error_message(oi->c, 109);
	    }
	  } else {
	    back = 0;
	    dkfig_tool2_simple_error_message(oi->c, 109);
	  }
        } else {
          if(!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS)) {
  	    if(!((oi->errprinted) & 2)) {
	      
  	      dkfig_tool2_simple_error_message(oi->c, 110);
  	      if(!(((oi->c)->opt1) & DKFIG_OPT_REPORT_MULTIPLE)) {
	        oi->errprinted |= 2;
  	      }
  	    }
          }
	}
      }
    } else {
      if((oi->c)->app) { 
        dkfig_tool2_simple_error_message(oi->c, 44);
      }
    }
  } else {
    if((oi->c)->app) {	
      dkfig_tool2_simple_error_message(oi->c, 44);
    }
  } 
  return back;
}



/**	Process special comments for one object.
	@param	oi	OI structure.
*/
static
void handle_special_comments DK_P1(OI *,oi)
{
  int i;
  if(((oi->co)->osc) && ((oi->co)->osci)) {
    dk_fig_opt *speccom;
    dksto_it_reset((oi->co)->osci);
    while((speccom = (dk_fig_opt *)dksto_it_next((oi->co)->osci)) != NULL) {
      i = dkfig_opt_process_special_comment(
        oi->c, speccom->name, kw[89], 0
      );
      if((oi->spcpass) == 0) {
        dkfig_tool2_report_special_comment(oi->c, speccom, i);
      }
    }
  }
}



/**	Style information collection pass.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int gather_information DK_P1(OI *,oi) 
{
  int back = 1, i;
  dk_fig_object *o;
  dkfig_pdf_pattern pdfpat, *patp;
  dkfig_pdf_image *iptr;
  unsigned long backupopt1, backupopt2;
  int backupia;
  
  oi->no = 6UL;
  dksto_it_reset(oi->fli);
  oi->co = NULL;
  while((o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
    
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, o->lineno);
    }
    oi->co = o;
    backupopt1 = (oi->c)->opt1;
    backupopt2 = (oi->c)->opt2;
    backupia = (oi->c)->image_align;
    handle_special_comments(oi);
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, o->lineno);
    }
    switch(o->objtype) {
      case DK_FIG_OBJ_TEXT: {
        if(!gather_text(oi)) { back = 0; }
      } break;
      case DK_FIG_OBJ_POLYLINE: {
        if(((oi->co)->fpd).st == 5) {
	  
	  if(!((oi->co)->drve)) {
	    (oi->co)->drve = new_drve();
	  }
	  if((oi->co)->drve) {
	    dk_fig_polyline *polyline;
	    polyline = (dk_fig_polyline *)((oi->co)->data);
	    if(polyline) {
	      if(polyline->imagename) {
	        dkfig_pdf_image pdfi, *pdfiptr;
		pdfi.inputfilename = polyline->imagename;
		pdfi.flipped = 0;
		if(polyline->flipped) {
		  if(((oi->c)->opt2) & DKFIG_OPT_FLIP_DIAGONAL) {
		    pdfi.flipped = 2;
		  } else {
		    pdfi.flipped = 1;
		  }
		}
		pdfiptr = (dkfig_pdf_image *)dksto_it_find_like(
		  oi->imgli, (void *)(&pdfi), 0
		);
		if(pdfiptr) {
		  ((dkfig_pdf_drve_text *)((oi->co)->drve))->i = pdfiptr;
		} else {
		  pdfiptr = new_image(polyline->imagename);
		  if(pdfiptr) {
		    pdfiptr->flipped = pdfi.flipped;
		    if(dksto_add(oi->imgl, (void *)(pdfiptr))) {
		      ((dkfig_pdf_drve_text *)((oi->co)->drve))->i = pdfiptr;
		    } else {
		      delete_image(pdfiptr);
		      pdfiptr = NULL;
		      back = 0;
		      if((oi->c)->app) {
	                dkapp_err_memory((oi->c)->app, sizeof(dk_storage_node_t), 1);
		      }
		    }
		    pdfiptr->lineno = (oi->co)->lineno;
		  } else {
		    back = 0;
		    if((oi->c)->app) {
	              dkapp_err_memory((oi->c)->app, sizeof(dkfig_pdf_pattern), 1);
		    }
		  }
		}
	      } else {
	        back = 0; 
		dkfig_tool2_simple_error_message(oi->c, 44);
	      }
	    } else {
	      back = 0;	
	      dkfig_tool2_simple_error_message(oi->c, 44);
	    }
	  } else {
	    back = 0;
	    if((oi->c)->app) {
	      dkapp_err_memory((oi->c)->app, sizeof(dkfig_pdf_drve_text), 1);
	    }
	  }
	}
      } /* fall-through */
      case DK_FIG_OBJ_ELLIPSE:
      case DK_FIG_OBJ_SPLINE:
      case DK_FIG_OBJ_ARC: {
        if(((oi->co)->fpd).cl) {
          if(dkfig_tool_must_pattern(((oi->co)->fpd).af, (oi->c)->opt1)) {
	    if(!((oi->co)->drve)) {
	      (oi->co)->drve = new_drve();
	    }
	    if((oi->co)->drve) {
	      pdfpat.patno = ((oi->co)->fpd).af;
	      pdfpat.bgcol = ((oi->co)->fpd).fc;
	      pdfpat.fgcol = ((oi->co)->fpd).pc;
	      /* pdfpat.lt    = ((oi->co)->fpd).lt; */
	      pdfpat.tile  = 0;		
	      if(((oi->c)->opt2) & DKFIG_OPT_PDF_PATTERN_TILE) {
	        pdfpat.tile = 1;	
	      }
	      patp = (dkfig_pdf_pattern *)dksto_it_find_like(
	        oi->patli, (void *)(&pdfpat), 0
	      );
	      if(patp) {
	        ((dkfig_pdf_drve_text *)((oi->co)->drve))->p = patp;
	      } else {
	        patp = dk_new(dkfig_pdf_pattern,1);
		if(patp) {
		  patp->patno  = pdfpat.patno;
		  patp->bgcol  = pdfpat.bgcol;
		  patp->fgcol  = pdfpat.fgcol;
		  /* patp->lt     = pdfpat.lt; */
		  patp->tile   = pdfpat.tile;
		  patp->lineno = (oi->co)->lineno;
		  if(dksto_add(oi->patl, (void *)patp)) {
		    ((dkfig_pdf_drve_text *)((oi->co)->drve))->p = patp;
		  } else {
		    back = 0;
		    dk_delete(patp);
		    if((oi->c)->app) {
	              dkapp_err_memory((oi->c)->app, sizeof(dk_storage_node_t), 1);
		    }
		  }
		} else {
		  back = 0;
		  if((oi->c)->app) {
	            dkapp_err_memory((oi->c)->app, sizeof(dkfig_pdf_pattern), 1);
		  }
		}
	      }
	    } else {
	      back = 0;
	      if((oi->c)->app) {
	        dkapp_err_memory((oi->c)->app, sizeof(dkfig_pdf_drve_text), 1);
	      }
	    }
	  }
	}
      } break;
    }
    (oi->c)->opt1 = backupopt1;
    (oi->c)->opt2 = backupopt2;
    (oi->c)->image_align = backupia;
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
  } oi->co = NULL;
  /* fonts */
  for(i = 0; i < 14; i++) {
    if((oi->fu)[i]) {
      (oi->fu)[i] = oi->no; oi->no += 1UL;
    }
  }
  /* patterns */
  dksto_it_reset(oi->patli);
  while((patp = (dkfig_pdf_pattern *)dksto_it_next(oi->patli)) != NULL) {
    patp->objno = oi->no;
    oi->no += 1UL;
  }
  /* images */
  dksto_it_reset(oi->imgli);
  while((iptr = (dkfig_pdf_image *)dksto_it_next(oi->imgli)) != NULL) {
    oi->ci = iptr;
    if(dkfigpi_prepare_image(oi)) {
      iptr->objno = oi->no;
      oi->no += 1UL;
      switch(iptr->ch) {
        case 2: case 4: {
	  oi->no += 1UL;
	  oi->procs |= DKFIG_PDF_PROCSET_IMGG;
	} break;
      }
      switch(iptr->ch) {
        case 1: case 2: {
	  oi->procs |= DKFIG_PDF_PROCSET_IMGG;
	} break;
	default: {
	  oi->procs |= DKFIG_PDF_PROCSET_IMGC;
	} break;
      }
    } else {
      back = 0;
    }
    oi->ci = NULL;
  }
  oi->nostr = dkfig_dt_needed_alpha(oi->no);
  if(oi->me) {
    back = 0;
    dkfig_tool2_simple_error_message(oi->c, 13);
  }
  
  return back;
}



/**	Prepare PDF output.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int preparation_pass DK_P1(OI *,oi)
{
  int back = 0;
  int error_code;
  error_code = 2;
  
  oi->spcpass = 0;
  dkfig_tool2_simple_progress_message(oi->c, 98);
  oi->fl = dkfig_flat_list(oi->c, (oi->c)->drwng);
  if(oi->fl) {
    error_code = 3;
    oi->fli = dksto_it_open(oi->fl);
    if(oi->fli) {
      error_code = 2;
      oi->imgl = dksto_open(0);
      if(oi->imgl) {
	dksto_set_comp(oi->imgl, compare_images, 0);
        error_code = 3;
        oi->imgli = dksto_it_open(oi->imgl);
	if(oi->imgli) {
	  error_code = 2;
	  oi->patl = dksto_open(0);
	  if(oi->patl) {
	    dksto_set_comp(oi->patl, compare_pattern, 0);
	    error_code = 3;
	    oi->patli = dksto_it_open(oi->patl);
	    if(oi->patli) {
	      error_code = 2;
	      oi->pdfo = dksto_open(0);
	      if(oi->pdfo) {
	        error_code = 3;
		dksto_set_comp(oi->pdfo, compare_object_positions, 0);
		oi->pdfoi = dksto_it_open(oi->pdfo);
		if(oi->pdfoi) {
		  error_code = 0;
		  if(establish_coord_transformation(oi)) {
		    /* oi->no = 5UL; */
		    back = gather_information(oi);
		  } else {
		    dkfig_tool2_simple_error_message(oi->c, 13);
		  }
		}
	      }
	    }
	  }
	}
      }
    }
  }
  if(!back) {
    switch(error_code) {
      case 1: {
	dkfig_tool2_simple_error_message(oi->c, 11);
      } break;
      case 2: {
        if((oi->c)->app) {
	  dkapp_err_memory((oi->c)->app, sizeof(dk_storage_t), 1);
	}
      } break;
      case 3: {
        if((oi->c)->app) {
	  dkapp_err_memory((oi->c)->app, sizeof(dk_storage_iterator_t), 1);
	}
      } break;
    }
  }
  oi->spcpass = 1;
  
  return back;
}



/**	Change CTM, translate and rotate.
	@param	oi	OI structure.
	@param	s	Output stream to write instructions to.
	@param	x	X shift.
	@param	y	Y shift.
	@param	phi	Rotation angle.
*/
static
void change_ctm DK_P5(OI *,oi, dk_stream_t *,s, double,x, double,y, double,phi)
{
  double a, b;
  a = cos(phi); b = sin(phi);
  /*
  a = dkma_double_restrict_digits(a, 3);
  b = dkma_double_restrict_digits(b, 3);
  */
  dkstream_puts(s, kw[56]);
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[19]);
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[19]);
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[56]);
  dkstream_puts(s, kw[1]);
  dkstream_puts_double(s, drd(x, oi->c, 1));
  dkstream_puts(s, kw[1]);
  dkstream_puts_double(s, drd(y, oi->c, 1));
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[55]);
  dkstream_puts(s, kw[0]);
  dkstream_puts_double(s, drd(a, oi->c, 2));
  dkstream_puts(s, kw[1]);
  dkstream_puts_double(s, drd(b, oi->c, 2));
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[57]);
  dkstream_puts_double(s, drd(b, oi->c, 2));
  dkstream_puts(s, kw[1]);
  dkstream_puts_double(s, drd(a, oi->c, 2));
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[19]);
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[19]);
  dkstream_puts(s, kw[1]);
  dkstream_puts(s, kw[55]);
  dkstream_puts(s, kw[0]);
}



/**	Write points in double coordinates.
	@param	oi	OI structure.
	@param	x	X value.
	@param	y	Y value.
	@param	h	How to handle digit restriction
	(1=coordinate, 2=trigonometric result, default=color).
*/
static
void dpointout DK_P4(OI *,oi, double,x, double,y, int,h)
{
  dkstream_puts_double(oi->gcs,drd(ccdx(oi,x),oi->c,h));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs,drd(ccdy(oi,y),oi->c,h));
  gcs_out(oi, 1);
}



/**	Write points in double coordinates, no transformation.
	@param	oi	OI structure.
	@param	x	X value.
	@param	y	Y value.
	@param	h	How to handle digit restriction
	(1=coordinate, 2=trigonometric result, default=color).
*/
static
void nocdpointout DK_P4(OI *,oi, double,x, double,y, int,h)
{
  dkstream_puts_double(oi->gcs, drd(x,oi->c,h));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(y,oi->c,h));
  gcs_out(oi, 1);
}



/**	Write points in long coordinates.
	@param	oi	OI structure.
	@param	x	X value.
	@param	y	Y value.
	@param	h	How to handle digit restriction
	(1=coordinate, 2=trigonometric result, default=color).
*/
static
void lpointout DK_P4(OI *,oi, long,x, long,y, int,h)
{
  dkstream_puts_double(oi->gcs,drd(cclx(oi,x),oi->c,h));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs,drd(ccly(oi,y),oi->c,h));
  gcs_out(oi, 1);
}



/**	Write text object to gcs.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int create_contents_text DK_P1(OI *,oi)
{
  int back = 0;
  dk_fig_text *t = NULL;
  dk_fig_fonth_t *fhptr = NULL;
  int is_special = 0, is_rotated = 0;
  dkfig_pdf_drve_text *e = NULL;
  unsigned long objno = 0UL;
  dk_fig_dcc dcc;
  
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    gcs_out(oi, 84);
    dkstream_puts_ul(oi->gcs, (oi->co)->lineno);
    gcs_out(oi, 0);
  }
  t = (dk_fig_text *)((oi->co)->data);
  e = (dkfig_pdf_drve_text *)((oi->co)->drve);
  if((t) && (e)) {
    fhptr = t->font_handling;
    if(fhptr) {
      back = 1;
      is_special = 0;
      switch(fhptr->handling) {
        case 2: case 3: case 4: case 5: { is_special = 1; } break;
      }
      if(is_special) {
        
	if(!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS)) {
  	  if(!((oi->errprinted) & 1)) {
  	    dkfig_tool2_simple_error_message(oi->c, 85);
  	    if(!(((oi->c)->opt1) & DKFIG_OPT_REPORT_MULTIPLE)) {
	      oi->errprinted |= 1;
  	    }
  	  }
	}
      } else {
        
        is_rotated = 0;
	if(fabs(t->angle) > DKFIG_EPSILON) { is_rotated = 1; }
	objno = (oi->fu)[e->fn];
	
        dkfig_tool_fill_dcc(oi->d, &dcc, ((oi->co)->fpd).pc);
	
	set_nonstroking(oi, &dcc);
	
	if(is_rotated) {
	  
	  gcs_out(oi, 37); gcs_out(oi, 0);
	  change_ctm(oi, oi->gcs, cclx(oi, t->x), ccly(oi, t->y), t->angle);
	  gcs_out(oi, 47); gcs_out(oi, 0);
	  gcs_out(oi, 35); gcs_out(oi, 45);
	  dkfig_tool_num_as_string(oi->gcs, objno, oi->nostr);
	  gcs_out(oi, 1);
	  dkstream_puts_double(
	    oi->gcs,
	    dkfig_tool2_drd(
	      dkma_mul_double_ok((oi->c)->fsf, fhptr->fontsize, &(oi->me)),
	      oi->c, 1
	    )
	  );
	  gcs_out(oi, 1);
	  gcs_out(oi, 49); gcs_out(oi, 0);
	  dkstream_puts_double(oi->gcs, 0.0);
	  gcs_out(oi, 1);
	  dkstream_puts_double(oi->gcs, 0.0);
	  gcs_out(oi, 1);
	  gcs_out(oi, 50); gcs_out(oi, 0);
	  if(((oi->c)->opt2) & DKFIG_OPT_UTF_8) {
	    /* UTF-8 encoded */
	    
	    pdf_encode_utf8(oi, oi->gcs, t->text);
	  } else {
	    
	    pdf_encode_str(oi, oi->gcs, t->text);
	  }
	  gcs_out(oi, 1); gcs_out(oi, 51); gcs_out(oi, 0);
	  gcs_out(oi, 48); gcs_out(oi, 0);
	  gcs_out(oi, 38); gcs_out(oi, 0);
	} else {
	  
	  gcs_out(oi, 47); gcs_out(oi, 0);
	  gcs_out(oi, 35); gcs_out(oi, 45);
	  dkfig_tool_num_as_string(oi->gcs, objno, oi->nostr);
	  gcs_out(oi, 1); 
	  dkstream_puts_double(
	    oi->gcs,
	    dkfig_tool2_drd(
	      dkma_mul_double_ok((oi->c)->fsf, fhptr->fontsize, &(oi->me)),
	      oi->c, 1
	    )
	  ); 
	  gcs_out(oi, 1);
	  gcs_out(oi, 49); gcs_out(oi, 0);
	  dkstream_puts_double(oi->gcs, drd(cclx(oi, t->x), oi->c, 1));
	  gcs_out(oi, 1); 
	  dkstream_puts_double(oi->gcs, drd(ccly(oi, t->y), oi->c, 1));
	  gcs_out(oi, 1); 
	  gcs_out(oi, 50); gcs_out(oi, 0);
	  if(((oi->c)->opt2) & DKFIG_OPT_UTF_8) {
	    pdf_encode_utf8(oi, oi->gcs, t->text);
	  } else {
	    pdf_encode_str(oi, oi->gcs, t->text);
	  }
	  
	  gcs_out(oi, 1); gcs_out(oi, 51); gcs_out(oi, 0);
	  gcs_out(oi, 48); gcs_out(oi, 0); 
	}
	
      }
    } else {	
      dkfig_tool2_simple_error_message(oi->c, 44);
    }
  } else {
    
    if(((oi->co)->fpd).st) {
      back = 1; /* It is okay to skip aligned text */
    } else {	
      if(t) {
        fhptr = t->font_handling;
	if(fhptr) {
	  switch(fhptr->handling) {
	    case 2: case 3: case 4: case 5: {
	      if(!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS)) {
  	        if(!((oi->errprinted) & 1)) {
  	          dkfig_tool2_simple_error_message(oi->c, 85);
  	          if(!(((oi->c)->opt1) & DKFIG_OPT_REPORT_MULTIPLE)) {
	            oi->errprinted |= 1;
  	          }
  	        }
	      }
	    } break;
	    default: {
	      dkfig_tool2_simple_error_message(oi->c, 44);
	    } break;
	  }
	} else {
	  dkfig_tool2_simple_error_message(oi->c, 44);
	}
      } else {
        dkfig_tool2_simple_error_message(oi->c, 44);
      }
    }
  }
  
  return back;
}



/**	Is there a reason to deny object filling?
	@param	oi	OI structure.
	@return	1=no filling, 0=allowed to fill.
*/
static
int reason_for_no_filling DK_P1(OI *,oi)
{
  int back = 0;
  if(((oi->co)->fpd).fc == (oi->d)->transparent) {
    back = 1;
  }
  if((oi->co)->objtype == DK_FIG_OBJ_POLYLINE) {
    if((oi->co)->subtype == 5) {
      if(!(((oi->c)->opt1) & DKFIG_OPT_FILL_BITMAP_AREA)) {
        back = 1;
      }
    } else {
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
        int wbgr = 0;
	if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
	  wbgr = 1;
	}
        if(dkfig_tool2_obj_is_bg_rect(oi->co, wbgr)) {
	  back = 1;
	}
      }
    }
  }
  return back;
}



/**	Is it necessary to fill the current object?
	@param	oi	OI structure.
	@return	1=fill, 0=no fill.
*/
static
int must_fill DK_P1(OI *,oi)
{
  int back = 0;
  if(((oi->co)->fpd).cl) {
    if(dkfig_tool_must_fill(((oi->co)->fpd).af, (oi->c)->opt1)) {
      back = 1;
      if(reason_for_no_filling(oi)) {
        back = 0;
      }
    }
  }
  return back;
}



/**	Is it necessary to pattern the current object?
	@param	oi	OI structure.
	@return	1=must pattern, 0=no pattern.
*/
static
int must_pattern DK_P1(OI *,oi)
{
  int back = 0;
  if(((oi->co)->fpd).cl) {
    if(dkfig_tool_must_pattern(((oi->co)->fpd).af, (oi->c)->opt1)) {
      back = 1;
      if(reason_for_no_filling(oi)) {
        back = 0;
      }
    }
  }
  return back;
}



/**	Is there a reason to deny stroking?
	@param	oi	OI structure.
	@return	1=no stroking, 0=string allowed.
*/
static
int reason_for_no_stroking DK_P1(OI *,oi)
{
  int back = 0;
  if(((oi->co)->fpd).pc == (oi->d)->transparent) {
    back = 1;
  }
  if((oi->co)->objtype == DK_FIG_OBJ_POLYLINE) {
    if((oi->co)->subtype == 5) {
      if((((oi->c)->opt1) & DKFIG_OPT_REMOVE_BITMAP_BORDER)) {
        back = 1;
      }
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_THIN_BORDERS) {
        if(((oi->co)->fpd).lt == 0L) {
	  back = 1;
	}
      }
    } else {
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
        int wbgr = 0;
	if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
	  wbgr = 1;
	}
        if(dkfig_tool2_obj_is_bg_rect(oi->co, wbgr)) {
	  back = 1;
	}
      }
    }
  }
  if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_THIN_BORDERS) {
    if(((oi->co)->fpd).lt == 0L) {
      if(((oi->co)->fpd).cl) {
        if(must_fill(oi) || must_pattern(oi)) {
	  back = 1;
	}
      }
    }
  }
  return back;
}



/**	Do we need to stroke we current object?
	@param	oi	OI structure.
	@return	1=must stroke, 0=no stroke.
*/
static
int must_stroke DK_P1(OI *,oi)
{
  int back = 1;
  if(reason_for_no_stroking(oi)) {
    back = 0;
  }
  return back;
}



/**	Set up graphics state for current object.
	@param	oi	OI structure.
*/
static
void set_lw_and_colors DK_P1(OI *,oi)
{
  if(must_pattern(oi)) {
    dkfig_pdf_drve_text *pdrve;
    if((oi->co)->drve) {
        pdrve = (dkfig_pdf_drve_text *)((oi->co)->drve);
	if(pdrve->p) {
	  dkfig_pdf_pattern *patp;
	  patp = pdrve->p;
          gcs_out(oi, 72);
	  gcs_out(oi, 35); gcs_out(oi, 45);
	  dkfig_tool_num_as_string(oi->gcs, patp->objno, oi->nostr);
	  gcs_out(oi, 1); gcs_out(oi, 73); gcs_out(oi, 0);
	  oi->flags &= (~(HAVE_NON_STROKE_COLOR));
	}
    }
  } else {
    if(must_fill(oi)) {
        dk_fig_dcc bdcc;
	dkfig_tool_fill_dcc(oi->d, &bdcc, ((oi->co)->fpd).fc);
	dkfig_tool_correct_dcc(&bdcc, ((oi->co)->fpd).fc, ((oi->co)->fpd).af);
	set_nonstroking(oi, &bdcc);
    }
  }
  if(must_stroke(oi)) {
    dk_fig_dcc fdcc;
    dkfig_tool_fill_dcc(oi->d, &fdcc, ((oi->co)->fpd).pc);
    set_stroking(oi, &fdcc);
    set_linewidth(oi, get_object_linewidth(oi));
    set_dash(oi, ((oi->co)->fpd).ls, ((oi->co)->fpd).sv);
    set_linecap(oi, ((oi->co)->fpd).cs);
    set_linejoin(oi, ((oi->co)->fpd).js);
  }
}



/**	Add final keyword to fill/stroke the current object.
	@param	oi	OI structure.
*/
static
void final_keyword DK_P1(OI *,oi)
{
  int kwno = 0;
  if(((oi->co)->fpd).cl) {	/* closed object */
    if(must_fill(oi) || must_pattern(oi)) {
      if(must_stroke(oi)) {
        if(((oi->c)->opt2) & DKFIG_OPT_FILL_NONZERO) {
	  kwno = 78;
	} else {
	  kwno = 79;
	}
      } else {
        if(((oi->c)->opt2) & DKFIG_OPT_FILL_NONZERO) {
	  kwno = 80;
	} else {
	  kwno = 81;
	}
      }
    } else {
      if(must_stroke(oi)) {
        kwno = 82;
      }
    }
  } else {			/* non-closed object */
    if(must_stroke(oi)) {
      kwno = 70;
    }
  }
  if(kwno) {
    gcs_out(oi, kwno); gcs_out(oi, 0);
  }
}



/**	Approximate arc by Bezier segments.
	@param	oi	OI structure.
	@param	ac	Arc calculation support structure.
*/
static
void pdf_arc_path DK_P2(OI *,oi, pdf_arc_calc *,ac)
{
  double phistep;
  double nsteps;
  double dxdt0, dydt0, dxdt1, dydt1, x0, y0, x1, y1, phi0, phi1;
  double xa, ya, xb, yb;
  double ddtfactor;
  unsigned i;
  
  dxdt0 = dydt0 = dxdt1 = dydt1 = x0 = y0 = x1 = y1 = 0.0;
  phi0 = phi1 = xa = ya = xb = yb = ddtfactor = 0.0;
  
  phistep = dkma_sub_double_ok(ac->phi1,ac->phi0,&(oi->me));
  ddtfactor = dkma_div_double_ok(
    dkma_sub_double_ok(ac->phi1, ac->phi0, &(oi->me)),
    dkma_l_to_double((long)(ac->segs)),
    &(oi->me)
  );
  nsteps = dkma_l_to_double(ac->segs);
  for(i = 0; i < ac->segs; i++) {
    if(i == 0) {
      phi0 = ac->phi0;
      x0 = ac->x0; y0 = ac->y0;
      dxdt0 = 0.0 - ac->rx * sin(phi0);
      dydt0 = ac->ry * cos(phi0);
      dxdt0 = dkma_mul_double_ok(ddtfactor, dxdt0, &(oi->me));
      dydt0 = dkma_mul_double_ok(ddtfactor, dydt0, &(oi->me));
    } else {
      phi0 = phi1;
      x0 = x1; y0 = y1;
      dxdt0 = dxdt1; dydt0 = dydt1;
    }
    phi1 = dkma_div_double_ok(
      dkma_mul_double_ok(
        dkma_l_to_double(1L + (long)i),
	phistep, &(oi->me)
      ),
      dkma_l_to_double((long)(ac->segs)),
      &(oi->me)
    );
    phi1 = dkma_add_double_ok(phi1, ac->phi0, &(oi->me));
    
    if(i == (ac->segs - 1)) {
      x1 = ac->x1; y1 = ac->y1;
    } else {
      x1 = ac->rx * cos(phi1);
      y1 = ac->ry * sin(phi1);
      
      x1 = dkma_add_double_ok(x1, ac->xm, &(oi->me));
      y1 = dkma_add_double_ok(y1, ac->ym, &(oi->me));
      
    }
    dxdt1 = 0.0 - ac->rx * sin(phi1);
    dydt1 = ac->ry * cos(phi1);
    
    dxdt1 = dkma_mul_double_ok(ddtfactor, dxdt1, &(oi->me));
    dydt1 = dkma_mul_double_ok(ddtfactor, dydt1, &(oi->me));
    
    xa = dkma_add_double_ok(x0, (dxdt0/3.0), &(oi->me));
    ya = dkma_add_double_ok(y0, (dydt0/3.0), &(oi->me));
    xb = dkma_sub_double_ok(x1, (dxdt1/3.0), &(oi->me));
    yb = dkma_sub_double_ok(y1, (dydt1/3.0), &(oi->me));
    nocdpointout(oi, xa, ya, 2);
    nocdpointout(oi, xb, yb, 2);
    if(i == (ac->segs - 1)) {
      nocdpointout(oi, x1, y1, 1);
    } else {
      nocdpointout(oi, x1, y1, 2);
    }
    gcs_out(oi, 83); gcs_out(oi, 0);
  } 
}



/**	Find bounding box for image.
	@param	oi	OI structure.
*/
static
void set_imgbb DK_P1(OI *,oi)
{
  dk_fig_polyline *p;
  dk_fig_bb bbdest;
  long *xptr, *yptr;
  size_t i;
  double xmin, xmax, ymin, ymax;
  
  p = (dk_fig_polyline *)((oi->co)->data);
  if(p) {
    dkfig_tool_bb_reset(&bbdest);
    xptr = p->xvalues; yptr = p->yvalues;
    for(i = 0; i < p->npoints; i++) {
      dkfig_tool_bb_add_x(&bbdest, cclx(oi, *xptr));
      dkfig_tool_bb_add_y(&bbdest, ccly(oi, *yptr));
      xptr++; yptr++;
    }
    xmin = bbdest.xmin; xmax = bbdest.xmax;
    ymin = bbdest.ymin; ymax = bbdest.ymax;
    xmin = drd(xmin,oi->c,1); xmax = drd(xmax,oi->c,1);
    ymin = drd(ymin,oi->c,1); ymax = drd(ymax,oi->c,1);
    dkfig_tool_bb_reset(&(oi->imgbb));
    dkfig_tool_bb_add_x(&(oi->imgbb), xmin);
    dkfig_tool_bb_add_x(&(oi->imgbb), xmax);
    dkfig_tool_bb_add_y(&(oi->imgbb), ymin);
    dkfig_tool_bb_add_y(&(oi->imgbb), ymax);
  }
}



/**	Write polyline path.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int write_polyline_path DK_P1(OI *,oi)
{
  int back = 0;
  dk_fig_polyline *p;
  long *xptr, *yptr; size_t i;
  
  p = (dk_fig_polyline *)((oi->co)->data);
  if(p) {
    back = 1;
    switch(((oi->co)->fpd).st) {
      case 2: case 4: case 5: {	/* box, arc-box, image */
        dk_fig_bb bbdest;
	double xmin, xmax, ymin, ymax, x1, x2, y1, y2, r;
	
	dkfig_tool_bb_reset(&bbdest);
	xptr = p->xvalues; yptr = p->yvalues;
	for(i = 0; i < p->npoints; i++) {
	  dkfig_tool_bb_add_x(&bbdest, cclx(oi, *xptr));
	  dkfig_tool_bb_add_y(&bbdest, ccly(oi, *yptr));
	  xptr++; yptr++;
	}
	xmin = bbdest.xmin; xmax = bbdest.xmax;
	ymin = bbdest.ymin; ymax = bbdest.ymax;
	xmin = drd(xmin,oi->c,1); xmax = drd(xmax,oi->c,1);
	ymin = drd(ymin,oi->c,1); ymax = drd(ymax,oi->c,1);
	dkfig_tool_bb_reset(&(oi->imgbb));	/* save bb for image showing */
	dkfig_tool_bb_add_x(&(oi->imgbb), xmin);
	dkfig_tool_bb_add_x(&(oi->imgbb), xmax);
	dkfig_tool_bb_add_y(&(oi->imgbb), ymin);
	dkfig_tool_bb_add_y(&(oi->imgbb), ymax);
	if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
	  switch(((oi->co)->fpd).st) {
	    case 2: case 5: {	/* box or image box */
	      dkstream_puts_double(oi->gcs, xmin); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, ymin); gcs_out(oi, 1);
	      gcs_out(oi, 66); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, xmax); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, ymin); gcs_out(oi, 1);
	      gcs_out(oi, 67); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, xmax); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, ymax); gcs_out(oi, 1);
	      gcs_out(oi, 67); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, xmin); gcs_out(oi, 1);
	      dkstream_puts_double(oi->gcs, ymax); gcs_out(oi, 1);
	      gcs_out(oi, 67); gcs_out(oi, 0);
	    } break;
	    default: {		/* arc-box */
	      pdf_arc_calc ac;
	      r = 0.9 * dkma_l_to_double(p->radius);
	      r = drd(r,oi->c,1);
	      x1 = dkma_add_double_ok(xmin, r, &(oi->me));
	      x2 = dkma_sub_double_ok(xmax, r, &(oi->me));
	      y1 = dkma_add_double_ok(ymin, r, &(oi->me));
	      y2 = dkma_sub_double_ok(ymax, r, &(oi->me));
	      ac.segs = (oi->c)->circlesteps;
	      nocdpointout(oi, xmin, y1, 1);
	      gcs_out(oi, 66); gcs_out(oi, 0);
	      ac.rx = ac.ry = r;
	      ac.xm = x1; ac.ym = y1;
	      ac.phi0 = M_PI; ac.phi1 = 1.5 * M_PI;
	      ac.segs = (oi->c)->circlesteps;
	      ac.x0 = xmin; ac.y0 = y1;
	      ac.x1 = x1; ac.y1 = ymin;
	      pdf_arc_path(oi, &ac);
	      nocdpointout(oi, x2, ymin, 1);
	      gcs_out(oi, 67); gcs_out(oi, 0);
	      ac.rx = ac.ry = r;
	      ac.xm = x2; ac.ym = y1;
	      ac.phi0 = 1.5 * M_PI; ac.phi1 = 2.0 * M_PI;
	      ac.segs = (oi->c)->circlesteps;
	      ac.x0 = x2; ac.y0 = ymin;
	      ac.x1 = xmax; ac.y1 = y1;
	      pdf_arc_path(oi, &ac);
	      nocdpointout(oi, xmax, y2, 1);
	      gcs_out(oi, 67); gcs_out(oi, 0);
	      ac.rx = ac.ry = r;
	      ac.xm = x2; ac.ym = y2;
	      ac.phi0 = 0.0; ac.phi1 = 0.5 * M_PI;
	      ac.segs = (oi->c)->circlesteps;
	      ac.x0 = xmax; ac.y0 = y2;
	      ac.x1 = x2; ac.y1 = ymax;
	      pdf_arc_path(oi, &ac);
	      nocdpointout(oi, x1, ymax, 1);
	      gcs_out(oi, 67); gcs_out(oi, 0);
	      ac.rx = ac.ry = r;
	      ac.xm = x1; ac.ym = y2;
	      ac.phi0 = 0.5 * M_PI; ac.phi1 = M_PI;
	      ac.segs = (oi->c)->circlesteps;
	      ac.x0 = x1; ac.y0 = ymax;
	      ac.x1 = xmin; ac.y1 = y2;
	      pdf_arc_path(oi, &ac);
	    } break;
	  }
	}
      } break;
      default: {		/* polyline or polygon */
        if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
	  xptr = p->xvalues; yptr = p->yvalues;
	  if((!(((oi->co)->fpd).cl)) && (((oi->co)->fpd).ar & 2)) {
	    dpointout(oi, (p->pa).x, (p->pa).y, 1);
	  } else {
	    lpointout(oi, *xptr, *yptr, 1);
	  }
	  xptr++; yptr++;
	  gcs_out(oi, 1); gcs_out(oi, 66); gcs_out(oi, 0);
	  for(i = 1; i < p->npoints; i++) {
	    if(i == (p->npoints - 1)) {
	      if(!(((oi->co)->fpd).cl)) {
	        if((((oi->co)->fpd).ar) & 1) {
		  dpointout(oi, (p->pe).x, (p->pe).y, 1);
		  gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 0);
		} else {
		  lpointout(oi, *xptr, *yptr, 1);
	          gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 0);
		}
	      }
	    } else {
	      lpointout(oi, *xptr, *yptr, 1);
	      gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 0);
	    }
	    xptr++; yptr++;
	  }
	}
      } break;
    }
  } else {	
    dkfig_tool2_simple_error_message(oi->c, 44);
  } 
  return back;
}



/**	Draw one arrow head.
	@param	oi	OI structure.
	@param	a	Arrowhead structure.
*/
static
void one_arrow_head DK_P2(OI *,oi, dk_fig_arrow *,a)
{
  dk_fig_dcc bdcc;
  int final_kw = 0;
  set_dash(oi, 0, 0.0);
  set_linecap(oi, 0);
  set_linejoin(oi, (oi->c)->ahlj);
  if(a->type) {
    if(a->style) {
      dkfig_tool_fill_dcc(oi->d, &bdcc, ((oi->co)->fpd).pc);
    } else {
      bdcc.red = bdcc.green = bdcc.blue = 1.0;
    }
    set_nonstroking(oi, &bdcc);
    final_kw = 78;
  } else {
    final_kw = 70;
  }
  dpointout(oi, (a->p1).x, (a->p1).y, 2);
  gcs_out(oi, 66); gcs_out(oi, 0);
  dpointout(oi, (a->p2).x, (a->p2).y, 2);
  gcs_out(oi, 67); gcs_out(oi, 0);
  dpointout(oi, (a->p3).x, (a->p3).y, 2);
  gcs_out(oi, 67); gcs_out(oi, 0);
  if(a->numpoints > 3) {
    dpointout(oi, (a->p4).x, (a->p4).y, 2);
    gcs_out(oi, 67); gcs_out(oi, 0);
  }
  if(final_kw) {
    gcs_out(oi, final_kw); gcs_out(oi, 0);
  }
}



/**	Draw both arrow heads for current object.
	@param	oi	OI structure.
*/
static
void
both_arrow_heads DK_P1(OI *,oi)
{
  if(!(((oi->co)->fpd).cl)) {
    if((((oi->co)->fpd).ar) & 1) { /* forward */
      one_arrow_head(oi, &(((oi->co)->fpd).ahf));
    }
    if((((oi->co)->fpd).ar) & 2) { /* backward */
      one_arrow_head(oi, &(((oi->co)->fpd).ahb));
    }
  }
}



/**	Show embedded image.
	@param	oi	OI structure.
*/
static
int show_image DK_P1(OI *,oi)
{
  int back = 1;
  dk_fig_polyline *p;
  dkfig_pdf_drve_text *e;
  dkfig_pdf_image *i, *oldci;
  double lwhalf, deltax, deltay, sfx, sfy, x0, y0, dwi, dhi;
  unsigned long wi, hi;
  p = (dk_fig_polyline *)((oi->co)->data);
  e = (dkfig_pdf_drve_text *)((oi->co)->drve);
  if((p) && (e)) {
    i = e->i;
    oldci = oi->ci;
    oi->ci = i;
    switch(i->flipped) {
      case 2:  { wi = i->h; hi = i->w; } break;
      default: { wi = i->w; hi = i->h; } break;
    }
    lwhalf = 0.0;
    deltax = dkma_sub_double_ok((oi->imgbb).xmax,(oi->imgbb).xmin,&(oi->me));
    deltay = dkma_sub_double_ok((oi->imgbb).ymax,(oi->imgbb).ymin,&(oi->me));
    if(must_stroke(oi)) {
      lwhalf = get_object_linewidth(oi);
      deltax = dkma_sub_double_ok(deltax, lwhalf, &(oi->me));
      deltay = dkma_sub_double_ok(deltay, lwhalf, &(oi->me));
      lwhalf = 0.5 * lwhalf;
    }
    sfx = deltax;
    sfy = deltay;
    x0 = dkma_add_double_ok((oi->imgbb).xmin, lwhalf, &(oi->me));
    y0 = dkma_add_double_ok((oi->imgbb).ymin, lwhalf, &(oi->me));
    if(((oi->c)->opt1) & DKFIG_OPT_KEEP_BITMAP_WH_RATIO) {
      /* correct x0, y0, sfx, sfy */
      dwi = dkma_l_to_double(wi);
      dhi = dkma_l_to_double(hi);
      if(MULD(deltay,dwi,&(oi->me)) > MULD(deltax,dhi,&(oi->me))) {
        sfy = MULD(deltax,DIVD(dhi,dwi,&(oi->me)),&(oi->me));
	switch((((oi->c)->image_align) >> 2) & 3) {
	  case DKFIG_ALIGN_V_TOP: {
	    y0 = ADDD(y0,SUBD(deltay,sfy,&(oi->me)), &(oi->me));
	  } break;
	  case DKFIG_ALIGN_V_CENTERED: {
	    y0 = ADDD(y0,(0.5 * SUBD(deltay,sfy,&(oi->me))), &(oi->me));
	  } break;
	}
      } else {
        sfx = MULD(deltay,DIVD(dwi,dhi,&(oi->me)),&(oi->me));
	switch(((oi->c)->image_align) & 3) {
	  case DKFIG_ALIGN_H_RIGHT: {
	    x0 = ADDD(x0,SUBD(deltax,sfx,&(oi->me)),&(oi->me));
	  } break;
	  case DKFIG_ALIGN_H_CENTERED: {
	    x0 = ADDD(x0,(0.5 * SUBD(deltax,sfx,&(oi->me))),&(oi->me));
	  } break;
	}
      }
    }
    gcs_out(oi, 37); gcs_out(oi, 0);
    /* shift */
    dkstream_puts_ul(oi->gcs, 1UL);
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 1UL);
    gcs_out(oi, 1);
    dkstream_puts_double(oi->gcs, drd(x0,oi->c,1));
    gcs_out(oi, 1);
    dkstream_puts_double(oi->gcs, drd(y0,oi->c,1));
    gcs_out(oi, 1);
    gcs_out(oi, 55); gcs_out(oi, 0);
    /* scale */
    dkstream_puts_double(oi->gcs, drd(sfx,oi->c,1));
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    dkstream_puts_double(oi->gcs, drd(sfy,oi->c,1));
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    dkstream_puts_ul(oi->gcs, 0UL);
    gcs_out(oi, 1);
    gcs_out(oi, 55); gcs_out(oi, 0);
    /* do */
    gcs_out(oi, 35); gcs_out(oi, 45);
    dkfig_tool_num_as_string(oi->gcs, i->objno, oi->nostr);
    gcs_out(oi, 1);
    gcs_out(oi, 101);
    gcs_out(oi, 0);
    gcs_out(oi, 38); gcs_out(oi, 0);
    oi->ci = oldci;
  }
  return back;
}



/**	Write polyline object to gcs.
	@param	oi	OI structure.
*/
static
int create_contents_polyline DK_P1(OI *,oi)
{
  int back = 1;
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    gcs_out(oi, 85);
    dkstream_puts_ul(oi->gcs, (oi->co)->lineno);
    gcs_out(oi, 0);
  }
  if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
    set_lw_and_colors(oi);
    back = write_polyline_path(oi);
    final_keyword(oi);
    both_arrow_heads(oi);
  }
  if(((oi->co)->fpd).st == 5) {
    set_imgbb(oi);
    show_image(oi);
  }
  return back;
}



/**	Write ellipse object to gcs.
	@param	oi	OI structure.
*/
static
int create_contents_ellipse DK_P1(OI *,oi)
{
  int back = 1;
  int is_rotated;
  dk_fig_ellipse *e;
  pdf_arc_calc ac;
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    gcs_out(oi, 86);
    dkstream_puts_ul(oi->gcs, (oi->co)->lineno);
    gcs_out(oi, 0);
  }
  e = (dk_fig_ellipse *)((oi->co)->data);
  if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
    back = 0;
    is_rotated = 0;
    ac.xm = ac.ym = 0.0;
    if(e) {
      back = 1;
      if(fabs(e->angle) > DKFIG_EPSILON) {
        is_rotated = 1;
      }
      set_lw_and_colors(oi);
      ac.rx = fabs(dkma_mul_double_ok(oi->xfactor, e->radiusx, &(oi->me)));
      ac.ry = fabs(dkma_mul_double_ok(oi->yfactor, e->radiusy, &(oi->me)));
      ac.phi0 = 0.0;
      ac.phi1 = 2.0 * M_PI;
      ac.segs = (oi->c)->circlesteps;
      if(ac.segs < 1) ac.segs = 1;
      ac.segs = ac.segs * 4;
      ac.x0 = ac.rx;
      ac.y0 = 0.0;
      if(is_rotated) {
        gcs_out(oi, 37); gcs_out(oi, 0);
	change_ctm(oi,oi->gcs,cclx(oi,e->centerx),ccly(oi,e->centery),e->angle);
      } else {
        ac.xm = cclx(oi,e->centerx);
	ac.ym = ccly(oi,e->centery);
	ac.x0 = dkma_add_double_ok(ac.x0,ac.xm,&(oi->me));
	ac.y0 = dkma_add_double_ok(ac.y0,ac.ym,&(oi->me));
      }
      ac.x0 = drd(ac.x0,oi->c,1);
      ac.y0 = drd(ac.y0,oi->c,1);
      ac.x1 = ac.x0;
      ac.y1 = ac.y0;
      nocdpointout(oi,ac.x0,ac.y0,1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      pdf_arc_path(oi, &ac);
      final_keyword(oi);
      if(is_rotated) {
        gcs_out(oi, 38); gcs_out(oi, 0);
      }
    } else {	
      dkfig_tool2_simple_error_message(oi->c, 44);
    }
  }
  return back;
}



/**	Write spline path to gcs.
	@param	oi	OI structure.
*/
static
void write_spline_path DK_P1(OI *,oi)
{
  dk_fig_spline *s;
  dk_fig_bezier_point *bpptr;
  size_t nsegs, li, ri, maxli;
  s = (dk_fig_spline *)((oi->co)->data);
  if(s) {
    bpptr = s->bpoints; nsegs = s->nbpoints - 1;
    if(((oi->co)->fpd).cl) { nsegs = s->nbpoints; }
    if((!(((oi->co)->fpd).cl)) && (((oi->co)->fpd).ar & 2)) {
      dpointout(oi, (s->pa).value.x, (s->pa).value.y, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      dpointout(oi, (s->pa).rcontrol.x, (s->pa).rcontrol.y, 1);
      dpointout(oi, (s->pa2).lcontrol.x, (s->pa2).lcontrol.y, 1);
      dpointout(oi, (s->pa2).value.x, (s->pa2).value.y, 1);
      gcs_out(oi, 83); gcs_out(oi, 0);
      li = s->normals;
    } else {
      dpointout(oi, bpptr[0].value.x, bpptr[0].value.y, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      li = 0;
    }
    if((s->normale > 0) || (((oi->co)->fpd).cl) || (!((((oi->co)->fpd).ar) & 1))) {
      maxli = s->nbpoints - 2;
      if(((oi->co)->fpd).cl) { maxli = s->nbpoints - 1; }
      if((!(((oi->co)->fpd).cl)) && (((oi->co)->fpd).ar & 1)) {
        maxli = s->normale - 1;
      }
      while(li <= maxli) {
        ri = li + 1;
	if(ri >= s->nbpoints) { ri = 0; }
	dpointout(oi, bpptr[li].rcontrol.x, bpptr[li].rcontrol.y, 1);
	dpointout(oi, bpptr[ri].lcontrol.x, bpptr[ri].lcontrol.y, 1);
	dpointout(oi, bpptr[ri].value.x, bpptr[ri].value.y, 1);
	gcs_out(oi, 83); gcs_out(oi, 0);
        li++;
      }
    }
    if((!(((oi->co)->fpd).cl)) && (((oi->co)->fpd).ar & 1)) {
      dpointout(oi, (s->pe2).rcontrol.x, (s->pe2).rcontrol.y, 1);
      dpointout(oi, (s->pe).lcontrol.x, (s->pe).lcontrol.y, 1);
      dpointout(oi, (s->pe).value.x, (s->pe).value.y, 1);
      gcs_out(oi, 83); gcs_out(oi, 0);
    }
  } else {	
    dkfig_tool2_simple_error_message(oi->c, 44);
  }
}



/**	Write spline object to gcs.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int create_contents_spline DK_P1(OI *,oi)
{
  int back = 1;
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    gcs_out(oi, 87);
    dkstream_puts_ul(oi->gcs, (oi->co)->lineno);
    gcs_out(oi, 0);
  }
  if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
    set_lw_and_colors(oi);
    write_spline_path(oi);
    final_keyword(oi);
    both_arrow_heads(oi);
  }
  return back;
}



/**	Write arc path.
	@param	oi	OI structure.
*/
static
void write_arc_path DK_P1(OI *,oi)
{
  pdf_arc_calc ac;
  dk_fig_arc *a;
  long lsegs;
  
  a = (dk_fig_arc *)((oi->co)->data);
  if(a) {
    lsegs = dkma_double_to_l(
      ceil(
        dkma_mul_double_ok(
	  dkma_l_to_double((oi->c)->circlesteps),
	  dkma_div_double_ok((a->calc).alength,(0.5 * M_PI), &(oi->me)),
	  &(oi->me)
	)
      )
    ); ac.segs = (unsigned)lsegs;
    ac.rx = fabs(dkma_mul_double_ok(oi->xfactor,(a->calc).ra,&(oi->me)));
    ac.ry = ac.rx;
    ac.xm = ccdx(oi, (a->calc).xm);
    ac.ym = ccdy(oi, (a->calc).ym);
    ac.phi0 = (a->calc).astart;
    ac.phi1 = dkma_add_double_ok(ac.phi0, (a->calc).alength, &(oi->me));
    if(!(((oi->co)->fpd).cl)) {		
      if((((oi->co)->fpd).ar) & 2) {	
        ac.phi0 = dkma_add_double_ok(ac.phi0, fabs(a->lba), &(oi->me));
      }
      if((((oi->co)->fpd).ar) & 1) {	
        ac.phi1 = dkma_sub_double_ok(ac.phi1, fabs(a->rba), &(oi->me));
      }
    }
    ac.x0 = dkma_add_double_ok(ac.xm, ac.rx * cos(ac.phi0), &(oi->me));
    ac.y0 = dkma_add_double_ok(ac.ym, ac.ry * sin(ac.phi0), &(oi->me));
    ac.x1 = dkma_add_double_ok(ac.xm, ac.rx * cos(ac.phi1), &(oi->me));
    ac.y1 = dkma_add_double_ok(ac.ym, ac.ry * sin(ac.phi1), &(oi->me));
    ac.x0 = drd(ac.x0, oi->c, 1); ac.y0 = drd(ac.y0, oi->c, 1);
    ac.x1 = drd(ac.x1, oi->c, 1); ac.y1 = drd(ac.y1, oi->c, 1);
    if(((oi->co)->fpd).cl) {
      nocdpointout(oi, ac.xm, ac.ym, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      nocdpointout(oi, ac.x0, ac.y0, 1);
      gcs_out(oi, 67); gcs_out(oi, 0);
    } else {
      nocdpointout(oi, ac.x0, ac.y0, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
    }
    pdf_arc_path(oi, &ac);
  } else {	
    dkfig_tool2_simple_error_message(oi->c, 44);
  } 
}



/**	Write arc object to gcs.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int create_contents_arc DK_P1(OI *,oi)
{
  int back = 1;
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    gcs_out(oi, 88);
    dkstream_puts_ul(oi->gcs, (oi->co)->lineno);
    gcs_out(oi, 0);
  }
  if(must_fill(oi) || must_pattern(oi) || must_stroke(oi)) {
    set_lw_and_colors(oi);
    write_arc_path(oi);
    final_keyword(oi);
    both_arrow_heads(oi);
  }
  return back;
}



/**	Write current object to gcs.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int create_contents_primitive DK_P1(OI *,oi)
{
  int back = 1;
  switch((oi->co)->objtype) {
    case DK_FIG_OBJ_TEXT: {
      back = create_contents_text(oi);
    } break;
    case DK_FIG_OBJ_POLYLINE: {
      back = create_contents_polyline(oi);
    } break;
    case DK_FIG_OBJ_ELLIPSE: {
      back = create_contents_ellipse(oi);
    } break;
    case DK_FIG_OBJ_SPLINE: {
      back = create_contents_spline(oi);
    } break;
    case DK_FIG_OBJ_ARC: {
      back = create_contents_arc(oi);
    } break;
    default: {
      dkfig_tool2_simple_error_message(oi->c, 104);
    } break;
  }
  if(oi->me) {
    back = 0;
    oi->me = 0;
    dkfig_tool2_simple_error_message(oi->c, 13);
  }
  return back;
}



/**	Set clip path.
	@param	oi	OI structure.
*/
static
void set_clip_path DK_P1(OI *,oi)
{
  dkstream_puts_double(oi->gcs, 0.0);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, 0.0);
  gcs_out(oi, 1);
  gcs_out(oi, 66);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, oi->xright);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, 0.0);
  gcs_out(oi, 1);
  gcs_out(oi, 67);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, oi->xright);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, oi->ytop);
  gcs_out(oi, 1);
  gcs_out(oi, 67);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, 0.0);
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, oi->ytop);
  gcs_out(oi, 1);
  gcs_out(oi, 67);
  gcs_out(oi, 1);
  gcs_out(oi, 103);
  gcs_out(oi, 0);
}



/**	Write all graphics objects to gcs.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int create_contents_stream DK_P1(OI *,oi)
{
  int back = 1;
  dk_fig_object *o;
  unsigned long backupopt1, backupopt2;
  int backupia;
  
  dkstream_set_double_no_exponent(oi->gcs, 1);
  gcs_out(oi, 37); gcs_out(oi, 0);
  set_clip_path(oi);
  dksto_it_reset(oi->fli);
  oi->co = NULL;
  while((o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, o->lineno);
    }
    backupopt1 = (oi->c)->opt1;
    backupopt2 = (oi->c)->opt2;
    backupia = (oi->c)->image_align;
    oi->co = o;
    if(!create_contents_primitive(oi)) {
      back = 0;
    }
    (oi->c)->opt1 = backupopt1;
    (oi->c)->opt2 = backupopt2;
    (oi->c)->image_align = backupia;
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
  } oi->co = NULL;
  gcs_out(oi, 38); gcs_out(oi, 0);
  back = 1;
  
  return back;
}



/**	Copy data file to gcs.
	@param	oi	OI structure.
	@param	buffer	Copy buffer.
	@param	lgt	Buffer length.
	@return	1 on success, 0 on error.
*/
static
int copy_file_to_stream DK_P3(OI *,oi, char *,buffer, unsigned long,lgt)
{
  int back = 0;
  FILE *fipo;
  char smallbuf[256], *bigbuf, *buf;
  size_t buflgt, rdbytes; int cc; unsigned long summary;
  
  fipo = dkapp_fopen((oi->c)->app, buffer, str_open_read_binary);
  if(fipo) {
    bigbuf = dk_new(char, 4096);
    if(bigbuf) {
      buf = bigbuf; buflgt = 4096;
    } else {
      buf = smallbuf; buflgt = 256;
    }
    cc = 1; summary = 0UL; back = 1;
    while((cc == 1) && (summary < lgt)) {
      rdbytes = buflgt;
      if(((unsigned long)rdbytes) > (lgt - summary)) {
        rdbytes = (size_t)(lgt - summary);
      }
      rdbytes = fread(buf, 1, rdbytes, fipo);
      if(rdbytes) {
        if(dkstream_write(oi->s, buf, rdbytes) != rdbytes) {
	  cc = 0;
	} else {
	  summary += (unsigned long)rdbytes;
	  if(summary >= lgt) {
	    back = 1; cc = 0;
	  }
	}
      } else {
        cc = 0;
      }
    }
    if(bigbuf) {
      dk_delete(bigbuf); bigbuf = NULL;
    }
    fclose(fipo);
    if(!back) {
      dkfig_tool2_simple_error_message(oi->c, 105);
    }
  } else {
    if((oi->c)->app) {
      dkapp_err_fopenr((oi->c)->app, buffer);
    }
  } 
  return back;
}



/**	Write graphics stream.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int write_graphics_stream DK_P1(OI *,oi)
{
  int back = 0;
  char *buffer; size_t lgt; unsigned long streamlgt;
  
  if((oi->c)->app) {
    lgt = dksf_get_maxpathlen();
    buffer = dk_new(char,lgt);
    if(buffer) {
      if(dkapp_tmpnam((oi->c)->app, buffer, lgt)) {
        dk_stream_t *plainfile;
	
	oi->gcs = NULL;
	plainfile = dkapp_stream_openfile(
	  (oi->c)->app, buffer, str_open_write_binary
	);
	if(plainfile) {
	  if(((oi->c)->opt2) & DKFIG_OPT_PLAIN_TEXT_STREAMS) {
	    oi->gcs = plainfile;
	    back = create_contents_stream(oi);
	  } else {
	    dk_stream_t *compressedfile;
	    compressedfile = dkof_open(plainfile, 3);
	    if(compressedfile) {
	      dkof_set_crnl(compressedfile, 1);
	      back = 1;
	      if(!dkof_set(compressedfile,0,DK_OF_TYPE_BUFFERED)) { back = 0; }
	      if(!dkof_set(compressedfile,1,DK_OF_TYPE_ASCII85)) { back = 0; }
	      if(!dkof_set(compressedfile,2,DK_OF_TYPE_FLATE)) { back = 0; }
	      if(back) {
	        back = 0;
		if(dkof_start_chunk(compressedfile)) {
		  oi->gcs = compressedfile;
		  back = create_contents_stream(oi);
		  if(!dkof_end_chunk(compressedfile)) {
		    back = 0;
                    dkfig_tool2_simple_error_message(oi->c, 74);
		  }
		} else {
		  dkfig_tool2_simple_error_message(oi->c, 73);
		}
	      } else {
		dkfig_tool2_simple_error_message(oi->c, 72);
	      }
	      dkof_close(compressedfile);
	      compressedfile = NULL;
	    } else {
	      dkfig_tool2_simple_error_message(oi->c, 72);
	    }
	  }
	  streamlgt = dkstream_get_bytes_written(plainfile);
	  dkstream_close(plainfile); plainfile = NULL;
	  if(back) {
            kw_out(oi, 5); kw_out(oi, 1);
	    kw_out(oi, 39); kw_out(oi, 1);
	    dkstream_puts_ul(oi->s, streamlgt);
	    if(!(((oi->c)->opt2) & DKFIG_OPT_PLAIN_TEXT_STREAMS)) {
	      kw_out(oi, 1);
              kw_out(oi, 40);
	    }
	    kw_out(oi, 1); kw_out(oi, 6); kw_out(oi, 0);
	    kw_out(oi, 41); kw_out(oi, 0);
	    back = copy_file_to_stream(oi, buffer, streamlgt);
	    kw_out(oi, 42); kw_out(oi, 0);
	    dksf_remove_file(buffer);
	  }
	} else {
	  if((oi->c)->app) {
	    dkapp_err_fopenw((oi->c)->app, buffer);
	  }
	}
	oi->gcs = NULL;
      } else {
	dkfig_tool2_simple_error_message(oi->c, 67);
      }
      dk_delete(buffer); buffer = NULL;
    } else {
      if((oi->c)->app) {
        dkapp_err_memory((oi->c)->app,sizeof(char),lgt);
      }
    }
  } else {	
    dkfig_tool2_simple_error_message(oi->c, 44);
  } 
  return back;
}



/**	Write font definitions to resources dictionary.
	@param	oi	OI structure.
*/
static
void write_fonts DK_P1(OI *,oi)
{
  int i, is_first;
  is_first = 1;
  for(i = 0; i < 14; i++) {
    if((oi->fu)[i]) {
      if(is_first) {
        kw_out(oi, 44); kw_out(oi, 1);
	kw_out(oi, 5); kw_out(oi, 0);
      }
      is_first = 0;
      kw_out(oi, 35); kw_out(oi, 45);
      dkfig_tool_num_as_string(oi->s, (oi->fu)[i], oi->nostr);
      kw_out(oi, 1);
      dkstream_puts_ul(oi->s, (oi->fu)[i]);
      kw_out(oi, 1); kw_out(oi, 19);
      kw_out(oi, 1); kw_out(oi, 13);
      kw_out(oi, 0);
    }
  }
  if(!is_first) {
    kw_out(oi, 6); kw_out(oi, 0);
  }
}



/**	Write pattern definitions to resource dictionary.
	@param	oi	OI structure.
*/
static
void
write_patterns DK_P1(OI *,oi)
{
  int is_first = 1;
  dkfig_pdf_pattern *patp;
  dksto_it_reset(oi->patli);
  while((patp = (dkfig_pdf_pattern *)dksto_it_next(oi->patli)) != NULL) {
    if(is_first) {
      is_first = 0;
      kw_out(oi, 34); kw_out(oi, 1); kw_out(oi, 5); kw_out(oi, 0);
    }
    kw_out(oi, 35); kw_out(oi, 45);
    dkfig_tool_num_as_string(oi->s, patp->objno, oi->nostr);
    kw_out(oi, 1);
    dkstream_puts_ul(oi->s, patp->objno);
    kw_out(oi, 1); kw_out(oi, 19);
    kw_out(oi, 1); kw_out(oi, 13);
    kw_out(oi, 0);
  }
  if(!is_first) {
    kw_out(oi, 6); kw_out(oi, 0);
  }
}



/**	Write image definitions to resource dictionary.
	@param	oi	OI structure.
*/
static
void write_images DK_P1(OI *,oi)
{
  int is_first = 1;
  dkfig_pdf_image *imgp;
  dksto_it_reset(oi->imgli);
  while((imgp = (dkfig_pdf_image *)dksto_it_next(oi->imgli)) != NULL) {
    if(is_first) {
      is_first = 0;
      kw_out(oi, 33); kw_out(oi, 1);
      kw_out(oi, 5); kw_out(oi, 0);
    }
    kw_out(oi, 35); kw_out(oi, 45);
    dkfig_tool_num_as_string(oi->s, imgp->objno, oi->nostr);
    kw_out(oi, 1);
    dkstream_puts_ul(oi->s, imgp->objno);
    kw_out(oi, 1); kw_out(oi, 19);
    kw_out(oi, 1); kw_out(oi, 13);
    kw_out(oi, 0);
  }
  if(!is_first) {
    kw_out(oi, 6); kw_out(oi, 0);
  }
}



/**	Write font definition objects to output stream (os).
	@param	oi	OI structure.
*/
static
int write_font_objects DK_P1(OI *,oi)
{
  int back = 1;
  int i;
  for(i = 0; i < 14; i++) {
    if((oi->fu)[i]) {
      if(begin_object(oi, (oi->fu)[i])) {
        kw_out(oi, 5); kw_out(oi, 1);
	kw_out(oi, 46);
	dkstream_puts(oi->s, pdf_font_names[i]);
	kw_out(oi, 1);
	kw_out(oi, 6); kw_out(oi, 0);
        end_object(oi);
      } else {
        back = 0;
      }
    }
  }
  return back;
}



/**	Data for one pattern.
*/
typedef struct {
  double patrp;		/**< Pattern repeat distance. */
  double lt;		/**< Line type. */
  double w;		/**< Pattern width. */
  double h;		/**< Pattern height. */
  int    tiled;		/**< Flag: Pattern tiled. */
} PATD;



/**	Fill a rectangle.
	@param	oi	OI structure.
	@param	x1	Left x.
	@param	y1	Bottom y.
	@param	x2	Right x.
	@param	y2	Top y.
*/
static
void fill_rect DK_P5(OI *,oi, double,x1, double,y1, double,x2, double,y2)
{
  dkstream_puts_double(oi->gcs, drd(x1,oi->c,2));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(y1,oi->c,2));
  gcs_out(oi, 1); gcs_out(oi, 66); gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(x2,oi->c,2));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(y1,oi->c,2));
  gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(x2,oi->c,2));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(y2,oi->c,2));
  gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(x1,oi->c,2));
  gcs_out(oi, 1);
  dkstream_puts_double(oi->gcs, drd(y2,oi->c,2));
  gcs_out(oi, 1); gcs_out(oi, 67); gcs_out(oi, 1);
  gcs_out(oi, 68); gcs_out(oi, 1);
  gcs_out(oi, 69); gcs_out(oi, 0);
}



/**	Draw a line.
	@param	oi	OI structure.
	@param	x0	Point 1 x.
	@param	y0	Point 1 y.
	@param	x1	Point 2 x.
	@param	y1	Point 2 y.
	@param	cr	Digit restriction
	(1=coordinate, 2=trigonometric, default=color).
*/
static
void draw_line DK_P6(OI *,oi,double,x0,double,y0,double,x1,double,y1,int,cr)
{
  nocdpointout(oi, x0, y0, cr);
  gcs_out(oi, 66); gcs_out(oi, 1);
  nocdpointout(oi, x1, y1, cr);
  gcs_out(oi, 67); gcs_out(oi, 1);
  gcs_out(oi, 70); gcs_out(oi, 0);
}



/**	Write fill pattern 41 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_41 DK_P2(OI *,oi, PATD *,p)
{
  int cc;
  double x, xstep, xend, x0, y0, x1, y1, f1, ystep;
  cc = 1;
  x = p->patrp;
  f1 = tan(M_PI / 6.0);
  xstep = 2.0 * p->patrp;
  if(p->tiled) {
    ystep = dkma_mul_double_ok(xstep, f1, &(oi->me));
    ystep = drd(ystep,oi->c,2);
    draw_line(oi, 0.0, ystep, xstep, 0.0, 2);
    draw_line(oi,(0.5 * xstep),(1.5 * ystep),(1.5 * xstep),(0.5 * ystep), 1);
    draw_line(oi,(-0.5 * xstep),(0.5 * ystep),(0.5 * xstep),(-0.5 * ystep), 1);
    p->w = xstep; p->h = ystep;
  } else {
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    while(cc) {
      x0 = x;   y0 = 0.0;
      x1 = 0.0;
      y1 = dkma_mul_double_ok(x0, f1, &(oi->me));
      if(y1 > oi->ytop) {
        y1 = oi->ytop;
	x1 = dkma_sub_double_ok(
	  x,
	  dkma_div_double_ok(oi->ytop, f1, &(oi->me)),
	  &(oi->me)
	);
        if(x1 > xend) {
          cc = 0;
        }
      }
      if(cc) {
        if(x0 > oi->xright) {
          x0 = oi->xright;
	  y0 = dkma_mul_double_ok(
	    f1,
	    dkma_sub_double_ok(x, oi->xright, &(oi->me)),
	    &(oi->me)
	  );
        }
        draw_line(oi, x0, y0, x1, y1, 1);
      }
      x += xstep;
    }
  }
}


  
/**	Write fill pattern 42 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_42 DK_P2(OI *,oi, PATD *,p)
{
  int cc;
  double x, xstep, xend, x0, y0, x1, y1, f1, ystep;
  
  xstep = dkma_mul_double_ok(2.0, p->patrp, &(oi->me));
  f1 = tan(M_PI / 6.0);
  if(p->tiled) {
    ystep = dkma_mul_double_ok(f1, xstep, &(oi->me));
    ystep = drd(ystep,oi->c,2);
    p->w = xstep; p->h = ystep;
    draw_line(oi, 0.0, 0.0, xstep, ystep, 2);
    draw_line(oi, (-0.5*xstep), (0.5*ystep), (0.5*xstep), (1.5*ystep), 2);
    draw_line(oi, (0.5*xstep), (-0.5*ystep), (1.5*xstep), (0.5*ystep), 2);
  } else {
    cc = 1;
    x = dkma_sub_double_ok(oi->xright, p->patrp, &(oi->me));
    xend = 0.0 - 0.5 * p->lt;
    while(cc) {
      x0 = x; y0 = 0.0;
      x1 = oi->xright;
      y1 = dkma_mul_double_ok(
        f1,
	dkma_sub_double_ok(oi->xright, x, &(oi->me)),
	&(oi->me)
      );
      if(y1 > oi->ytop) {
        y1 = oi->ytop;
	x1 = dkma_add_double_ok(
	  x,
	  dkma_div_double_ok(oi->ytop, f1, &(oi->me)),
	  &(oi->me)
	);
        if(x1 < xend) {
          cc = 0;
        }
      }
      if(cc) {
        if(x0 < 0.0) {
          x0 = 0.0;
	  y0 = dkma_mul_double_ok(f1, (0.0 - x), &(oi->me));
        }
        draw_line(oi, x0, y0, x1, y1, 1);
      }
      x -= xstep;
    }
  } 
}



/**	Write fill pattern 44 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_44 DK_P2(OI *,oi, PATD *,p)
{
  int cc;
  double x, xstep, xend, x0, y0, x1, y1;
  cc = 1;
  xstep = sqrt(2.0) * p->patrp;
  if(p->tiled) {
    p->w = p->h = drd(xstep,oi->c,2);
    draw_line(oi, 0.0, xstep, xstep, 0.0, 2);
    draw_line(oi, (0.5*xstep), (1.5*xstep), (1.5*xstep), (0.5*xstep), 2);
    draw_line(oi, (-0.5*xstep), (0.5*xstep), (0.5*xstep), (-0.5*xstep), 2);
  } else {
    x = 0.5 * xstep;
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    while(cc) {
      x0 = x;   y0 = 0.0;
      x1 = 0.0; y1 = x0;
      if(y1 > oi->ytop) {
        y1 = oi->ytop;
	x1 = dkma_sub_double_ok(x, oi->ytop, &(oi->me));
        if(x1 > xend) {
          cc = 0;
        }
      }
      if(cc) {
        if(x0 > oi->xright) {
          x0 = oi->xright;
	  y0 = dkma_sub_double_ok(x, oi->xright, &(oi->me));
        }
        draw_line(oi, x0, y0, x1, y1, 1);
      }
      x += xstep;
    }
  }
}



/**	Write fill pattern 45 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_45 DK_P2(OI *,oi, PATD *,p)
{
  int cc;
  double x, xstep, xend, x0, y0, x1, y1;
  
  cc = 1;
  xstep = dkma_mul_double_ok(sqrt(2.0), p->patrp, &(oi->me));
  if(p->tiled) {
    xstep = drd(xstep,oi->c,2);
    p->w = p->h = xstep;
    draw_line(oi, 0.0, 0.0, xstep, xstep, 2);
    draw_line(oi, (-0.5*xstep), (0.5*xstep), (0.5*xstep),(1.5*xstep),2);
    draw_line(oi, (0.5*xstep), (-0.5*xstep), (1.5*xstep),(0.5*xstep),2);
  } else {
    xend = 0.0 - 0.5 * p->lt;
    x = dkma_sub_double_ok(oi->xright, (0.5 * xstep), &(oi->me));
    while(cc) {
      x0 = x; y0 = 0.0;
      x1 = oi->xright;
      y1 = dkma_sub_double_ok(oi->xright, x, &(oi->me));
      if(y1 > oi->ytop) {
        y1 = oi->ytop;
	x1 = dkma_add_double_ok(x, oi->ytop, &(oi->me));
        if(x1 < xend) {
          cc = 0;
        }
      }
      if(cc) {
        if(x0 < 0.0) {
          x0 = 0.0;
	  y0 = 0.0 - x;
        }
        draw_line(oi, x0, y0, x1, y1, 1);
      }
      x -= xstep;
    }
  } 
}



/**	Write fill pattern 49 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_49 DK_P2(OI *,oi, PATD *,p)
{
  double y, yend, ystep;
  y = 0.0;
  ystep = drd(p->patrp,oi->c,1);
  if(p->tiled) {
    draw_line(oi, 0.0, 0.0, oi->xright, 0.0, 1);
    draw_line(oi, 0.0, ystep, oi->xright, ystep, 1);
    p->w = oi->xright;
    p->h = ystep;
  } else {
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    while(y < yend) {
      draw_line(oi, 0.0, y, oi->xright, y, 1);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
  }
}



/**	Write fill pattern 50 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_50 DK_P2(OI *,oi, PATD *,p)
{
  double x, xend, xstep;
  x = 0.0;
  xstep = drd(p->patrp,oi->c,1);
  if(p->tiled) {
    p->w = xstep; p->h = oi->ytop;
    draw_line(oi, 0.0, 0.0, 0.0, oi->ytop, 1);
    draw_line(oi, xstep, 0.0, xstep, oi->ytop, 1);
  } else {
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    while(x < xend) {
      draw_line(oi, x, 0.0, x, oi->ytop, 1);
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
  }
}



/**	Write fill pattern 51 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_51_c DK_P2(OI *,oi, PATD *,p)
{
  double x, ystep, xstep;
  x = 0.0;
  ystep = xstep = drd(p->patrp,oi->c,1);
  p->w = xstep; p->h = ystep;
  nocdpointout(oi, 0.0, 0.0, 1);
  gcs_out(oi, 66); gcs_out(oi, 1);
  nocdpointout(oi, xstep, 0.0, 1);
  gcs_out(oi, 67); gcs_out(oi, 1);
  nocdpointout(oi, xstep, ystep, 1);
  gcs_out(oi, 67); gcs_out(oi, 1);
  nocdpointout(oi, 0.0, ystep, 1);
  gcs_out(oi, 67); gcs_out(oi, 1);
  gcs_out(oi, 68); gcs_out(oi, 1);
  gcs_out(oi, 70); gcs_out(oi, 0);
}



/**	Write fill pattern 47 (a) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_47_a DK_P2(OI *,oi, PATD *,p)
{
  double y, yend, ystep;
  
  y = 0.0;
  ystep = drd(p->patrp,oi->c,1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  yend = dkma_add_double_ok(
    oi->ytop,
    (0.5 * p->lt),
    &(oi->me)
  );
  while(y < yend) {
    draw_line(oi, 0.0, y, oi->xright, y, 1);
    y = dkma_add_double_ok(y, ystep, &(oi->me));
  }
  
}



/**	Write fill pattern 47 (c) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_47_c DK_P2(OI *,oi, PATD *,p)
{
  double ystep, xshift, xstep;
  
  xshift = ystep = drd(p->patrp, oi->c, 1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  xstep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  ll_set_linecap(oi, 2);
  draw_line(oi, 0.0, 0.0, xstep, 0.0, 1);
  draw_line(oi, 0.0, ystep, xstep, ystep, 1);
  draw_line(oi, 0.0, xstep, xstep, xstep, 1);
  ll_set_linecap(oi, 0);
  draw_line(oi, xshift, 0.0, xshift, ystep, 1);
  xshift = dkma_mul_double_ok(xshift, 3.0, &(oi->me));
  draw_line(oi, xshift, ystep, xshift, (2.0 * ystep), 1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  p->w = xstep; p->h = ystep;
  
}



/**	Write fill pattern 47 (b) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_47_b DK_P2(OI *,oi, PATD *,p)
{
  double y, yend, ystep;
  double x, xend, xstep, xini;
  int i;
  
  y = 0.0;
  xini = ystep = drd(p->patrp,oi->c,1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  xstep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  i = 0;
  while(y < yend) {
    
    if(i) {
      x = xini; i = 0;
    } else {
      x = 3.0 * xini; i = 1;
    } 
    while(x < xend) {
      
      draw_line(oi, x, y, x, (y + ystep), 1);
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
    y += ystep;
  } 
}



/**	Write fill pattern 48 (a) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_48_a DK_P2(OI *,oi, PATD *,p)
{
  double x, xend, xstep, yini, ystep, yend;
  x = 0.0;
  yini = xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ystep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  yend = oi->ytop + 0.5 * p->lt;
  yend = dkma_add_double_ok(oi->ytop,(0.5 * p->lt),&(oi->me));
  while(x < xend) {
    draw_line(oi, x, 0.0, x, oi->ytop, 1);
    x = dkma_add_double_ok(x,xstep,&(oi->me));
  }
}



/**	Write fill pattern 48 (c) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_48_c DK_P2(OI *,oi, PATD *,p)
{
  double xstep, ystep, yshift;
  yshift = xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ystep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ll_set_linecap(oi,2);
  draw_line(oi, 0.0, 0.0, 0.0, ystep, 1);
  draw_line(oi, xstep, 0.0, xstep, ystep, 1);
  draw_line(oi, ystep, 0.0, ystep, ystep, 1);
  ll_set_linecap(oi, 0);
  draw_line(oi, 0.0, yshift, xstep, yshift, 1);
  yshift = dkma_mul_double_ok(3.0, yshift, &(oi->me));
  draw_line(oi, xstep, yshift, ystep, yshift, 1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  p->w = xstep; p->h = ystep;
}



/**	Write fill pattern 48 (b) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_48_b DK_P2(OI *,oi, PATD *,p)
{
  double x, xend, xstep, y, yini, ystep, yend; int i;
  x = 0.0; i = 0;
  yini = xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ystep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  xend = dkma_add_double_ok(
    oi->xright,
    (0.5 * p->lt),
    &(oi->me)
  );
  yend = dkma_add_double_ok(
    oi->ytop,
    (0.5 * p->lt),
    &(oi->me)
  );
  while(x < xend) {
    /* draw_line(oi, x, 0.0, x, oi->ytop, 1); */
    if(i) {
      i = 0; y = yini;
    } else {
      i = 1;
      y = dkma_mul_double_ok(3.0, yini, &(oi->me));
    }
    while(y < yend) {
      draw_line(oi, x, y, (x+xstep), y, 1);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
    x = dkma_add_double_ok(x, xstep, &(oi->me));
  }
}



/**	Write fill pattern 52 (b) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_52_b DK_P2(OI *,oi, PATD *,p)
{
  double y, yend, ystep;
  double x, xend, xstep, xini, xshift;
  int i;
  
  x = y = xend = yend = xstep = ystep = xini = xshift = 0.0;
  xshift = xini = ystep = drd(p->patrp,oi->c,1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  yend  = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  xstep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  xend  = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  i = 0;
  while(y < yend) {
    
    switch(i) {
      case 0: { i = 1; x = 0.0; } break;
      case 1: { i = 2;
        x = dkma_mul_double_ok(3.0, xini, &(oi->me));
      } break;
      case 2: { i = 3;
        x = dkma_mul_double_ok(2.0, xini, &(oi->me));
      } break;
      case 3: { i = 0; x = xini; } break;
    }
    
    while(x < xend) {
      
      draw_line(oi, x, y, (x+xshift), (y + ystep), 1);
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
    y = dkma_add_double_ok(y, ystep, &(oi->me));
  } 
}



/**	Write fill pattern 52 (tiled) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_52_tiled DK_P2(OI *,oi, PATD *,p)
{
  double xstep, ystep, xini, xi2, xi3, xi4, xi5, xi6, xi8;
  xini = drd(p->patrp,oi->c,1);
  xi8 = ystep = dkma_mul_double_ok(8.0, xini, &(oi->me));
  xi4 = xstep = dkma_mul_double_ok(4.0, xini, &(oi->me));
  xi2 = dkma_mul_double_ok(2.0, xini, &(oi->me));
  xi3 = dkma_mul_double_ok(3.0, xini, &(oi->me));
  xi5 = dkma_mul_double_ok(5.0, xini, &(oi->me));
  xi6 = dkma_mul_double_ok(6.0, xini, &(oi->me));
  p->w = xstep; p->h = ystep;
  ll_set_linecap(oi, 1);
  draw_line(oi, 0.0, 0.0, xstep, 0.0, 1);
  draw_line(oi, 0.0, xi2, xstep, xi2, 1);
  draw_line(oi, 0.0, xi4, xstep, xi4, 1);
  draw_line(oi, 0.0, xi6, xstep, xi6, 1);
  draw_line(oi, 0.0, xi8, xstep, xi8, 1);
  draw_line(oi, 0.0, 0.0, xini, xi2, 1);
  draw_line(oi, xi3, xi2, xi4, xi4, 1);
  draw_line(oi, xi2, xi4, xi3, xi6, 1);
  draw_line(oi, xini, xi6, xi2, xi8, 1);
  draw_line(oi, xi4, 0.0, xi5, xi2, 1);
  draw_line(oi, (-1.0*xini), xi2, 0.0, xi4, 1);
}



/**	Write fill pattern 53 (tiled) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_53_tiled DK_P2(OI *,oi, PATD *,p)
{
  double xstep, ystep, xini, xi2, xi3, xi4, xi5, xi6, xi8;
  xini = drd(p->patrp,oi->c,1);
  xi8 = ystep = dkma_mul_double_ok(8.0, xini, &(oi->me));
  xi4 = xstep = dkma_mul_double_ok(4.0, xini, &(oi->me));
  xi2 = dkma_mul_double_ok(2.0, xini, &(oi->me));
  xi3 = dkma_mul_double_ok(3.0, xini, &(oi->me));
  xi5 = dkma_mul_double_ok(5.0, xini, &(oi->me));
  xi6 = dkma_mul_double_ok(6.0, xini, &(oi->me));
  p->w = xstep; p->h = ystep;
  ll_set_linecap(oi, 1);
  draw_line(oi, 0.0, 0.0, xstep, 0.0, 1);
  draw_line(oi, 0.0, xi2, xstep, xi2, 1);
  draw_line(oi, 0.0, xi4, xstep, xi4, 1);
  draw_line(oi, 0.0, xi6, xstep, xi6, 1);
  draw_line(oi, 0.0, xi8, xstep, xi8, 1);
  draw_line(oi, 0.0, xi2, xini, 0.0, 1);
  draw_line(oi, xini, xi4, xi2, xi2, 1);
  draw_line(oi, xi2, xi6, xi3, xi4, 1);
  draw_line(oi, xi3, xi8, xi4, xi6, 1);
  draw_line(oi, xi4, xi2, xi5, 0.0, 1);
  draw_line(oi, (-1.0*xini), xi8, 0.0, xi6, 1);
}



/**	Write fill pattern 53 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_53_b DK_P2(OI *,oi, PATD *,p)
{
  double y, yend, ystep;
  double x, xend, xstep, xini, xshift;
  int i;
  
  x = y = 0.0;
  xshift = xini = ystep = drd(p->patrp,oi->c,1);
  ystep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  xstep = dkma_mul_double_ok(2.0, ystep, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  i = 0;
  while(y < yend) {
    
    switch(i) {
      case 0: { i = 1; x = 0.0; } break;
      case 1: { i = 2; x = xini; } break;
      case 2: { i = 3; x = dkma_mul_double_ok(2.0,xini,&(oi->me)); } break;
      case 3: { i = 0; x = dkma_mul_double_ok(3.0,xini,&(oi->me)); } break;
    }
    
    while(x < xend) {
      
      draw_line(oi, (x+xshift), y, x, (y + ystep), 1);
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
    y = dkma_add_double_ok(y, ystep, &(oi->me));
  } 
}



/**	Write fill pattern 54 (b) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_54_b DK_P2(OI *,oi, PATD *,p)
{
  double x, xend, xstep, y, yini, ystep, yend, yshift; int i;
  x = xend = xstep = y = yini = ystep = yend = yshift = 0.0;
  i = 0;
  yshift = yini = xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ystep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  while(x < xend) {
    switch(i) {
      case 0: {
        i = 1; y = 0.0;
      } break;
      case 1: {
        i = 2; y = yini;
      } break;
      case 2: {
        i = 3; y = dkma_mul_double_ok(2.0, yini, &(oi->me));
      } break;
      case 3: {
        i = 0; y = dkma_mul_double_ok(3.0, yini, &(oi->me));
      } break;
    }
    while(y < yend) {
      draw_line(oi, x, (y+yshift), (x+xstep), y, 1);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
    x = dkma_add_double_ok(x, xstep, &(oi->me));
  }
}



/**	Write fill pattern 55 (b) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_55_b DK_P2(OI *,oi, PATD *,p)
{
  double x, xend, xstep, y, yini, ystep, yend, yshift; int i;
  x = xend = xstep = y = yini = ystep = yend = yshift = 0.0;
  i = 0;
  yshift = yini = xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  ystep = dkma_mul_double_ok(2.0, xstep, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  while(x < xend) {
    switch(i) {
      case 0: {
        i = 1; y = dkma_mul_double_ok(3.0, yini, &(oi->me));
      } break;
      case 1: {
        i = 2; y = dkma_mul_double_ok(2.0, yini, &(oi->me));
      } break;
      case 2: {
        i = 3; y = yini;
      } break;
      case 3: {
        i = 0; y = 0.0;
      } break;
    }
    while(y < yend) {
      draw_line(oi, x, y, (x+xstep), (y+yshift), 1);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
    x = dkma_add_double_ok(x, xstep, &(oi->me));
  }
}



/**	Write fill pattern 54 (tiled) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_54_tiled DK_P2(OI *,oi, PATD *,p)
{
  double yini, xstep, ystep, yi2, yi3, yi4, yi5, yi6, yi8;
  yini = drd(p->patrp,oi->c,1);
  yi8 = xstep = dkma_mul_double_ok(8.0, yini, &(oi->me));
  yi4 = ystep = dkma_mul_double_ok(4.0, yini, &(oi->me));
  yi2 = dkma_mul_double_ok(2.0, yini, &(oi->me));
  yi3 = dkma_mul_double_ok(3.0, yini, &(oi->me));
  yi5 = dkma_mul_double_ok(5.0, yini, &(oi->me));
  yi6 = dkma_mul_double_ok(6.0, yini, &(oi->me));
  p->w = xstep; p->h = ystep;
  draw_line(oi, 0.0, 0.0, 0.0, ystep, 1);
  draw_line(oi, yi2, 0.0, yi2, ystep, 1);
  draw_line(oi, yi4, 0.0, yi4, ystep, 1);
  draw_line(oi, yi6, 0.0, yi6, ystep, 1);
  draw_line(oi, yi8, 0.0, yi8, ystep, 1);
  draw_line(oi, 0.0, yi2, yi2, yini, 1);
  draw_line(oi, yi2, yi3, yi4, yi2, 1);
  draw_line(oi, yi4, yi4, yi6, yi3, 1);
  draw_line(oi, yi6, yini, yi8, 0.0, 1);
  draw_line(oi, yi4, 0.0, yi6, (-1.0*yini), 1);
  draw_line(oi, yi6, yi5, yi8, yi4, 1);
}



/**	Write fill pattern 55 (tiled) to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_55_tiled DK_P2(OI *,oi, PATD *,p)
{
  double yini, xstep, ystep, yi2, yi3, yi4, yi5, yi6, yi8;
  yini = drd(p->patrp,oi->c,1);
  yi8 = xstep = dkma_mul_double_ok(8.0, yini, &(oi->me));
  yi4 = ystep = dkma_mul_double_ok(4.0, yini, &(oi->me));
  yi2 = dkma_mul_double_ok(2.0, yini, &(oi->me));
  yi3 = dkma_mul_double_ok(3.0, yini, &(oi->me));
  yi5 = dkma_mul_double_ok(5.0, yini, &(oi->me));
  yi6 = dkma_mul_double_ok(6.0, yini, &(oi->me));
  p->w = xstep; p->h = ystep;
  draw_line(oi, 0.0, 0.0, 0.0, ystep, 1);
  draw_line(oi, yi2, 0.0, yi2, ystep, 1);
  draw_line(oi, yi4, 0.0, yi4, ystep, 1);
  draw_line(oi, yi6, 0.0, yi6, ystep, 1);
  draw_line(oi, yi8, 0.0, yi8, ystep, 1);
  draw_line(oi, 0.0, yi3, yi2, yi4, 1);
  draw_line(oi, yi2, yi2, yi4, yi3, 1);
  draw_line(oi, yi4, yini, yi6, yi2, 1);
  draw_line(oi, yi6, 0.0, yi8, yini, 1);
  draw_line(oi, 0.0, (-1.0*yini), yi2, 0.0, 1);
  draw_line(oi, yi6, yi5, yi8, yi4, 1);
}



/**	Write fill pattern 58 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_58 DK_P2(OI *,oi, PATD *,p)
{
  pdf_arc_calc ac;
  double x, y, xstep, ystep, xend, yend, r;
  r = 2.0 * p->patrp;
  r = drd(r,oi->c,1);
  xstep = ystep = 2.0 * r;
  if(p->tiled) {
    p->w = xstep; p->h = ystep;
    ac.xm = r; ac.ym = r;
    ac.rx = r; ac.ry = r;
    ac.phi0 = 0.0; ac.phi1 = 2.0 * M_PI;
    ac.segs = 4 * (oi->c)->circlesteps;
    ac.x0 = ac.x1 = dkma_mul_double_ok(2.0, r, &(oi->me));
    ac.y0 = ac.y1 = r;
    nocdpointout(oi, ac.x0, ac.y0, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    pdf_arc_path(oi, &ac);
    gcs_out(oi, 68); gcs_out(oi, 1);
    gcs_out(oi, 70); gcs_out(oi, 0);
  } else {
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    x = 0.0;
    while(x < xend) {
      y = 0.0;
      while(y < yend) {
        ac.xm = dkma_add_double_ok(x, r, &(oi->me));
        ac.ym = dkma_add_double_ok(y, r, &(oi->me));
        ac.rx = ac.ry = r;
        ac.phi0 = 0.0;
        ac.phi1 = 2.0 * M_PI;
        ac.segs = 4 * (oi->c)->circlesteps;
        ac.x0 = ac.x1 = dkma_add_double_ok(ac.xm, r, &(oi->me));
        ac.y0 = ac.y1 = ac.ym;
        nocdpointout(oi, ac.x0, ac.y0, 1);
        gcs_out(oi, 66); gcs_out(oi, 0);
        pdf_arc_path(oi, &ac);
        gcs_out(oi, 68); gcs_out(oi, 1);
        gcs_out(oi, 70); gcs_out(oi, 0);
	y = dkma_add_double_ok(y, ystep, &(oi->me));
      }
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
  }
}



/**	Write fill pattern 59 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_59 DK_P2(OI *,oi, PATD *,p)
{
  double r, x, y, x1, x2, x3, x4, y1, y2;
  double xstep, ystep, xend, yend;
  r = dkma_mul_double_ok(2.0, p->patrp, &(oi->me));
  r = drd(r, oi->c, 1);
  ystep = dkma_mul_double_ok(2.0, r, &(oi->me));
  r = dkma_mul_double_ok(2.0, r, &(oi->me)) / sqrt(3.0);
  xstep = dkma_mul_double_ok(3.0, r, &(oi->me));
  xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
  yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
  x = 0.0;
  if(p->tiled) {
    y = 0.0;
    x1 = dkma_add_double_ok(x, (0.5 * r), &(oi->me));
    x2 = dkma_add_double_ok(x1, r, &(oi->me));
    x3 = dkma_add_double_ok(x2, (0.5 * r), &(oi->me));
    x4 = dkma_add_double_ok(x3, r, &(oi->me));
    y1 = dkma_add_double_ok(y, (0.5 * ystep), &(oi->me));
    y2 = dkma_add_double_ok(y, ystep, &(oi->me));
    nocdpointout(oi, x, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, x1, y, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x2, y, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x3, y1, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x2, y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x1, y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    gcs_out(oi, 68); gcs_out(oi, 1);
    gcs_out(oi, 70); gcs_out(oi, 0);
    nocdpointout(oi, x3, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, x4, y1, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
    nocdpointout(oi, x4, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, dkma_add_double_ok(x4,x1,&(oi->me)), y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
    nocdpointout(oi, x4, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, dkma_add_double_ok(x4,x1,&(oi->me)), 0, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
    p->w = xstep; p->h = ystep;
  } else {
    while(x < xend) {
      y = 0.0;
      while(y < yend) {
        x1 = dkma_add_double_ok(x, (0.5 * r), &(oi->me));
        x2 = dkma_add_double_ok(x1, r, &(oi->me));
        x3 = dkma_add_double_ok(x2, (0.5 * r), &(oi->me));
        x4 = dkma_add_double_ok(x3, r, &(oi->me));
        y1 = dkma_add_double_ok(y, (0.5 * ystep), &(oi->me));
        y2 = dkma_add_double_ok(y, ystep, &(oi->me));
        nocdpointout(oi, x, y1, 1);
        gcs_out(oi, 66); gcs_out(oi, 0);
        nocdpointout(oi, x1, y, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x2, y, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x3, y1, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x2, y2, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x1, y2, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        gcs_out(oi, 68); gcs_out(oi, 1);
        gcs_out(oi, 70); gcs_out(oi, 0);
        nocdpointout(oi, x3, y1, 1);
        gcs_out(oi, 66); gcs_out(oi, 0);
        nocdpointout(oi, x4, y1, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        gcs_out(oi, 70); gcs_out(oi, 0);
	y = dkma_add_double_ok(y, ystep, &(oi->me));
      }
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
  }
}



/**	Write fill pattern 60 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_60 DK_P2(OI *,oi, PATD *,p)
{
  double xstep, m, x, y, x1, x2, x3, y1, y2, y3, xend, yend;
  xstep = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(4.0, xstep, &(oi->me));
  m = xstep / (2.0 + sqrt(2.0));
  m = drd(m,oi->c,2);
  if(p->tiled) {
    x = y = 0.0;
    x1 = y1 = m;
    x2 = y2 = xstep - m;
    x3 = y3 = xstep;
    nocdpointout(oi, 0.0, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, x1, 0.0, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x2, 0.0, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x3, y1, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x3, y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x2, y3, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, x1, y3, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    nocdpointout(oi, 0.0, y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 0);
    gcs_out(oi, 68); gcs_out(oi, 1);
    gcs_out(oi, 70); gcs_out(oi, 0);
    p->w = xstep; p->h = xstep;
  } else {
    x = 0.0;
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    while(x < xend) {
      y = 0.0;
      while(y < yend) {
        x1 = dkma_add_double_ok(x, m, &(oi->me));
	y1 = dkma_add_double_ok(y, m, &(oi->me));
        x2 = dkma_add_double_ok(x, (xstep - m), &(oi->me));
	y2 = dkma_add_double_ok(y, (xstep - m), &(oi->me));
        x3 = dkma_add_double_ok(x, xstep, &(oi->me));
	y3 = dkma_add_double_ok(y, xstep, &(oi->me));
        nocdpointout(oi, x, y1, 1);
        gcs_out(oi, 66); gcs_out(oi, 0);
        nocdpointout(oi, x1, y, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x2, y, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x3, y1, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x3, y2, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x2, y3, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x1, y3, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        nocdpointout(oi, x, y2, 1);
        gcs_out(oi, 67); gcs_out(oi, 0);
        gcs_out(oi, 68); gcs_out(oi, 1);
        gcs_out(oi, 70); gcs_out(oi, 0);
	y = dkma_add_double_ok(y, xstep, &(oi->me));
      }
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
  }
}



/**	Write fill pattern 61 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_61 DK_P2(OI *,oi, PATD *,p)
{
  double x, y, xstep, ystep, xend, yend, xshift, y1, y2;
  int i;
  xshift = drd(p->patrp,oi->c,1);
  xstep = dkma_mul_double_ok(2.0, xshift, &(oi->me));
  ystep = xstep;
  if(p->tiled) {
    y1 = 0.5 * xshift;
    y2 = dkma_add_double_ok(y1, xshift, &(oi->me));
    ll_set_linecap(oi, 1);
    ll_set_linejoin(oi, 1);
    nocdpointout(oi, 0.0, y1, 1);
    gcs_out(oi, 66); gcs_out(oi, 1);
    nocdpointout(oi, xshift, y2, 1);
    gcs_out(oi, 67); gcs_out(oi, 1);
    nocdpointout(oi, xstep, y1, 1);
    gcs_out(oi, 67); gcs_out(oi, 1);
    gcs_out(oi, 70); gcs_out(oi, 0);
    p->w = xstep; p->h = ystep;
  } else {
    ll_set_linecap(oi, 2);
    ll_set_linejoin(oi, 0);
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    y = 0.0;
    while(y < yend) {
      i = 0; x = 0.0;
      y1 = dkma_add_double_ok(y, (0.5 * xshift), &(oi->me));
      y2 = dkma_add_double_ok(y1, xshift, &(oi->me));
      nocdpointout(oi, x, y1, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      do {
	x = dkma_add_double_ok(x, xshift, &(oi->me));
        if(i) {
	  i = 0;
	  nocdpointout(oi, x, y1, 1);
	} else {
	  i = 1;
	  nocdpointout(oi, x, y2, 1);
	}
	gcs_out(oi, 67); gcs_out(oi, 0);
      } while(x < xend);
      gcs_out(oi, 70); gcs_out(oi, 0);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
  }
}



/**	Write fill pattern 62 to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
*/
static
void stroke_62 DK_P2(OI *,oi, PATD *,p)
{
  double x, y, x1, x2, xstep, ystep, xshift, xend, yend;
  int i;
  xshift = drd(p->patrp,oi->c,1);
  xstep = ystep = dkma_mul_double_ok(2.0, xshift, &(oi->me));
  if(p->tiled) {
    x = y = 0.0;
    x1 = 0.5 * xshift;
    x2 = dkma_add_double_ok(x1, xshift, &(oi->me));
    ll_set_linejoin(oi, 1); ll_set_linecap(oi, 1);
    nocdpointout(oi, x1, 0.0, 1);
    gcs_out(oi, 66); gcs_out(oi, 1);
    nocdpointout(oi, x2, xshift, 1);
    gcs_out(oi, 67); gcs_out(oi, 1);
    nocdpointout(oi, x1, xstep, 1);
    gcs_out(oi, 67); gcs_out(oi, 1);
    gcs_out(oi, 70); gcs_out(oi, 0);
    p->w = xstep; p->h = ystep;
  } else {
    ll_set_linejoin(oi, 0); ll_set_linecap(oi, 2);
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    x = 0.0;
    while(x < xend) {
      y = 0.0; i = 0;
      x1 = dkma_add_double_ok(x, (0.5 * xshift), &(oi->me));
      x2 = dkma_add_double_ok(x1, xshift, &(oi->me));
      nocdpointout(oi, x1, 0.0, 1);
      gcs_out(oi, 66); gcs_out(oi, 0);
      do {
	y = dkma_add_double_ok(y, xshift, &(oi->me));
	if(i) {
	  i = 0;
	  nocdpointout(oi, x1, y, 1);
	} else {
	  i = 1;
	  nocdpointout(oi, x2, y, 1);
	}
	gcs_out(oi, 67); gcs_out(oi, 1);
      } while(y < yend);
      gcs_out(oi, 70); gcs_out(oi, 0);
      x = dkma_add_double_ok(x, xstep, &(oi->me));
    }
  }
}



/**	Write fill pattern to graphics stream.
	@param	oi	OI structure.
	@param	p	Pattern description structure.
	@param	cr	0=large, 1=small.
*/
static
void stroke_56 DK_P3(OI *,oi, PATD *,p, int,cr)
{
  double radius, deltax, deltay, xshift, yshift, xstep, ystep, x, y;
  double deltaxa;
  radius = fabs(p->patrp);
  if(cr) {	/* small */
    xshift = yshift = radius;
    xstep = ystep = dkma_mul_double_ok(2.0, xshift, &(oi->me));
    deltax = deltay = dkma_mul_double_ok((0.5 * M_PI), radius, &(oi->me)) / 3.0;
    deltaxa = 0.0;
  } else {	/* large */
    double phi;
    radius = dkma_mul_double_ok(2.5, radius, &(oi->me));
    phi = 1.5 * M_PI - 0.5 * 1.881618;
    deltaxa = radius * fabs(sin(phi));
    deltay  = radius * fabs(cos(phi));
    deltax  = radius;
    deltaxa = dkma_mul_double_ok(deltaxa, (0.5 * 1.881618), &(oi->me));
    deltax  = dkma_mul_double_ok(deltax, (0.5 * 1.881618), &(oi->me));
    deltay  = dkma_mul_double_ok(deltay, (0.5 * 1.881618), &(oi->me));
    deltaxa = deltaxa / 3.0;
    deltax  = deltax  / 3.0;
    deltay  = deltay  / 3.0;
    xshift  = dkma_mul_double_ok(2.0, p->patrp, &(oi->me));
    xstep   = dkma_mul_double_ok(2.0, xshift, &(oi->me));
    yshift  = radius * (1.0 - cos(0.5 * 1.881618));
    yshift  = drd(yshift,oi->c,1);
    ystep   = dkma_mul_double_ok(2.0, yshift, &(oi->me));
  }
  if(p->tiled) {
    p->w = xstep; p->h = ystep;
    x = y = 0.0;
    nocdpointout(oi, x, dkma_add_double_ok(y,ystep,&(oi->me)), 1);
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(oi, dkma_add_double_ok(x,deltaxa,&(oi->me)),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,ystep,&(oi->me)),
	deltay,&(oi->me)
      ), 2
    ); 
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xshift,&(oi->me)),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    nocdpointout(
      oi,
      dkma_add_double_ok(
        x,
	dkma_add_double_ok(xshift,deltax,&(oi->me)),
	&(oi->me)
      ),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xstep,&(oi->me)),
	deltaxa,&(oi->me)
      ),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,ystep,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_add_double_ok(y,ystep,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
    x = 0.0 - xshift;
    nocdpointout(
      oi, x, dkma_add_double_ok(y,yshift,&(oi->me)), 1
    );
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(
      oi, x,
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y, 2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xshift,&(oi->me)),
      y,
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    nocdpointout(
      oi,
      dkma_add_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y, 1
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
        deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    x = dkma_add_double_ok(x, xstep, &(oi->me));
    nocdpointout(
      oi,
      x,
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y, 2
    );
    nocdpointout(
      oi, dkma_add_double_ok(x,xshift,&(oi->me)), y, 1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    nocdpointout(
      oi,
      dkma_add_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y, 1
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
    y = ystep;
    x = 0.0 - xshift;
    nocdpointout(
      oi,
      x,
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 66); gcs_out(oi, 0);
    nocdpointout(
      oi,
      x,
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y,
      2
    );
    nocdpointout(oi, (x+xshift), y, 1);
    gcs_out(oi, 83); gcs_out(oi, 0);
    nocdpointout(
      oi,
      dkma_add_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y,
      1
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    x = dkma_add_double_ok(x,xstep,&(oi->me));
    nocdpointout(
      oi,
      x,
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_sub_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y,
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xshift,&(oi->me)),
      y,
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    nocdpointout(
      oi,
      dkma_add_double_ok(
        dkma_add_double_ok(x,xshift,&(oi->me)),
	deltax,&(oi->me)
      ),
      y,
      1
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_sub_double_ok(
        dkma_add_double_ok(y,yshift,&(oi->me)),
	deltay,&(oi->me)
      ),
      2
    );
    nocdpointout(
      oi,
      dkma_add_double_ok(x,xstep,&(oi->me)),
      dkma_add_double_ok(y,yshift,&(oi->me)),
      1
    );
    gcs_out(oi, 83); gcs_out(oi, 0);
    gcs_out(oi, 70); gcs_out(oi, 0);
  } else {
    double xend, yend;
    ll_set_linecap(oi, 1); ll_set_linejoin(oi, 1);
    xend = dkma_add_double_ok(oi->xright, (0.5 * p->lt), &(oi->me));
    yend = dkma_add_double_ok(oi->ytop, (0.5 * p->lt), &(oi->me));
    y = 0.0;
    while(y < yend) {
      x = 0.0;
      nocdpointout(
        oi,
	x,
	dkma_add_double_ok(y,ystep,&(oi->me)),
	1
      );
      gcs_out(oi, 66); gcs_out(oi, 0);
      do {
        nocdpointout(
	  oi,
	  dkma_add_double_ok(x,deltaxa,&(oi->me)),
	  dkma_sub_double_ok(
	    dkma_add_double_ok(y,ystep,&(oi->me)),
	    deltay,&(oi->me)
	  ),
	  2
	);
	nocdpointout(
	  oi,
	  dkma_sub_double_ok(
	    dkma_add_double_ok(x,xshift,&(oi->me)),
	    deltax,&(oi->me)
	  ),
	  dkma_add_double_ok(y,yshift,&(oi->me)),
	  2
	);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(x,xshift,&(oi->me)),
	  dkma_add_double_ok(y,yshift,&(oi->me)),
	  1
	);
	gcs_out(oi, 83); gcs_out(oi, 0);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(
	    dkma_add_double_ok(x,xshift,&(oi->me)),
	    deltax,&(oi->me)
	  ),
	  dkma_add_double_ok(y,yshift,&(oi->me)),
	  1
	);
	nocdpointout(
	  oi,
	  dkma_sub_double_ok(
	    dkma_add_double_ok(x,xstep,&(oi->me)),
	    deltaxa,&(oi->me)
	  ),
	  dkma_sub_double_ok(
	    dkma_add_double_ok(y,ystep,&(oi->me)),
	    deltay,&(oi->me)
	  ),
	  2
	);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(x,xstep,&(oi->me)),
	  dkma_add_double_ok(y,ystep,&(oi->me)),
	  1
	);
	gcs_out(oi, 83); gcs_out(oi, 0);
	x = dkma_add_double_ok(x,xstep,&(oi->me));
      } while(x < xend);
      gcs_out(oi, 70); gcs_out(oi, 0);
      x = 0.0 - xshift;
      nocdpointout(
        oi,
	x,
	dkma_add_double_ok(y,yshift,&(oi->me)),
	1
      );
      gcs_out(oi, 66); gcs_out(oi, 0);
      do {
        nocdpointout(
	  oi,
	  x,
	  dkma_sub_double_ok(
	    dkma_add_double_ok(y,yshift,&(oi->me)),
	    deltay,&(oi->me)
	  ),
	  2
	);
	nocdpointout(
	  oi,
	  dkma_sub_double_ok(
	    dkma_add_double_ok(x,xshift,&(oi->me)),
	    deltax,&(oi->me)
	  ),
	  y,
	  2
	);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(x,xshift,&(oi->me)),
	  y,
	  1
	);
	gcs_out(oi, 83); gcs_out(oi, 0);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(
	    dkma_add_double_ok(x,xshift,&(oi->me)),
	    deltax,&(oi->me)
	  ),
	  y,
	  1
	);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(x,xstep,&(oi->me)),
	  dkma_sub_double_ok(
	    dkma_add_double_ok(y,yshift,&(oi->me)),
	    deltay,&(oi->me)
	  ),
	  2
	);
	nocdpointout(
	  oi,
	  dkma_add_double_ok(x,xstep,&(oi->me)),
	  dkma_add_double_ok(y,yshift,&(oi->me)),
	  1
	);
	gcs_out(oi, 83); gcs_out(oi, 0);
	x = dkma_add_double_ok(x, xstep, &(oi->me));
      } while(x < xend);
      gcs_out(oi, 70); gcs_out(oi, 0);
      y = dkma_add_double_ok(y, ystep, &(oi->me));
    }
  }
}



/**	Write one pattern data to gcs.
	@param	oi	OI structure.
	@param	w	Pointer to width.
	@param	h	Pointer to height.
	@return	1 on success, 0 on error.
*/
static
int
create_pattern_stream DK_P3(OI *,oi, double *,w, double *,h)
{
  int back = 1;
  int use_color = 1;
  double g;
  PATD patd;
  dk_fig_dcc fdcc, bdcc;
  
  if(!(((oi->c)->opt2) & DKFIG_OPT_COLOR)) {
    use_color = 0;
  }
  if((oi->c)->patrp) {
    patd.patrp = 0.9 * dkma_l_to_double((oi->c)->patrp);
  } else {
    patd.patrp = 3.6;
  }
  patd.w = oi->xright;
  patd.h = oi->ytop;
  patd.tiled = 0;
  if((oi->cp)->tile) {
    patd.tiled = 1;
    
  } else {
    
  }
  /* foreground and background color */
  dkfig_tool_fill_dcc(oi->d, &fdcc, (oi->cp)->fgcol);
  dkfig_tool_fill_dcc(oi->d, &bdcc, (oi->cp)->bgcol);
  /* patd.lt = 0.9 * dkma_l_to_double((oi->cp)->lt); */
  patd.lt = 0.9;
  /*
  if(((oi->cp)->lt) == 0L) {
    patd.lt = 0.9;
  }
  */
  if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
    patd.lt = 0.5 * patd.lt;
  }
  if(use_color) {
    write_dcc_triple(oi, &fdcc);
    gcs_out(oi, 61); gcs_out(oi, 0);
    write_dcc_triple(oi, &bdcc);
    gcs_out(oi, 60); gcs_out(oi, 0);
  } else {
    g = 0.3 * fdcc.red + 0.59 * fdcc.green + 0.11 * fdcc.blue;
    dkstream_puts_double(oi->gcs, drd(g, oi->c, 0));
    gcs_out(oi, 1); gcs_out(oi, 106); gcs_out(oi, 0);
    g = 0.3 * bdcc.red + 0.59 * bdcc.green + 0.11 * bdcc.blue;
    dkstream_puts_double(oi->gcs, drd(g, oi->c, 0));
    gcs_out(oi, 1); gcs_out(oi, 105); gcs_out(oi, 0);
  }
  ll_set_linewidth(oi, drd(patd.lt,oi->c,1));
  fill_rect(oi, 0.0, 0.0, oi->xright, oi->ytop);

  switch((oi->cp)->patno) {
    case 41: {
      ll_set_linecap(oi, 2);
      stroke_41(oi, &patd);
    } break;
    case 42: {
      ll_set_linecap(oi, 2);
      stroke_42(oi, &patd);
    } break;
    case 43: {
      ll_set_linecap(oi, 2);
      stroke_41(oi, &patd);
      stroke_42(oi, &patd);
    } break;
    case 44: {
      ll_set_linecap(oi, 2);
      stroke_44(oi, &patd);
    } break;
    case 45: {
      ll_set_linecap(oi, 2);
      stroke_45(oi, &patd);
    } break;
    case 46: {
      ll_set_linecap(oi, 2);
      stroke_44(oi, &patd);
      stroke_45(oi, &patd);
    } break;
    case 47: {	/* horizontal bricks */
      if(patd.tiled) {
	stroke_47_c(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_47_a(oi, &patd);
        stroke_47_b(oi, &patd);
      }
    } break;
    case 48: {	/* vertical bricks */
      if(patd.tiled) {
        stroke_48_c(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_48_a(oi, &patd);
        stroke_48_b(oi, &patd);
      }
    } break;
    case 49: {	/* horizontal lines */
      ll_set_linecap(oi, 0);
      stroke_49(oi, &patd);
    } break;
    case 50: {	/* vertical lines */
      ll_set_linecap(oi, 0);
      stroke_50(oi, &patd);
    } break;
    case 51: {	/* crosshatch */
      if(patd.tiled) {
        ll_set_linecap(oi, 0);
	ll_set_linejoin(oi, 0);
        stroke_51_c(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_49(oi, &patd);
        stroke_50(oi, &patd);
      }
    } break;
    case 52: {	/* horizontal shingles 1 */
      if(patd.tiled) {
        stroke_52_tiled(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_47_a(oi, &patd);
        stroke_52_b(oi, &patd);
      }
    } break;
    case 53: {	/* horizontal shingles 2 */
      if(patd.tiled) {
        stroke_53_tiled(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_47_a(oi, &patd);
        stroke_53_b(oi, &patd);
      }
    } break;
    case 54: {	/* vertical shingles 1 */
      if(patd.tiled) {
        stroke_54_tiled(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_48_a(oi, &patd);
        stroke_54_b(oi, &patd);
      }
    } break;
    case 55: {	/* vertical shingles 2 */
      if(patd.tiled) {
        stroke_55_tiled(oi, &patd);
      } else {
        ll_set_linecap(oi, 0);
        stroke_48_a(oi, &patd);
        stroke_55_b(oi, &patd);
      }
    } break;
    case 56: {	/* large fish scales */
      stroke_56(oi, &patd, 0);
    } break;
    case 57: {	/* small fish scales */
      stroke_56(oi, &patd, 1);
    } break;
    case 58: {	/* circles */
      stroke_58(oi, &patd);
    } break;
    case 59: {	/* hexagons */
      ll_set_linecap(oi, 1);
      stroke_59(oi, &patd);
    } break;
    case 60: {	/* octagons */
      ll_set_linejoin(oi, 0);
      stroke_60(oi, &patd);
    } break;
    case 61: {	/* horizontal tire treads */
      stroke_61(oi, &patd);
    } break;
    case 62: {	/* vertical tire treads */
      stroke_62(oi, &patd);
    } break;
  }
  *w = patd.w; *h = patd.h;
  
  return back;
}



/**	Write pattern object to os.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
write_one_pattern_object DK_P1(OI *,oi)
{
  int back = 0;
  double w, h;	/* width and height of a pattern tile */
  char *buffer; size_t lgt; unsigned long streamlgt;
  if((oi->c)->app) {
    lgt = dksf_get_maxpathlen();
    buffer = dk_new(char, lgt);
    if(buffer) {
      if(dkapp_tmpnam((oi->c)->app, buffer, lgt)) {
        dk_stream_t *plainfile;
	oi->gcs = NULL;
	plainfile = dkapp_stream_openfile(
	  (oi->c)->app, buffer, str_open_write_binary
	);
	if(plainfile) {
	  if(((oi->c)->opt2) & DKFIG_OPT_PLAIN_TEXT_STREAMS) {
	    oi->gcs = plainfile;
	    back = create_pattern_stream(oi, &w, &h);
	  } else {
	    dk_stream_t *compressedfile;
	    compressedfile = dkof_open(plainfile, 3);
	    if(compressedfile) {
	      dkof_set_crnl(compressedfile, 1);
	      back = 1;
	      if(!dkof_set(compressedfile,0,DK_OF_TYPE_BUFFERED)) { back = 0; }
	      if(!dkof_set(compressedfile,1,DK_OF_TYPE_ASCII85)) { back = 0; }
	      if(!dkof_set(compressedfile,2,DK_OF_TYPE_FLATE)) { back = 0; }
	      if(back) {
	        back = 0;
		if(dkof_start_chunk(compressedfile)) {
		  oi->gcs = compressedfile;
		  back = create_pattern_stream(oi, &w, &h);
		  if(!dkof_end_chunk(compressedfile)) {
		    back = 0;
		    dkfig_tool2_simple_error_message(oi->c, 74);
		  }
		} else {
		  dkfig_tool2_simple_error_message(oi->c, 73);
		}
	      } else {
		dkfig_tool2_simple_error_message(oi->c, 72);
	      }
	    } else {
	      dkfig_tool2_simple_error_message(oi->c, 72);
	    }
	  }
	  streamlgt = dkstream_get_bytes_written(plainfile);
	  dkstream_close(plainfile); plainfile = NULL;
	  if(back) {
	    /* dictionary and stream */
	    back = 0;
	    if(begin_object(oi, (oi->cp)->objno)) {
	      kw_out(oi, 5); kw_out(oi, 0);
              kw_out(oi, 62); kw_out(oi, 0);
	      kw_out(oi, 63);
	      dkstream_puts_double(oi->s, w);
	      kw_out(oi, 1);
	      dkstream_puts_double(oi->s, h);
	      kw_out(oi, 25); kw_out(oi, 1);
	      kw_out(oi, 64); kw_out(oi, 1);
	      dkstream_puts_double(oi->s, w);
	      kw_out(oi, 1);
	      kw_out(oi, 65); kw_out(oi, 1);
	      dkstream_puts_double(oi->s, h);
	      kw_out(oi, 0);
	      kw_out(oi, 28); kw_out(oi, 1);
	      kw_out(oi, 5); kw_out(oi, 1);
	      kw_out(oi, 29);
	      kw_out(oi, 30);
	      kw_out(oi, 25); kw_out(oi, 1);
	      kw_out(oi, 6); kw_out(oi, 0);
	      kw_out(oi, 39); kw_out(oi, 1);
	      dkstream_puts_ul(oi->s, streamlgt);
	      if(!(((oi->c)->opt2) & DKFIG_OPT_PLAIN_TEXT_STREAMS)) {
                kw_out(oi, 1);
		kw_out(oi, 40);
	      }
	      kw_out(oi, 0);
	      kw_out(oi, 6); kw_out(oi, 0);
	      kw_out(oi, 41); kw_out(oi, 0);
	      back = copy_file_to_stream(oi, buffer, streamlgt);
	      kw_out(oi, 42); kw_out(oi, 0);
	      dksf_remove_file(buffer);
	      end_object(oi);
	    }
	  }
	} else {
	  if((oi->c)->app) {
	    dkapp_err_fopenw((oi->c)->app, buffer);
	  }
	}
	oi->gcs = NULL;
      } else {
	dkfig_tool2_simple_error_message(oi->c, 67);
      }
      dk_delete(buffer); buffer = NULL;
    } else {
      if((oi->c)->app) {
        dkapp_err_memory((oi->c)->app,sizeof(char),lgt);
      }
    }
  } else {	
    dkfig_tool2_simple_error_message(oi->c, 44);
  }
  return back;
}



/**	Write all pattern objects to os.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
write_pattern_objects DK_P1(OI *,oi)
{
  int back = 1;
  dkfig_pdf_pattern *patp;
  dksto_it_reset(oi->patli);
  while((patp = (dkfig_pdf_pattern *)dksto_it_next(oi->patli)) != NULL) {
    oi->cp = patp;
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, patp->lineno);
    }
    if(!write_one_pattern_object(oi)) {
      back = 0;
      dkfig_tool2_simple_error_message(oi->c, 106);
    }
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
  }
  return back;
}



/**	Write one image object to os.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int write_one_image DK_P1(OI *,oi)
{
  int back = 0;
  if(begin_object(oi, (oi->ci)->objno)) {
    kw_out(oi, 5); kw_out(oi, 0);
    kw_out(oi, 90); kw_out(oi, 0);
    kw_out(oi, 91); kw_out(oi, 1);
    switch((oi->ci)->ch) {
      case 1: case 2: {
        kw_out(oi, 93);
      } break;
      default: {
        kw_out(oi, 92);
      } break;
    }
    kw_out(oi, 0);
    kw_out(oi, 94); kw_out(oi, 0);
    kw_out(oi, 40); kw_out(oi, 0);
    kw_out(oi, 95); kw_out(oi, 1);
    switch((oi->ci)->flipped) {
      case 2: {
        dkstream_puts_ul(oi->s, (oi->ci)->h);
      } break;
      default: {
        dkstream_puts_ul(oi->s, (oi->ci)->w);
      } break;
    }
    kw_out(oi, 0);
    kw_out(oi, 96); kw_out(oi, 1);
    switch((oi->ci)->flipped) {
      case 2: {
        dkstream_puts_ul(oi->s, (oi->ci)->w);
      } break;
      default: {
        dkstream_puts_ul(oi->s, (oi->ci)->h);
      } break;
    }
    kw_out(oi, 0);
    if(((oi->c)->opt2) & DKFIG_OPT_INTERPOLATE_IMAGES) {
      kw_out(oi, 97); kw_out(oi, 0);
    }
    switch((oi->ci)->ch) {
      case 2: case 4: {
        kw_out(oi, 98); kw_out(oi, 1);
	dkstream_puts_ul(oi->s, ((oi->ci)->objno + 1UL));
	kw_out(oi, 1); kw_out(oi, 99);
	kw_out(oi, 0);
      } break;
    }
    kw_out(oi, 39); kw_out(oi, 1);
    dkstream_puts_ul(oi->s, (oi->ci)->ol);
    kw_out(oi, 0);
    kw_out(oi, 6); kw_out(oi, 0);
    kw_out(oi, 41); kw_out(oi, 0);
    back = copy_file_to_stream(oi, (oi->ci)->ofn, (oi->ci)->ol);
    kw_out(oi, 42); kw_out(oi, 0);
    end_object(oi);
    if(back) {
      switch((oi->ci)->ch) {
        case 2: case 4: {
	  back = 0;
	  if(begin_object(oi, ((oi->ci)->objno + 1UL))) {
	    kw_out(oi, 5); kw_out(oi, 0);
            kw_out(oi, 100); kw_out(oi, 1);
            kw_out(oi, 90); kw_out(oi, 0);
            kw_out(oi, 91); kw_out(oi, 1);
            kw_out(oi, 93); kw_out(oi, 0);
            kw_out(oi, 94); kw_out(oi, 0);
            kw_out(oi, 40); kw_out(oi, 0);
            kw_out(oi, 95); kw_out(oi, 1);
            switch((oi->ci)->flipped) {
              case 2: {
                dkstream_puts_ul(oi->s, (oi->ci)->h);
              } break;
              default: {
                dkstream_puts_ul(oi->s, (oi->ci)->w);
              } break;
            }
            kw_out(oi, 0);
            kw_out(oi, 96); kw_out(oi, 1);
            switch((oi->ci)->flipped) {
              case 2: {
                dkstream_puts_ul(oi->s, (oi->ci)->w);
              } break;
              default: {
                dkstream_puts_ul(oi->s, (oi->ci)->h);
              } break;
            }
            kw_out(oi, 0);
            /*
            if(((oi->c)->opt2) & DKFIG_OPT_INTERPOLATE_IMAGES) {
              kw_out(oi, 97); kw_out(oi, 0);
            }
            */
            kw_out(oi, 39); kw_out(oi, 1);
            dkstream_puts_ul(oi->s, (oi->ci)->al);
            kw_out(oi, 0);
	    kw_out(oi, 6); kw_out(oi, 0);
	    kw_out(oi, 41); kw_out(oi, 0);
	    back = copy_file_to_stream(oi, (oi->ci)->afn, (oi->ci)->al);
	    kw_out(oi, 42); kw_out(oi, 0);
	    end_object(oi);
	  }
	} break;
      }
    }
  }
  return back;
}



/**	Write all image objects to os.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int write_image_objects DK_P1(OI *,oi)
{
  int back = 1;
  dkfig_pdf_image *pi;
  dksto_it_reset(oi->imgli);
  while((pi = (dkfig_pdf_image *)dksto_it_next(oi->imgli)) != NULL) {
    oi->ci = pi;
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, pi->lineno);
    }
    if(!write_one_image(oi)) {
      back = 0;
      dkfig_tool2_combined_error_message(oi->c, 107, 108, (oi->ci)->inputfilename);
    }
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
    oi->ci = NULL;
  }
  return back;
}



/**	Write media box and crop box data to os.
	@param	oi	OI structure.
	@param	kwno	Keyword index to choose media or crop box.
*/
static
void media_crop_box DK_P2(OI *,oi, int,kwno)
{
	  kw_out(oi, kwno);
	  dkstream_puts_double(oi->s, 0.0);
	  kw_out(oi, 1);
	  dkstream_puts_double(oi->s, 0.0);
	  kw_out(oi, 1);
	  dkstream_puts_double(oi->s, oi->xright);
	  kw_out(oi, 1);
	  dkstream_puts_double(oi->s, oi->ytop);
	  kw_out(oi, 25); kw_out(oi, 0);
}



/**	Output pass - pproduce PDF output.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int output_pass DK_P1(OI *,oi)
{
  int back = 1;
  
  kw_out(oi, 2); kw_out(oi, 0);
  dkfig_tool2_simple_progress_message(oi->c, 99);
  if(begin_object(oi, 1UL)) {
    kw_out(oi, 5); kw_out(oi, 1);
    kw_out(oi, 20); kw_out(oi, 1);
    kw_out(oi, 6); kw_out(oi, 0);
    end_object(oi);
    if(begin_object(oi, 2UL)) {
      kw_out(oi, 5); kw_out(oi, 1);
      kw_out(oi, 21);
      if(((oi->c)->opt2) & DKFIG_OPT_FULL_SCREEN) {
        kw_out(oi, 43);
      }
      kw_out(oi, 1); kw_out(oi, 6); kw_out(oi, 0);
      end_object(oi);
      if(begin_object(oi, 3UL)) {
        kw_out(oi, 5); kw_out(oi, 1);
	kw_out(oi, 22);
	kw_out(oi, 1); kw_out(oi, 6); kw_out(oi, 0);
        end_object(oi);
	if(begin_object(oi, 4UL)) {
	  kw_out(oi, 5); kw_out(oi, 0);
	  kw_out(oi, 23); kw_out(oi, 0);
          if(((oi->c)->opt2) & DKFIG_OPT_PDF_PAGE_ATTRIBUTES) {
	    if(((oi->d)->opt2) & DKFIG_OPT_HAVE_ALPHA_CHANNEL) {
	      kw_out(oi, 104); kw_out(oi, 0);
	    }
	  }
	  kw_out(oi, 27); kw_out(oi, 0);
	  media_crop_box(oi, 24);
	  media_crop_box(oi, 102);
	  kw_out(oi, 36); kw_out(oi, 0);
	  kw_out(oi, 26); kw_out(oi, 0);
	  kw_out(oi, 28); kw_out(oi, 1); kw_out(oi, 5); kw_out(oi, 0);
	  kw_out(oi, 29); 
	  kw_out(oi, 30);
	  if((oi->procs) & DKFIG_PDF_PROCSET_TEXT) {
	    kw_out(oi, 1); kw_out(oi, 54);
	  }
	  if((oi->procs) & DKFIG_PDF_PROCSET_IMGG) {
	    kw_out(oi, 1); kw_out(oi, 58);
	  }
	  if((oi->procs) & DKFIG_PDF_PROCSET_IMGC) {
	    kw_out(oi, 1); kw_out(oi, 59);
	  }
	  kw_out(oi, 25); kw_out(oi, 0);
	  write_fonts(oi);
	  write_patterns(oi);
	  write_images(oi);
	  kw_out(oi, 6); kw_out(oi, 0);
	  kw_out(oi, 6); kw_out(oi, 0);
	  end_object(oi);
	  if(begin_object(oi, 5UL)) {
	    /* oi->no = 6UL; */
	    dkfig_tool2_simple_progress_message(oi->c, 100);
	    back = write_graphics_stream(oi);
	    end_object(oi);
	    if(back) {
	      dkfig_tool2_simple_progress_message(oi->c, 101);
	      back = write_font_objects(oi);
	      if(back) {
	        dkfig_tool2_simple_progress_message(oi->c, 102);
	        back = write_pattern_objects(oi);
		if(back) {
		  dkfig_tool2_simple_progress_message(oi->c, 103);
		  back = write_image_objects(oi);
		}
	      }
	    }
	  }
	}
      }
    }
  }
  if(back) {
    back = finalize_pdf(oi);
  } 
  return back;
}



/**	Cleanup pass - release collected style, pattern and image information.
	@param	oi	OI structure.
*/
static
void cleanup_pass DK_P1(OI *,oi)
{
  dk_fig_object *o;
  dkfig_pdf_pattern *patp;
  
  if((oi->fl) && (oi->fli)) {
    dksto_it_reset(oi->fli);
    while((o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
      if(o->drve) {
        delete_drve((dkfig_pdf_drve_text *)(o->drve));
	o->drve = NULL;
      }
    }
    dksto_it_close(oi->fli);
  }
  if(oi->fl) {
    dksto_close(oi->fl);
  }
  oi->fl = NULL; oi->fli = NULL;
  if((oi->patl) && (oi->patli)) {
    dksto_it_reset(oi->patli);
    while((patp = (dkfig_pdf_pattern *)dksto_it_next(oi->patli)) != NULL) {
      
      dk_delete(patp);
    }
    dksto_it_close(oi->patli);
  }
  if(oi->patl) {
    dksto_close(oi->patl);
  }
  oi->patl = NULL; oi->patli = NULL;
  if((oi->imgl) && (oi->imgli)) {
    dkfig_pdf_image *i;
    dksto_it_reset(oi->imgli);
    while((i = (dkfig_pdf_image *)dksto_it_next(oi->imgli)) != NULL) {
      delete_image(i);
    }
    dksto_it_close(oi->imgli);
  }
  if(oi->imgl) {
    dksto_close(oi->imgl);
  }
  oi->imgl = NULL; oi->imgli = NULL;
  if((oi->pdfo) && (oi->pdfoi)) {
    OPOS *p;
    dksto_it_reset(oi->pdfoi);
    /* free all object position structures */
    while((p = (OPOS *)dksto_it_next(oi->pdfoi)) != NULL) {
      dk_delete(p);
    }
    dksto_it_close(oi->pdfoi);
  }
  if(oi->pdfo) {
    dksto_close(oi->pdfo);
  }
  oi->pdfo = NULL; oi->pdfoi = NULL;
  
}



/**	PDF output driver function.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_output_pdf DK_P1(dk_fig_conversion *,c)
{
  int back = 0, i;
  unsigned long fonts_used[14];
  OI oi;
  null_oi(&oi);
  oi.fu = fonts_used;
  for(i = 0; i < 14; i++) { fonts_used[i] = 0UL; }
  if(c) {
    if(c->app) {
      dkapp_set_source_lineno(c->app, 0UL);
    }
    oi.c = c;
    if(c->ostrm) {
      oi.s = c->ostrm;
      dkstream_set_double_no_exponent(oi.s, 1);
      if(c->drwng) {
        dk_fig_object *o;
	o = c->drwng;
	oi.d = (dk_fig_drawing *)(o->data);
	/* Progress: Gathering information */
	dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 121);
	if(preparation_pass(&oi)) {
          dkfig_tool2_report_unused_options(c);
	  /*  Progress: Starting output */
	  if(c->msg1) {
	    dkfig_tool2_msg3(
	      c, DK_LOG_LEVEL_PROGRESS, 20, 21,
	      ((c->ofn2) ? (c->ofn2) : ((c->msg1)[122]))
	    );
	  }
	  back = output_pass(&oi);
	  if(back) {
	    if(((oi.d)->opt2) & DKFIG_OPT_HAVE_ALPHA_CHANNEL) {
	      if(!((c->opt2) & DKFIG_OPT_SUPPRESS_ALPHA_INFO)) {
	        dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 129);
	      }
	    }
	  }
	  /* Progress: finished output */
	  dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 22);
	}
	cleanup_pass(&oi);
      }
    }
  }
  return back;
}



