PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
cgm.c
Go to the documentation of this file.
1 // PLplot cgm device driver.
2 //
3 
4 //
5 // This driver generates CGM (computer graphics metafiles) files (bit of a
6 // tautology that... 'computer graphics metaFILES FILES' - oh well).
7 //
8 // The CGM format is vector-based and is widely used as an interchange
9 // format between drawing and plotting programs. Although I have never
10 // looked at them, there are apparently both Java applets and browser
11 // plug-ins for displaying CGM files on web pages.
12 //
13 // This plplot driver supports lines, polylines (they make a difference to
14 // CGM files), fills, and line widths. It is limited to 256 colours, which
15 // should not be a problem. The plplot CGM driver's source (cgm.c) was
16 // derived largely from the gd driver (gd.c).
17 //
18 // The plplot driver requires libcd.a. libcd.a is very similar to libgd.a
19 // and has a similar licencing agreement behind it. Unlike libgd,
20 // development of libcd seems to have crawled to a halt back in 1998 with
21 // V1.3 of the library. The original host site for the library no longer
22 // exists, so probably the best source of the library presently is:
23 //
24 // http://www.pa.msu.edu/reference/cgmdraw_ref.html
25 // http://www.pa.msu.edu/ftp/pub/unix/
26 //
27 
28 //
29 // Two options are supported by the driver via the -drvopt command line
30 // toggle.
31 //
32 // By default CGM files don't have a background as such. The driver adds
33 // support for different backgrounds by colouring in a large rectangle
34 // underneath everything else. If for some reason you want the "raw plotted
35 // junk" and aren't really interested in having an obtrusive piece of paper
36 // in the back, use the command line toggle "-drvopt no_paper=1" to turn off
37 // this background paper.
38 //
39 // By default the CGM files generated by this driver try to make edges of
40 // polygons (ie fills) "invisible", which is something CGM files can do.
41 // Some programs (ie CoreDraw) ignore this field and draw edges in anyway.
42 // By setting "-drvopt force_edges=1" the driver will render edges on all
43 // filled polygons, and will set their colour to the same as the polygon.
44 // Most drivers should not need this, but if you see lines that you don't
45 // think you should be seeing in your viewer, try this toggle.
46 //
47 
48 //
49 // Driver supports a hack that manipulates the colour palette when
50 // a light background is selected. This is basically to make sure
51 // there are not two "whites" when -bg ffffff is issued at the
52 // command line.
53 //
54 // Related to this change, there is an ability to swap the "new"
55 // black colour (index 15) with the red colour (index 2) by issuing
56 // the command line "-hack" option. I like this for web pages, because
57 // I think that black looks nicer than red (on white) for default
58 // plotting. That is why it can be enabled with -hack, in case you
59 // don't like it working this way.
60 //
61 // For me, these two changes make it easy to switch from a "screen friendly"
62 // black background with red first plotting colour, to a "web friendly"
63 // white background with a black first plotting colour.
64 //
65 // These features are enabled on a driver level by defining
66 // "SWAP_BALCK_WHEN_WHITE". If you wan't the driver to behave 100% like other
67 // drivers, comment out the define
68 //
69 
70 #define SWAP_BALCK_WHEN_WHITE
71 
72 #include "plDevs.h"
73 
74 #ifdef PLD_cgm
75 
76 #include "plplotP.h"
77 #include "drivers.h"
78 
79 #include <cd.h>
80 
81 // Device info
82 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_cgm = "cgm:CGM file:0:cgm:44:cgm\n";
83 
84 // Prototypes for functions in this file.
85 
86 static void fill_polygon( PLStream *pls );
87 static void setcmap( PLStream *pls );
88 static void plD_init_cgm_Dev( PLStream *pls );
89 
90 // top level declarations
91 
92 // In an attempt to fix a problem with the hidden line removal functions
93 // that results in hidden lines *not* being removed from "small" plot
94 // pages (ie, like a normal video screen), a "virtual" page of much
95 // greater size is used to trick the algorithm into working correctly.
96 // If, in future, this gets fixed on its own, then don't define
97 // "use_experimental_hidden_line_hack"
98 //
99 
100 #define use_experimental_hidden_line_hack
101 
102 static int force_edges = 0;
103 static int disable_background = 0;
104 
105 static DrvOpt cgm_options[] = { { "force_edges", DRV_INT, &force_edges, "Force edges to be drawn on filled polygongs (0|1)" },
106  { "no_paper", DRV_INT, &disable_background, "Disable background (0|1)" },
107  { NULL, DRV_INT, NULL, NULL } };
108 
109 
110 // Struct to hold device-specific info.
111 
112 typedef struct
113 {
114  cdImagePtr im_out; // Graphics pointer
115  PLINT cgmx;
116  PLINT cgmy;
117 
118 // GD does "funny" things with the colour map.
119 // It can't guarantee that the colours will be where you think they are.
120 // So we need this "colour_index" table to store where the colour we
121 // requested happens to be. Messy, but it works.
122 //
123 
124  int colour_index[256]; // Colour "index" table
125 
126 //
127 // I use two colours for both fill and line drawing - a "last colour" and
128 // "current colour". The driver only switches colours if they have changed
129 // and are used. If no fills are ever done, then the instruction to set the
130 // fill colour is never sent to the CGM file. Should make for smaller and
131 // more efficient files (I guess).
132 //
133 
134  int colour; // Current Colour
135  int last_line_colour; // Last line colour used
136  int fill_colour; // Current Fill colour
137  int last_fill_colour; // Last Fill colour used
138 
139  int totcol; // Total number of colours
140  int ncol1; // Actual size of ncol1 we got
141  int scale; // scaling factor to "blow up" to
142  // the "virtual" page in removing hidden lines
143  int force_edges; // Forces edges to be drawn in fills
144  int disable_background; // Turns off background rectangle
145 } cgm_Dev;
146 
147 void plD_init_cgm( PLStream * );
148 void plD_line_cgm( PLStream *, short, short, short, short );
149 void plD_polyline_cgm( PLStream *, short *, short *, PLINT );
150 void plD_eop_cgm( PLStream * );
151 void plD_bop_cgm( PLStream * );
152 void plD_tidy_cgm( PLStream * );
153 void plD_state_cgm( PLStream *, PLINT );
154 void plD_esc_cgm( PLStream *, PLINT, void * );
155 
156 
158 {
159 #ifndef ENABLE_DYNDRIVERS
160  pdt->pl_MenuStr = "CGM (Computer Graphics metafile) file";
161  pdt->pl_DevName = "cgm";
162 #endif
164  pdt->pl_seq = 44;
165  pdt->pl_init = (plD_init_fp) plD_init_cgm;
166  pdt->pl_line = (plD_line_fp) plD_line_cgm;
167  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cgm;
168  pdt->pl_eop = (plD_eop_fp) plD_eop_cgm;
169  pdt->pl_bop = (plD_bop_fp) plD_bop_cgm;
170  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cgm;
171  pdt->pl_state = (plD_state_fp) plD_state_cgm;
172  pdt->pl_esc = (plD_esc_fp) plD_esc_cgm;
173 }
174 
175 
176 //--------------------------------------------------------------------------
177 // plD_init_cgm_Dev()
178 //
179 //--------------------------------------------------------------------------
180 
181 static void
182 plD_init_cgm_Dev( PLStream *pls )
183 {
184  cgm_Dev *dev;
185 
186 // Allocate and initialize device-specific data
187 
188  if ( pls->dev != NULL )
189  free( (void *) pls->dev );
190 
191  pls->dev = calloc( 1, (size_t) sizeof ( cgm_Dev ) );
192  if ( pls->dev == NULL )
193  plexit( "plD_init_cgm_Dev: Out of memory." );
194 
195  dev = (cgm_Dev *) pls->dev;
196 
197 // Check for and set up driver options
198 
199  plParseDrvOpts( cgm_options );
200  dev->force_edges = force_edges; // force edges (for corel draw etc...)
201  dev->disable_background = disable_background; // Disable background
202 
203  dev->colour = 1; // Set a fall back pen colour in case user doesn't
204  dev->fill_colour = dev->colour; // initially set fill and line colour the same
205  dev->last_fill_colour = -1; // set to -1 = unallocated
206  dev->last_line_colour = -1; // set to -1 = unallocated
207 }
208 
209 //--------------------------------------------------------------------------
210 // plD_init_cgm()
211 //
212 // Initialize device.
213 //--------------------------------------------------------------------------
214 
215 void plD_init_cgm( PLStream *pls )
216 {
217  cgm_Dev *dev = NULL;
218 
219  pls->termin = 0; // Not an interactive device
220  pls->icol0 = 1;
221  pls->bytecnt = 0;
222  pls->page = 0;
223  pls->dev_fill0 = 1; // Can do solid fills
224 
225  if ( !pls->colorset )
226  pls->color = 1; // Is a color device
227 
228  if ( pls->width < 1 )
229  pls->width = 1; // set a legal line width
230 
231 // Initialize family file info
232  plFamInit( pls );
233 
234 // Prompt for a file name if not already set
235  plOpenFile( pls );
236 
237 // Allocate and initialize device-specific data
238  plD_init_cgm_Dev( pls );
239  dev = (cgm_Dev *) pls->dev;
240 
241  if ( pls->xlength <= 0 || pls->ylength <= 0 )
242  {
243 // use default width, height of 800x600 if not specifed by -geometry option
244 // or plspage
245  plspage( 0., 0., 800, 600, 0, 0 );
246  }
247 
248  pls->graphx = GRAPHICS_MODE;
249 
250  dev->cgmx = pls->xlength - 1; // should I use -1 or not???
251  dev->cgmy = pls->ylength - 1;
252 
253 #ifdef use_experimental_hidden_line_hack
254 
255  if ( dev->cgmx > dev->cgmy ) // Work out the scaling factor for the
256  { // "virtual" (oversized) page
257  dev->scale = ( PIXELS_X - 1 ) / dev->cgmx;
258  }
259  else
260  {
261  dev->scale = PIXELS_Y / dev->cgmy;
262  }
263 #else
264 
265  dev->scale = 1;
266 
267 #endif
268 
269  if ( pls->xdpi <= 0 )
270  {
271 // This corresponds to a typical monitor resolution of 4 pixels/mm.
272  plspage( 4. * 25.4, 4. * 25.4, 0, 0, 0, 0 );
273  }
274  else
275  {
276  pls->ydpi = pls->xdpi; // Set X and Y dpi's to the same value
277  }
278 // Convert DPI to pixels/mm
279  plP_setpxl( dev->scale * pls->xdpi / 25.4, dev->scale * pls->ydpi / 25.4 );
280 
281  plP_setphy( 0, dev->scale * dev->cgmx, 0, dev->scale * dev->cgmy );
282 }
283 
284 //--------------------------------------------------------------------------
285 // plD_line_cgm()
286 //
287 // Draw a line in the current color from (x1,y1) to (x2,y2).
288 //--------------------------------------------------------------------------
289 
290 void
291 plD_line_cgm( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
292 {
293  cgm_Dev *dev = (cgm_Dev *) pls->dev;
294  int x1 = x1a / dev->scale, y1 = y1a / dev->scale, x2 = x2a / dev->scale, y2 = y2a / dev->scale;
295  y1 = y1;
296  y2 = y2;
297 
298 //
299 // Determine if the colour has changed since the last time a line was
300 // drawn. If it has, then set the colour NOW otherwise, keep on going like
301 // "nuthin happened".
302 //
303 
304  if ( dev->last_line_colour != dev->colour )
305  {
306  cdSetLineColor( dev->im_out, dev->colour );
307  dev->last_line_colour = dev->colour;
308  }
309 
310  cdLine( dev->im_out, x1, y1, x2, y2 );
311 }
312 
313 //--------------------------------------------------------------------------
314 // plD_polyline_cgm()
315 //
316 // Draw a polyline in the current color.
317 //--------------------------------------------------------------------------
318 
319 void
320 plD_polyline_cgm( PLStream *pls, short *xa, short *ya, PLINT npts )
321 {
322  cgm_Dev *dev = (cgm_Dev *) pls->dev;
323  PLINT i;
324  cdPoint *points = NULL;
325 
326  if ( ( points = calloc( npts, (size_t) sizeof ( cdPoint ) ) ) == NULL )
327  {
328  plexit( "Memory allocation error in \"plD_polyline_cgm\"" );
329  }
330 
331  for ( i = 0; i < npts; i++ )
332  {
333  points[i].x = xa[i] / dev->scale;
334  points[i].y = ( ya[i] / dev->scale );
335  }
336 
337 //
338 // Determine if the colour has changed since the last time a line was
339 // drawn. If it has, then set the colour NOW otherwise, keep on going like
340 // "nuthin happened".
341 //
342 
343  if ( dev->last_line_colour != dev->colour )
344  {
345  cdSetLineColor( dev->im_out, dev->colour );
346  dev->last_line_colour = dev->colour;
347  }
348 
349  cdPolyLine( dev->im_out, points, npts );
350  free( points );
351 }
352 
353 
354 //--------------------------------------------------------------------------
355 // fill_polygon()
356 //
357 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
358 //--------------------------------------------------------------------------
359 
360 static void
361 fill_polygon( PLStream *pls )
362 {
363  cgm_Dev *dev = (cgm_Dev *) pls->dev;
364 
365  PLINT i;
366  cdPoint *points = NULL;
367 
368  if ( pls->dev_npts < 1 )
369  return;
370 
371  if ( ( points = calloc( pls->dev_npts, (size_t) sizeof ( cdPoint ) ) ) == NULL )
372  {
373  plexit( "Memory allocation error in \"plD_fill_polygon_cgm\"" );
374  }
375 
376  for ( i = 0; i < pls->dev_npts; i++ )
377  {
378  points[i].x = pls->dev_x[i] / dev->scale;
379  points[i].y = ( pls->dev_y[i] / dev->scale );
380  }
381 
382 
383 //
384 // Determine if the fill colour has changed since the last time a fill was
385 // done. If it has, then set the colour NOW otherwise, keep on going like
386 // "nuthin happened". If it's the first time, we will know 'cause the the
387 // "last_fill_colour" will be -1.
388 //
389 
390  if ( ( dev->fill_colour != dev->last_fill_colour ) || ( dev->force_edges == 1 ) )
391  {
392  cdSetFillColor( dev->im_out, dev->fill_colour );
393 
394 //
395 // Due to a bug in cd V1.3, we have to set the edge colour to the fill
396 // colour. This is despite telling the library edges should be invisible.
397 // Seems the invisible edges only work with rectangles.
398 //
399 
400  if ( dev->force_edges == 1 )
401  {
402  cdSetEdgeColor( dev->im_out, dev->fill_colour );
403  cdSetEdgeVis( dev->im_out, 1 );
404  }
405 
406  dev->last_fill_colour = dev->fill_colour;
407  }
408 
409  cdPolygon( dev->im_out, points, pls->dev_npts );
410 
411  if ( dev->force_edges == 1 )
412  cdSetEdgeVis( dev->im_out, 0 ); // Turn edges off now
413 
414  free( points );
415 }
416 
417 //--------------------------------------------------------------------------
418 // setcmap()
419 //
420 // Sets up color palette.
421 //--------------------------------------------------------------------------
422 
423 static void
424 setcmap( PLStream *pls )
425 {
426  int i, ncol1 = pls->ncol1;
427  int ncol0 = pls->ncol0, total_colours;
428  PLColor cmap1col;
429  cgm_Dev *dev = (cgm_Dev *) pls->dev;
430  PLFLT tmp_colour_pos;
431 
432  cdImageColorClear( dev->im_out ); // UNDOCUMENTED FUNCTION TO RESET THE
433  // INTERNAL COLOUR TABLE OF THE
434  // CD DRIVER. Seems to work and fix
435  // the errors
436 
437  if ( ncol0 > cdMaxColors / 2 ) // Check for ridiculous number of colours
438  { // in ncol0, and appropriately adjust the
439  plwarn( "Too many colours in cmap0." ); // number, issuing a
440  ncol0 = cdMaxColors / 2; // warning if it does
441  pls->ncol0 = ncol0;
442  }
443 
444  dev->totcol = 0; // Reset the number of colours counter to zero
445 
446  total_colours = ncol0 + ncol1; // Work out how many colours are wanted
447 
448  if ( total_colours > cdMaxColors ) // Do some rather modest error
449  { // checking to make sure that
450  total_colours = cdMaxColors; // we are not defining more colours
451  ncol1 = total_colours - ncol0; // than we have room for.
452 
453  if ( ncol1 <= 0 )
454  {
455  plexit( "Problem setting colourmap in CGM driver." );
456  }
457  }
458 
459  dev->ncol1 = ncol1; // The actual size of ncol1, regardless of what was asked.
460  // This is dependent on colour slots available.
461  // It might well be the same as ncol1.
462  //
463 
464 // Initialize cmap 0 colors
465 
466  if ( ncol0 > 0 ) // make sure the program actually asked for cmap0 first
467  {
468 #ifdef SWAP_BALCK_WHEN_WHITE
469 
470 //
471 // Do a kludge to add a "black" colour back to the palette if the
472 // background is "almost white" (ie changed through -bg).
473 //
474 // Also includes an "optional" change to swap the red colour (1) with the
475 // black colour (15), which is off by default. (I don't like the red being
476 // the 'default' colour "1" on a "white" background, or for that matter
477 // yellow being "2", but I can live more with yellow at number two.)
478 // Just use "-hack" from the command line to make it take effect.
479 //
480 //
481 
482  if ( ( pls->ncol0 > 15 ) && ( pls->cmap0[0].r > 227 ) && ( pls->cmap0[0].g > 227 ) && ( pls->cmap0[0].b > 227 ) )
483  {
484  if ( pls->hack != 1 ) // just set colour 15 to black
485  {
486  pls->cmap0[15].r = 0;
487  pls->cmap0[15].g = 0;
488  pls->cmap0[15].b = 0;
489  }
490  else // swap colour 15 and colour 1
491  {
492  pls->cmap0[15].r = pls->cmap0[1].r;
493  pls->cmap0[15].g = pls->cmap0[1].g;
494  pls->cmap0[15].b = pls->cmap0[1].b;
495 
496  pls->cmap0[1].r = 0;
497  pls->cmap0[1].g = 0;
498  pls->cmap0[1].b = 0;
499  }
500  }
501 
502 #endif
503 
504  for ( i = 0; i < ncol0; i++ )
505  {
506  if ( (
507  dev->colour_index[i] = cdImageColorAllocate( dev->im_out,
508  pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b )
509  ) == -1 )
510  {
511  plwarn( "Problem setting cmap0 in CGM driver." );
512  }
513  else
514  ++dev->totcol; // count the number of colours we use as we use them
515  }
516  }
517 
518 // Initialize any remaining slots for cmap1
519 
520 
521  if ( ncol1 > 0 ) // make sure that we want to define cmap1 first
522  {
523  for ( i = 0; i < ncol1; i++ )
524  {
525  if ( ncol1 < pls->ncol1 ) // Check the dynamic range of colours
526  {
527  //
528  // Ok, now if we have less colour slots available than are being
529  // defined by pls->ncol1, then we still want to use the full
530  // dynamic range of cmap1 as best we can, so what we do is work
531  // out an approximation to the index in the full dynamic range
532  // in cases when pls->ncol1 exceeds the number of free colours.
533  //
534 
535  tmp_colour_pos = i > 0 ? pls->ncol1 * ( (PLFLT) i / ncol1 ) : 0;
536  plcol_interp( pls, &cmap1col, (int) tmp_colour_pos, pls->ncol1 );
537  }
538  else
539  {
540  plcol_interp( pls, &cmap1col, i, ncol1 );
541  }
542 
543 
544  if ( (
545  dev->colour_index[i + pls->ncol0] = cdImageColorAllocate( dev->im_out,
546  cmap1col.r, cmap1col.g, cmap1col.b )
547  ) == -1 )
548  {
549  plwarn( "Problem setting cmap1 in CGM driver." );
550  }
551  else
552  ++dev->totcol; // count the number of colours we use as we use them
553  }
554  }
555 }
556 
557 
558 //--------------------------------------------------------------------------
559 // plD_state_cgm()
560 //
561 // Handle change in PLStream state (color, pen width, fill attribute, etc).
562 //--------------------------------------------------------------------------
563 
564 void
565 plD_state_cgm( PLStream *pls, PLINT op )
566 {
567  cgm_Dev *dev = (cgm_Dev *) pls->dev;
568  PLFLT tmp_colour_pos;
569 
570  switch ( op )
571  {
572  case PLSTATE_WIDTH:
573  cdSetLineWidth( dev->im_out, pls->width );
574  break;
575 
576  case PLSTATE_COLOR0:
577  dev->colour = pls->icol0;
578  if ( dev->colour == PL_RGB_COLOR )
579  {
580  int r = pls->curcolor.r;
581  int g = pls->curcolor.g;
582  int b = pls->curcolor.b;
583  if ( dev->totcol < cdMaxColors )
584  {
585  if ( (
586  dev->colour_index[++dev->totcol] = cdImageColorAllocate( dev->im_out, r, g, b )
587  ) == -1 )
588  plwarn( "Problem changing colour in \"PLSTATE_COLOR0\"" );
589  else
590  dev->colour = dev->totcol;
591  }
592  }
593  dev->fill_colour = dev->colour;
594  break;
595 
596  case PLSTATE_COLOR1:
597  //
598  // Start by checking to see if we have to compensate for cases where
599  // we don't have the full dynamic range of cmap1 at our disposal
600  //
601  if ( dev->ncol1 < pls->ncol1 )
602  {
603  tmp_colour_pos = dev->ncol1 * ( (PLFLT) pls->icol1 / ( pls->ncol1 > 0 ? pls->ncol1 : 1 ) );
604  dev->colour = pls->ncol0 + (int) tmp_colour_pos;
605  }
606  else
607  dev->colour = pls->ncol0 + pls->icol1;
608 
609  dev->fill_colour = dev->colour;
610  break;
611 
612 
613  case PLSTATE_CMAP0:
614  case PLSTATE_CMAP1:
615  //
616  // Code to redefine the entire palette
617  //
618  if ( pls->color )
619  setcmap( pls );
620  break;
621  }
622 }
623 
624 
625 //--------------------------------------------------------------------------
626 // plD_esc_cgm()
627 //
628 // Escape function.
629 //--------------------------------------------------------------------------
630 
631 void plD_esc_cgm( PLStream *pls, PLINT op, void *ptr )
632 {
633  switch ( op )
634  {
635  case PLESC_FILL: // fill
636  fill_polygon( pls );
637  break;
638  }
639 }
640 
641 //--------------------------------------------------------------------------
642 // plD_bop_cgm()
643 //
644 // Set up for the next page.
645 // Advance to next family file if necessary (file output).
646 //--------------------------------------------------------------------------
647 
648 void plD_bop_cgm( PLStream *pls )
649 {
650  cgm_Dev *dev;
651 
652  plGetFam( pls );
653 // force new file if pls->family set for all subsequent calls to plGetFam
654 // n.b. putting this after plGetFam call is important since plinit calls
655 // bop, and you don't want the familying sequence started until after
656 // that first call to bop.
657 
658  pls->famadv = 1;
659 
660  pls->page++;
661 
662 // n.b. pls->dev can change because of an indirect call to plD_init_cgm
663 // from plGetFam if familying is enabled. Thus, wait to define dev until
664 // now.
665 
666  dev = (cgm_Dev *) pls->dev;
667 
668  if ( pls->page == 1 )
669  {
670  dev->im_out = cdImageCreate( pls->xlength, pls->ylength );
671  }
672  else if ( pls->family != 1 )
673  {
674  cdCgmNewPic( dev->im_out, 0 );
675  }
676 
677  setcmap( pls );
678 
679 // Continue to initialise the driver
680 
681  cdSetFillStyle( dev->im_out, 1 ); // Set solid fills
682 
683 //
684 // Due to a border being drawn around the edge of the image, we also
685 // manually, then turn them off again to make edges turn off. By
686 // default the driver thinks they are off, so when we tell the driver
687 // to turn them off it says "they are already off, I wont do anything"
688 // but in reality they are on by default. So what we do is turn them ON
689 // manually, then turn them OFF later.
690 //
691 // Due to a boarder being drawn around the edge of the image, we also
692 // want the edges turned on so we can lay down a rectangle coloured in
693 // the background colour at the start. Once we have drawn our
694 // background box, we then turn edges off for the rest of the page.
695 //
696 
697  cdSetEdgeVis( dev->im_out, 1 ); // turn edges on so we can turn them off!
698 
699  if ( dev->disable_background != 1 )
700  {
701  cdSetEdgeWidth( dev->im_out, pls->xlength / 5 ); // set edge to *really* wide so we can cover the edge of the page completelt
702  cdSetEdgeColor( dev->im_out, 0 ); // set the edge colour to the background colour so we can make a coloured page
703  cdSetFillColor( dev->im_out, 0 ); // set fill colour to background colour so we have a coloured page
704  cdRectangle( dev->im_out, 0, 0, pls->xlength - 1, pls->ylength - 1 ); // Draw a coloured rectangle to act as our "paper"
705  }
706 
707  cdSetEdgeVis( dev->im_out, 0 ); // Turn edges off now
708  cdSetEdgeWidth( dev->im_out, 0 ); // Just to be 100% sure
709 
710  cdSetLineType( dev->im_out, 1 ); // set solid lines
711  cdSetLineWidth( dev->im_out, pls->width ); // set initial line width for each page
712 }
713 
714 //--------------------------------------------------------------------------
715 // plD_tidy_cgm()
716 //
717 // Close graphics file or otherwise clean up.
718 //--------------------------------------------------------------------------
719 
720 void plD_tidy_cgm( PLStream *pls )
721 {
722  cgm_Dev *dev = (cgm_Dev *) pls->dev;
723 
724  if ( pls->family != 1 )
725  {
726  cdImageCgm( dev->im_out, pls->OutFile );
727  }
728 
729  cdImageDestroy( dev->im_out );
730  plCloseFile( pls );
731  free_mem( pls->dev );
732 }
733 
734 //--------------------------------------------------------------------------
735 // plD_eop_cgm()
736 //
737 // End of page.
738 //--------------------------------------------------------------------------
739 
740 void plD_eop_cgm( PLStream *pls )
741 {
742  cgm_Dev *dev = (cgm_Dev *) pls->dev;
743  int i;
744 
745  if ( pls->family == 1 )
746  {
747  cdImageCgm( dev->im_out, pls->OutFile );
748  }
749  for ( i = 0; i < cdMaxColors; ++i )
750  dev->colour_index[i] = -1;
751 
752  dev->fill_colour = dev->colour; // initially set fill and line colour the same
753  dev->last_fill_colour = -1; // set to -1 = unallocated
754  dev->last_line_colour = -1; // set to -1 = unallocated
755 }
756 
757 
758 //#endif
759 
760 
761 #else
762 int
764 {
765  return 0;
766 }
767 
768 #endif // cgm