PLplot 5.15.0
Loading...
Searching...
No Matches
gd.c
Go to the documentation of this file.
1// PNG, GIF, and JPEG device driver based on libgd
2//
3// Copyright (C) 2004 Joao Cardoso
4// Copyright (C) 2002, 2003, 2004 Andrew Roach
5//
6// This file is part of PLplot.
7//
8// PLplot is free software; you can redistribute it and/or modify
9// it under the terms of the GNU Library General Public License as published
10// by the Free Software Foundation; either version 2 of the License, or
11// (at your option) any later version.
12//
13// PLplot is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public License
19// along with PLplot; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21//
22
23// GIF SUPPORT
24//
25// Following the expiration of Unisys's worldwide patents on lzw compression
26// GD 2.0.28+ have reinstated support for GIFs, and so support for this
27// format has been added to the GD family of drivers. GIF's only support
28// 1, 4 and 8 bit, so no truecolour. Why would you want GIFs though ? PNG is
29// a far superior format, not only giving you 1,4,8 and 24 bit, but also
30// better compression and just about all browsers now support them.
31//
32
33//
34// The GD drivers, PNG, GIF, and JPEG, support a number of different options
35// depending on the version of GD installed.
36//
37// If you have installed GD Ver 2.+ you gain support for truecolour (24
38// bit, 16 millionish) modes as well as different line widths. These
39// capibilities are part of GD more so than the GD driver, so they aren't
40// available in any 1.? versions of the driver.
41//
42// 24 bit support is, by default, set to "auto" if you have V2.+ of GD.
43// What this means is the *driver* decides when to use 24 bit or 8 bit
44// modes for PNG files. The logic is rather simple - if you have less than
45// 257 colours, it is set to 8 bit mode, if more then it's in 24 bit mode.
46// This should work fine for most people, most of the time, in most
47// situations; however, it can be overridden in case it has to via the
48// "-drvopt" command line switch. The png driver has two related settings:
49// 8bit and
50// 24bit
51//
52// If either of these command line toggles are set, that mode becomes the
53// standard used regardless of the number of colours used. It can be envoked
54// as follows:
55// x08c -dev png -drvopt 8bit -fam -o 8bitpng
56// or
57// x08c -dev png -drvopt 24bit -fam -o 24bitpng
58//
59// NOTE:
60// The 24 bit PNG file is an RGBA file, not RGB - it includes alpha channel
61// (transparency). Transparency is set to opaque, but the fact it is an
62// RGBA and not an RGB might cause some problems with some viewers.
63// Sadly, I can't do anything about it... sorry.
64//
65// GIF files can only have 256 colours, so naturally truecolour mode is not
66// supported for this sub-driver.
67//
68// Stuff for GD V1.? as well as V2.+
69//
70// optimise
71//
72// From version 1.17 of the GD driver, a command line option has been
73// added to try and optimise the PNG files. If successful, the optimise
74// command will create 4 bit (16 colour) PNGs instead of 8 bit (256 colour)
75// ones. This results in slightly smaller files with no loss in any colour
76// information. The function has no real memory overhead, but does have a
77// slight speed hit in exchange for the optimisation. For example:
78// x08c -dev png -drvopt 8bit,optimise -fam -o 8bitpng
79// forces the png driver to make 8bit pngs, and will then optimise any PNG
80// images with 16 or less colours into a 4 bit PNG. Note, this DOESN'T WORK
81// WITH 24bit PNGs yet, and will never work with JPEGs.
82//
83//
84// Also as of version 1.17 of the GD driver, the options for palette
85// modification previously set with the command line option "-hack" have
86// now been moved to two options settable from the -drvopt switch.
87//
88// def_black15
89//
90// -drvopt def_black15 sets index 15, usually white, to black if index 0,
91// the background colour and usually black, has been set to white from the
92// command line option -bg
93//
94// swp_red15
95//
96// -drvopt swp_red15 swaps index 15, usually white, with index 1, which is
97// usually red. This might be desirable occasionally, but it is principally
98// included for cases when the background has been set on the command line
99// to white, and the "def_black15" option has been issued to redefine index
100// 15 as black. By issuing a command like:
101// x08c -dev png -bg ffffff -drvopt def_black15,swp_red15
102// the driver will set the background to white, then redefine index 15 of
103// cmap0, which is usually white to black, then swap index 2 (red) to 15
104// (white originally, now black), so at the end of the day, the "default"
105// plotting colour is now black. Why do all of this ? It is a very quick
106// way of making a nice web-friendly png without having to redefine the
107// cmaps within your program.
108//
109// smoothlines
110//
111// -drvopt smoothlines=1 turns on anti-aliased line and polygong drawing if
112// you are using a 24bit mode. Unfortunately gd doesn't honour line
113// width when anti-aliasing, so by default it is off.
114//
115
116
117#include "plDevs.h"
118
119#if defined ( PLD_png ) || defined ( PLD_jpeg ) || defined ( PLD_gif )
120
121#include "plplotP.h"
122#include "drivers.h"
123
124#include <gd.h>
125
126// Device info
127//
128// Don't knoq if all this logic is necessary, but basically we are going to
129// start with all three sub-drivers present, then work out way down to two
130// and finally one of each.
131//
132
133PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_gd =
134#if defined ( PLD_png )
135 "png:PNG file:0:gd:39:png\n"
136#endif
137#if defined ( PLD_jpeg )
138 "jpeg:JPEG file:0:gd:40:jpeg\n"
139#endif
140#if defined ( PLD_gif )
141 "gif:GIF file:0:gd:47:gif\n"
142#endif
143;
144
145#if GD2_VERS >= 2
146#ifdef PL_HAVE_FREETYPE
147#define SMOOTH_LINES_OK
148#endif
149#endif
150
151#ifdef PL_HAVE_FREETYPE
152
153//
154// Freetype support has been added to the GD family of drivers using the
155// plfreetype.c module, and implemented as a driver-specific optional extra
156// invoked via the -drvopt command line toggle. It uses the
157// "PLESC_HAS_TEXT" command for rendering within the driver.
158//
159// Freetype support is turned on/off at compile time by defining
160// "PL_HAVE_FREETYPE".
161//
162// To give the user some level of control over the fonts that are used,
163// environmental variables can be set to over-ride the definitions used by
164// the five default plplot fonts.
165//
166// Freetype rendering is used with the command line "-drvopt text".
167// Anti-aliased fonts can be used by issuing "-drvopt text,smooth"
168//
169
170#include "plfreetype.h"
171
172#endif
173
174// Prototypes for functions in this file.
175
176static void fill_polygon( PLStream *pls );
177static void setcmap( PLStream *pls );
178static void plD_init_png_Dev( PLStream *pls );
179static void plD_gd_optimise( PLStream *pls );
180static void plD_black15_gd( PLStream *pls );
181static void plD_red15_gd( PLStream *pls );
182#ifdef PLD_gif
183static void plD_init_gif_Dev( PLStream *pls );
184#endif
185
186#ifdef PL_HAVE_FREETYPE
187
188static void plD_pixel_gd( PLStream *pls, short x, short y );
189static PLINT plD_read_pixel_gd( PLStream *pls, short x, short y );
190static void plD_set_pixel_gd( PLStream *pls, short x, short y, PLINT colour );
191static void init_freetype_lv1( PLStream *pls );
192static void init_freetype_lv2( PLStream *pls );
193
194#endif
195
196// top level declarations
197
198static int NCOLOURS = gdMaxColors;
199
200// In an attempt to fix a problem with the hidden line removal functions
201// that results in hidden lines *not* being removed from "small" plot
202// pages (ie, like a normal video screen), a "virtual" page of much
203// greater size is used to trick the algorithm into working correctly.
204// If, in future, this gets fixed on its own, then don't define
205// "use_experimental_hidden_line_hack"
206//
207
208#define use_experimental_hidden_line_hack
209
210// I think the current version of Freetype supports up to a maximum of
211// 128 grey levels for text smoothing. You can get quite acceptable
212// results with as few as 4 grey-levels. Uusually only about 5 get used
213// anyway, but the question is where, in the "grey spectrum" will they be ?
214// Who knows ? The following define lets you set a maximum limit on the
215// number of grey-levels used. It is really only here for the 24bit mode
216// and could be set to 255, but that would slow things down and use more
217// memory. 64 seems to be a nice compromise, but if you want to change it,
218// then change it here.
219//
220
221#ifndef max_number_of_grey_levels_used_in_text_smoothing
222#define max_number_of_grey_levels_used_in_text_smoothing 64
223#endif
224
225// Not present in versions before 2.0
226
227#ifndef gdImagePalettePixel
228#define gdImagePalettePixel( im, x, y ) ( im )->pixels[( y )][( x )]
229#endif
230
231#if GD2_VERS >= 2
232int plToGdAlpha( PLFLT a )
233{
234 int tmp = (int) ( ( 1.0 - a ) * gdAlphaMax );
235 return tmp;
236}
237#endif
238
239// Struct to hold device-specific info.
240
241typedef struct
242{
243 gdImagePtr im_out; // Graphics pointer
244 PLINT pngx;
245 PLINT pngy;
246
247 int colour; // Current Colour
248 int totcol; // Total number of colours
249 int ncol1; // Actual size of ncol1 we got
250
251 PLFLT scale; // scaling factor to "blow up" to
252 // the "virtual" page in removing hidden lines
253
254 int optimise; // Flag used for 4bit pngs
255 int black15; // Flag used for forcing a black colour
256 int red15; // Flag for swapping red and 15
257
258 unsigned char TRY_BLENDED_ANTIALIASING; // Flag to try and set up BLENDED ANTIALIASING
259
260#if GD2_VERS >= 2
261 int truecolour; // Flag to ALWAYS force 24 bit mode
262 int palette; // Flag to ALWAYS force 8 bit mode
263 unsigned char smooth; // Flag to ask for line smoothing
264#endif
265} png_Dev;
266
267void plD_init_png( PLStream * );
268void plD_line_png( PLStream *, short, short, short, short );
269void plD_polyline_png( PLStream *, short *, short *, PLINT );
270void plD_eop_png( PLStream * );
271void plD_eop_jpeg( PLStream * );
272void plD_bop_png( PLStream * );
273void plD_tidy_png( PLStream * );
274void plD_state_png( PLStream *, PLINT );
275void plD_esc_png( PLStream *, PLINT, void * );
276#ifdef PLD_gif
277void plD_init_gif( PLStream * );
278void plD_eop_gif( PLStream * );
279#endif
280
281#ifdef PLD_png
282
284{
285#ifndef ENABLE_DYNDRIVERS
286 pdt->pl_MenuStr = "PNG file";
287 pdt->pl_DevName = "png";
288#endif
289 pdt->pl_type = plDevType_FileOriented;
290 pdt->pl_seq = 39;
291 pdt->pl_init = (plD_init_fp) plD_init_png;
292 pdt->pl_line = (plD_line_fp) plD_line_png;
293 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_png;
294 pdt->pl_eop = (plD_eop_fp) plD_eop_png;
295 pdt->pl_bop = (plD_bop_fp) plD_bop_png;
296 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_png;
297 pdt->pl_state = (plD_state_fp) plD_state_png;
298 pdt->pl_esc = (plD_esc_fp) plD_esc_png;
299}
300
301#endif
302
303#ifdef PLD_jpeg
304
306{
307#ifndef ENABLE_DYNDRIVERS
308 pdt->pl_MenuStr = "JPEG File";
309 pdt->pl_DevName = "jpeg";
310#endif
311 pdt->pl_type = plDevType_FileOriented;
312 pdt->pl_seq = 40;
313 pdt->pl_init = (plD_init_fp) plD_init_png;
314 pdt->pl_line = (plD_line_fp) plD_line_png;
315 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_png;
316 pdt->pl_eop = (plD_eop_fp) plD_eop_jpeg;
317 pdt->pl_bop = (plD_bop_fp) plD_bop_png;
318 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_png;
319 pdt->pl_state = (plD_state_fp) plD_state_png;
320 pdt->pl_esc = (plD_esc_fp) plD_esc_png;
321}
322#endif
323
324
325#ifdef PLD_gif
326
328{
329#ifndef ENABLE_DYNDRIVERS
330 pdt->pl_MenuStr = "GIF File";
331 pdt->pl_DevName = "gif";
332#endif
333 pdt->pl_type = plDevType_FileOriented;
334 pdt->pl_seq = 47;
335 pdt->pl_init = (plD_init_fp) plD_init_gif;
336 pdt->pl_line = (plD_line_fp) plD_line_png;
337 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_png;
338 pdt->pl_eop = (plD_eop_fp) plD_eop_gif;
339 pdt->pl_bop = (plD_bop_fp) plD_bop_png;
340 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_png;
341 pdt->pl_state = (plD_state_fp) plD_state_png;
342 pdt->pl_esc = (plD_esc_fp) plD_esc_png;
343}
344#endif
345
346
347//--------------------------------------------------------------------------
348// plD_init_png_Dev()
349//
350//--------------------------------------------------------------------------
351
352static void
353plD_init_png_Dev( PLStream *pls )
354{
355 png_Dev *dev;
356
357// Stuff for the driver options, these vars are copied into the driver
358// structure so that everything is thread safe and reenterant.
359//
360
361 static int optimise = 0;
362 static int black15 = 0;
363 static int red15 = 0;
364#if GD2_VERS >= 2
365 static int truecolour = 0;
366 static int palette = 0;
367 static int smooth_line = 0;
368#endif
369#ifdef PL_HAVE_FREETYPE
370 static int freetype = 1;
371 static int smooth_text = 1;
372 FT_Data *FT;
373#endif
374
375 DrvOpt gd_options[] = { { "optimise", DRV_INT, &optimise, "Optimise PNG palette when possible" },
376 { "def_black15", DRV_INT, &black15, "Define idx 15 as black. If the background is \"whiteish\" (from \"-bg\" option), force index 15 (traditionally white) to be \"black\"" },
377 { "swp_red15", DRV_INT, &red15, "Swap index 1 (usually red) and 1 (usually white); always done after \"black15\"; quite useful for quick changes to web pages" },
378#if GD2_VERS >= 2
379 { "8bit", DRV_INT, &palette, "Palette (8 bit) mode" },
380 { "24bit", DRV_INT, &truecolour, "Truecolor (24 bit) mode" },
381 { "smoothlines", DRV_INT, &smooth_line, "Turn line Anti Aliasing on (1) or off (0)" },
382#endif
383#ifdef PL_HAVE_FREETYPE
384 { "text", DRV_INT, &freetype, "Use driver text (FreeType)" },
385 { "smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)" },
386#endif
387 { NULL, DRV_INT, NULL, NULL } };
388
389
390// Allocate and initialize device-specific data
391
392 if ( pls->dev != NULL )
393 free( (void *) pls->dev );
394
395 pls->dev = calloc( 1, (size_t) sizeof ( png_Dev ) );
396 if ( pls->dev == NULL )
397 plexit( "plD_init_png_Dev: Out of memory." );
398
399 dev = (png_Dev *) pls->dev;
400
401 dev->colour = 1; // Set a fall back pen colour in case user doesn't
402
403
404// Check for and set up driver options
405
406 plParseDrvOpts( gd_options );
407
408 dev->black15 = black15;
409 dev->red15 = red15;
410 dev->optimise = optimise;
411
412#if GD2_VERS >= 2
413
414 dev->palette = palette;
415 dev->truecolour = truecolour;
416
417
418
419 if ( ( dev->truecolour > 0 ) && ( dev->palette > 0 ) )
420 plwarn( "Selecting both \"truecolor\" AND \"palette\" driver options is contradictory, so\nI will just use my best judgment.\n" );
421 else if ( dev->truecolour > 0 )
422 NCOLOURS = 16777216;
423 else if ( ( dev->truecolour == 0 ) && ( dev->palette == 0 ) && ( ( pls->ncol1 + pls->ncol0 ) > NCOLOURS ) )
424 {
425 NCOLOURS = 16777216;
426 }
427
428 if ( ( dev->palette == 0 ) && ( dev->optimise == 0 ) && ( smooth_line == 1 ) )
429 dev->smooth = 1; // Allow smoothing of lines if we have a truecolour device
430
431#endif
432
433#ifdef PL_HAVE_FREETYPE
434 if ( freetype )
435 {
436 pls->dev_text = 1; // want to draw text
437 pls->dev_unicode = 1; // want unicode
438
439 // As long as we aren't optimising, we'll try to use better antialaising
440 // We can also only do this if the user wants smoothing, and hasn't
441 // selected a palette mode.
442 //
443
444
445 init_freetype_lv1( pls );
446 FT = (FT_Data *) pls->FT;
447 FT->want_smooth_text = smooth_text > 0 ? 1 : 0;
448 if ( ( dev->optimise == 0 ) && ( dev->palette == 0 ) && ( smooth_text != 0 ) )
449 {
450 FT->BLENDED_ANTIALIASING = 1;
451 dev->truecolour = 1;
452 }
453 }
454
455#endif
456}
457
458//--------------------------------------------------------------------------
459// plD_init_png()
460//
461// Initialize device.
462//--------------------------------------------------------------------------
463
464void plD_init_png( PLStream *pls )
465{
466 png_Dev *dev = NULL;
467
468 pls->termin = 0; // Not an interactive device
469 pls->icol0 = 1;
470 pls->bytecnt = 0;
471 pls->page = 0;
472 pls->dev_fill0 = 1; // Can do solid fills
473
474 if ( !pls->colorset )
475 pls->color = 1; // Is a color device
476
477// Initialize family file info
478 plFamInit( pls );
479
480// Prompt for a file name if not already set
481 plOpenFile( pls );
482
483// Allocate and initialize device-specific data
484 plD_init_png_Dev( pls );
485 dev = (png_Dev *) pls->dev;
486
487 // set dpi and page size defaults if the user has not already set
488 // these with -dpi or -geometry command line options or with
489 // plspage.
490
491 if ( pls->xdpi <= 0. || pls->ydpi <= 0. )
492 {
493 // Use recommended default pixels per inch.
495 }
496
497 if ( pls->xlength == 0 || pls->ylength == 0 )
498 {
499 // Use recommended default pixel width and height.
501 }
502
503 pls->graphx = GRAPHICS_MODE;
504
505 dev->pngx = pls->xlength - 1; // should I use -1 or not???
506 dev->pngy = pls->ylength - 1;
507
508#ifdef use_experimental_hidden_line_hack
509
510 if ( dev->pngx > dev->pngy ) // Work out the scaling factor for the
511 { // "virtual" (oversized) page
512 dev->scale = (PLFLT) ( PIXELS_X - 1 ) / (PLFLT) dev->pngx;
513 }
514 else
515 {
516 dev->scale = (PLFLT) PIXELS_Y / (PLFLT) dev->pngy;
517 }
518#else
519
520 dev->scale = 1.;
521
522#endif
523
524// Convert DPI to pixels/mm
525 plP_setpxl( dev->scale * pls->xdpi / PLPLOT_MM_PER_INCH, dev->scale * pls->ydpi / PLPLOT_MM_PER_INCH );
526
527 plP_setphy( 0, dev->scale * dev->pngx, 0, dev->scale * dev->pngy );
528
529#ifdef PL_HAVE_FREETYPE
530 if ( pls->dev_text )
531 {
532 init_freetype_lv2( pls );
533 }
534#endif
535}
536
537
538#ifdef PLD_gif
539
540//--------------------------------------------------------------------------
541// plD_init_gif_Dev()
542//
543// We need a new initialiser for the GIF version of the GD driver because
544// the GIF one does not support TRUECOLOUR
545//--------------------------------------------------------------------------
546
547static void
548plD_init_gif_Dev( PLStream *pls )
549{
550 png_Dev *dev;
551
552// Stuff for the driver options, these vars are copied into the driver
553// structure so that everything is thread safe and reenterant.
554//
555
556 static int black15 = 0;
557 static int red15 = 0;
558#ifdef PL_HAVE_FREETYPE
559 static int freetype = 1;
560 static int smooth_text = 0;
561 FT_Data *FT;
562#endif
563
564 DrvOpt gd_options[] = { { "def_black15", DRV_INT, &black15, "Define idx 15 as black. If the background is \"whiteish\" (from \"-bg\" option), force index 15 (traditionally white) to be \"black\"" },
565 { "swp_red15", DRV_INT, &red15, "Swap index 1 (usually red) and 1 (usually white); always done after \"black15\"; quite useful for quick changes to web pages" },
566#ifdef PL_HAVE_FREETYPE
567 { "text", DRV_INT, &freetype, "Use driver text (FreeType)" },
568 { "smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)" },
569#endif
570 { NULL, DRV_INT, NULL, NULL } };
571
572
573// Allocate and initialize device-specific data
574
575 if ( pls->dev != NULL )
576 free( (void *) pls->dev );
577
578 pls->dev = calloc( 1, (size_t) sizeof ( png_Dev ) );
579 if ( pls->dev == NULL )
580 plexit( "plD_init_gif_Dev: Out of memory." );
581
582 dev = (png_Dev *) pls->dev;
583
584 dev->colour = 1; // Set a fall back pen colour in case user doesn't
585
586// Check for and set up driver options
587
588 plParseDrvOpts( gd_options );
589
590 dev->black15 = black15;
591 dev->red15 = red15;
592
593 dev->optimise = 0; // Optimise does not work for GIFs... should, but it doesn't
594 dev->palette = 1; // Always use palette mode for GIF files
595 dev->truecolour = 0; // Never have truecolour in GIFS
596
597#ifdef PL_HAVE_FREETYPE
598 if ( freetype )
599 {
600 pls->dev_text = 1; // want to draw text
601 pls->dev_unicode = 1; // want unicode
602
603 init_freetype_lv1( pls );
604 FT = (FT_Data *) pls->FT;
605
606 FT->want_smooth_text = smooth_text > 0 ? 1 : 0;
607 }
608
609#endif
610}
611
612//--------------------------------------------------------------------------
613// plD_init_gif()
614//
615// Initialize device.
616//--------------------------------------------------------------------------
617
618void plD_init_gif( PLStream *pls )
619{
620 png_Dev *dev = NULL;
621
622 pls->termin = 0; // Not an interactive device
623 pls->icol0 = 1;
624 pls->bytecnt = 0;
625 pls->page = 0;
626 pls->dev_fill0 = 1; // Can do solid fills
627
628 if ( !pls->colorset )
629 pls->color = 1; // Is a color device
630
631// Initialize family file info
632 plFamInit( pls );
633
634// Prompt for a file name if not already set
635 plOpenFile( pls );
636
637// Allocate and initialize device-specific data
638 plD_init_gif_Dev( pls );
639 dev = (png_Dev *) pls->dev;
640
641 // set dpi and page size defaults if the user has not already set
642 // these with -dpi or -geometry command line options or with
643 // plspage.
644
645 if ( pls->xdpi <= 0. || pls->ydpi <= 0. )
646 {
647 // Use recommended default pixels per inch.
649 }
650
651 if ( pls->xlength == 0 || pls->ylength == 0 )
652 {
653 // Use recommended default pixel width and height.
655 }
656
657 pls->graphx = GRAPHICS_MODE;
658
659 dev->pngx = pls->xlength - 1; // should I use -1 or not???
660 dev->pngy = pls->ylength - 1;
661
662#ifdef use_experimental_hidden_line_hack
663
664 if ( dev->pngx > dev->pngy ) // Work out the scaling factor for the
665 { // "virtual" (oversized) page
666 dev->scale = (PLFLT) ( PIXELS_X - 1 ) / (PLFLT) dev->pngx;
667 }
668 else
669 {
670 dev->scale = (PLFLT) PIXELS_Y / (PLFLT) dev->pngy;
671 }
672#else
673
674 dev->scale = 1.;
675
676#endif
677
678
679// Convert DPI to pixels/mm
680 plP_setpxl( dev->scale * pls->xdpi / PLPLOT_MM_PER_INCH, dev->scale * pls->ydpi / PLPLOT_MM_PER_INCH );
681
682 plP_setphy( 0, dev->scale * dev->pngx, 0, dev->scale * dev->pngy );
683
684#ifdef PL_HAVE_FREETYPE
685 if ( pls->dev_text )
686 {
687 init_freetype_lv2( pls );
688 }
689#endif
690}
691
692#endif
693
694
695//--------------------------------------------------------------------------
696// plD_line_png()
697//
698// Draw a line in the current color from (x1,y1) to (x2,y2).
699//--------------------------------------------------------------------------
700
701void
702plD_line_png( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
703{
704 png_Dev *dev = (png_Dev *) pls->dev;
705 int x1 = x1a / dev->scale, y1 = y1a / dev->scale, x2 = x2a / dev->scale, y2 = y2a / dev->scale;
706 y1 = dev->pngy - y1;
707 y2 = dev->pngy - y2;
708
709 #ifdef SMOOTH_LINES_OK
710 if ( dev->smooth == 1 )
711 {
712 gdImageSetAntiAliased( dev->im_out, dev->colour );
713 gdImageLine( dev->im_out, x1, y1, x2, y2, gdAntiAliased );
714 }
715 else
716 {
717 gdImageLine( dev->im_out, x1, y1, x2, y2, dev->colour );
718 }
719 #else
720 gdImageLine( dev->im_out, x1, y1, x2, y2, dev->colour );
721 #endif
722}
723
724//--------------------------------------------------------------------------
725// plD_polyline_png()
726//
727// Draw a polyline in the current color.
728//--------------------------------------------------------------------------
729
730void
731plD_polyline_png( PLStream *pls, short *xa, short *ya, PLINT npts )
732{
733 PLINT i;
734
735 for ( i = 0; i < npts - 1; i++ )
736 plD_line_png( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] );
737}
738
739
740//--------------------------------------------------------------------------
741// fill_polygon()
742//
743// Fill polygon described in points pls->dev_x[] and pls->dev_y[].
744//--------------------------------------------------------------------------
745
746static void
748{
749 png_Dev *dev = (png_Dev *) pls->dev;
750
751 int i;
752 gdPoint *points = NULL;
753
754 if ( pls->dev_npts < 1 )
755 return;
756
757 points = malloc( (size_t) pls->dev_npts * sizeof ( gdPoint ) );
758
759 for ( i = 0; i < pls->dev_npts; i++ )
760 {
761 points[i].x = pls->dev_x[i] / dev->scale;
762 points[i].y = dev->pngy - ( pls->dev_y[i] / dev->scale );
763 }
764
765 #ifdef SMOOTH_LINES_OK
766 if ( dev->smooth == 1 )
767 {
768 gdImageSetAntiAliased( dev->im_out, dev->colour );
769 gdImageFilledPolygon( dev->im_out, points, pls->dev_npts, gdAntiAliased );
770 }
771 else
772 {
773 gdImageFilledPolygon( dev->im_out, points, pls->dev_npts, dev->colour );
774 }
775 #else
776 gdImageFilledPolygon( dev->im_out, points, pls->dev_npts, dev->colour );
777 #endif
778
779 free( points );
780}
781
782//--------------------------------------------------------------------------
783// setcmap()
784//
785// Sets up color palette.
786//--------------------------------------------------------------------------
787
788static void
789setcmap( PLStream *pls )
790{
791 int i, ncol1 = pls->ncol1;
792 int ncol0 = pls->ncol0, total_colours;
793 PLColor cmap1col;
794 png_Dev *dev = (png_Dev *) pls->dev;
795 PLFLT tmp_colour_pos;
796
797//
798// Yuckky fix to get rid of the previosuly allocated palette from the
799// GD image
800//
801
802 if ( dev->im_out != NULL )
803 {
804 for ( i = 0; i < 256; i++ )
805 {
806 gdImageColorDeallocate( dev->im_out, i );
807 }
808 }
809
810 if ( ncol0 > NCOLOURS / 2 ) // Check for ridiculous number of colours
811 { // in ncol0, and appropriately adjust the
812 plwarn( "Too many colours in cmap0." ); // number, issuing a
813 ncol0 = NCOLOURS / 2; // warning if it does
814 pls->ncol0 = ncol0;
815 }
816
817 dev->totcol = 0; // Reset the number of colours counter to zero
818
819 total_colours = ncol0 + ncol1; // Work out how many colours are wanted
820
821 if ( total_colours > NCOLOURS ) // Do some rather modest error
822 { // checking to make sure that
823 total_colours = NCOLOURS; // we are not defining more colours
824 ncol1 = total_colours - ncol0; // than we have room for.
825
826 if ( ncol1 <= 0 )
827 {
828 plexit( "Problem setting colourmap in PNG or JPEG driver." );
829 }
830 }
831
832 dev->ncol1 = ncol1; // The actual size of ncol1, regardless of what was asked.
833 // This is dependent on colour slots available.
834 // It might well be the same as ncol1.
835 //
836
837// Initialize cmap 0 colors
838
839 if ( ( ncol0 > 0 ) && ( dev->im_out != NULL ) ) // make sure the program actually asked for cmap0 first
840 {
841 for ( i = 0; i < ncol0; i++ )
842 {
843#if GD2_VERS >= 2
844 gdImageColorAllocateAlpha( dev->im_out,
845 pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b,
846 plToGdAlpha( pls->cmap0[i].a ) );
847#else
848 gdImageColorAllocate( dev->im_out,
849 pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b );
850#endif
851 ++dev->totcol; // count the number of colours we use as we use them
852 }
853 }
854
855// Initialize any remaining slots for cmap1
856
857
858 if ( ( ncol1 > 0 ) && ( dev->im_out != NULL ) ) // make sure that we want to define cmap1 first
859 {
860 for ( i = 0; i < ncol1; i++ )
861 {
862 if ( ncol1 < pls->ncol1 ) // Check the dynamic range of colours
863 {
864 //
865 // Ok, now if we have less colour slots available than are being
866 // defined by pls->ncol1, then we still want to use the full
867 // dynamic range of cmap1 as best we can, so what we do is work
868 // out an approximation to the index in the full dynamic range
869 // in cases when pls->ncol1 exceeds the number of free colours.
870 //
871
872 tmp_colour_pos = i > 0 ? pls->ncol1 * ( (PLFLT) i / ncol1 ) : 0;
873 plcol_interp( pls, &cmap1col, (int) tmp_colour_pos, pls->ncol1 );
874 }
875 else
876 {
877 plcol_interp( pls, &cmap1col, i, ncol1 );
878 }
879
880
881#if GD2_VERS >= 2
882 gdImageColorAllocateAlpha( dev->im_out,
883 cmap1col.r, cmap1col.g, cmap1col.b,
884 plToGdAlpha( cmap1col.a ) );
885#else
886 gdImageColorAllocate( dev->im_out,
887 cmap1col.r, cmap1col.g, cmap1col.b );
888#endif
889
890 ++dev->totcol; // count the number of colours we use as we go
891 }
892 }
893}
894
895
896//--------------------------------------------------------------------------
897// plD_state_png()
898//
899// Handle change in PLStream state (color, pen width, fill attribute, etc).
900//--------------------------------------------------------------------------
901
902void
903plD_state_png( PLStream *pls, PLINT op )
904{
905 png_Dev *dev = (png_Dev *) pls->dev;
906 PLFLT tmp_colour_pos;
907#if GD2_VERS >= 2
908 long temp_col;
909#endif
910
911
912 switch ( op )
913 {
914#if GD2_VERS >= 2
915 case PLSTATE_WIDTH:
916 gdImageSetThickness( dev->im_out, pls->width );
917 break;
918#endif
919
920 case PLSTATE_COLOR0:
921#if GD2_VERS >= 2
922
923 if ( ( pls->icol0 == PL_RGB_COLOR ) || // Should never happen since PL_RGB_COLOR is deprecated, but here for backwards compatibility
924 ( gdImageTrueColor( dev->im_out ) ) ) // We will do this if we are in "TrueColour" mode
925 {
926 if ( ( dev->totcol < NCOLOURS ) || // See if there are slots left, if so we will allocate a new colour
927 ( gdImageTrueColor( dev->im_out ) ) ) // In TrueColour mode we allocate each colour as we come to it
928 {
929 // Next allocate a new colour to a temporary slot since what we do with it will vary depending on if its a palette index or truecolour
930#if GD2_VERS >= 2
931 temp_col = gdImageColorAllocateAlpha( dev->im_out, pls->curcolor.r,
932 pls->curcolor.g, pls->curcolor.b,
933 plToGdAlpha( pls->curcolor.a ) );
934#else
935 temp_col = gdImageColorAllocate( dev->im_out, pls->curcolor.r,
936 pls->curcolor.g, pls->curcolor.b );
937#endif
938
939 if ( gdImageTrueColor( dev->im_out ) )
940 dev->colour = temp_col; // If it's truecolour, then we will directly set dev->colour to our "new" colour
941 else
942 {
943 dev->colour = dev->totcol; // or else, we will just set it to the last colour
944 dev->totcol++; // Bump the total colours for next time round
945 }
946 }
947 }
948 else // just a normal colour allocate, so don't worry about the above stuff, just grab the index
949 {
950 dev->colour = pls->icol0;
951 }
952
953#else
954 dev->colour = pls->icol0;
955 if ( dev->colour == PL_RGB_COLOR )
956 {
957 if ( dev->totcol < NCOLOURS )
958 {
959#if GD2_VERS >= 2
960 gdImageColorAllocateAlpha( dev->im_out, pls->curcolor.r,
961 pls->curcolor.g, pls->curcolor.b,
962 plToGdAlpha( pls->curcolor.a ) );
963#else
964 gdImageColorAllocate( dev->im_out, pls->curcolor.r,
965 pls->curcolor.g, pls->curcolor.b );
966#endif
967 dev->colour = dev->totcol;
968 }
969 }
970#endif
971 break;
972
973 case PLSTATE_COLOR1:
974
975#if GD2_VERS >= 2
976 if ( !gdImageTrueColor( dev->im_out ) )
977 {
978#endif
979 //
980 // Start by checking to see if we have to compensate for cases where
981 // we don't have the full dynamic range of cmap1 at our disposal
982 //
983 if ( dev->ncol1 < pls->ncol1 )
984 {
985 tmp_colour_pos = dev->ncol1 * ( (PLFLT) pls->icol1 / ( pls->ncol1 > 0 ? pls->ncol1 : 1 ) );
986 dev->colour = pls->ncol0 + (int) tmp_colour_pos;
987 }
988 else
989 dev->colour = pls->ncol0 + pls->icol1;
990#if GD2_VERS >= 2
991 }
992 else // it is a truecolour image
993 {
994#if GD2_VERS >= 2
995 dev->colour = gdTrueColorAlpha( pls->curcolor.r, pls->curcolor.g,
996 pls->curcolor.b,
997 plToGdAlpha( pls->curcolor.a ) );
998#else
999 dev->colour = gdTrueColor( pls->curcolor.r, pls->curcolor.g,
1000 pls->curcolor.b );
1001#endif
1002 }
1003#endif
1004 break;
1005
1006
1007 case PLSTATE_CMAP0:
1008 case PLSTATE_CMAP1:
1009
1010#if GD2_VERS >= 2
1011 if ( ( dev->im_out != NULL ) && !gdImageTrueColor( dev->im_out ) )
1012 {
1013#endif
1014
1015 //
1016 // Code to redefine the entire palette
1017 //
1018
1019
1020 if ( pls->color )
1021 setcmap( pls );
1022
1023#if GD2_VERS >= 2
1024 }
1025#endif
1026
1027 break;
1028 }
1029}
1030
1031
1032//--------------------------------------------------------------------------
1033// plD_esc_png()
1034//
1035// Escape function.
1036//--------------------------------------------------------------------------
1037
1038void plD_esc_png( PLStream *pls, PLINT op, void *ptr )
1039{
1040 switch ( op )
1041 {
1042 case PLESC_FILL: // fill
1043 fill_polygon( pls );
1044 break;
1045
1046#ifdef PL_HAVE_FREETYPE
1047 case PLESC_HAS_TEXT:
1048 plD_render_freetype_text( pls, (EscText *) ptr );
1049 break;
1050#endif
1051 }
1052}
1053
1054//--------------------------------------------------------------------------
1055// plD_bop_png()
1056//
1057// Set up for the next page.
1058// Advance to next family file if necessary (file output).
1059//--------------------------------------------------------------------------
1060
1061void plD_bop_png( PLStream *pls )
1062{
1063 png_Dev *dev;
1064
1065 plGetFam( pls );
1066// force new file if pls->family set for all subsequent calls to plGetFam
1067// n.b. putting this after plGetFam call is important since plinit calls
1068// bop, and you don't want the familying sequence started until after
1069// that first call to bop.
1070
1071// n.b. pls->dev can change because of an indirect call to plD_init_png
1072// from plGetFam if familying is enabled. Thus, wait to define dev until
1073// now.
1074
1075 dev = (png_Dev *) pls->dev;
1076
1077 pls->famadv = 1;
1078
1079 pls->page++;
1080
1081 if ( dev->black15 )
1082 plD_black15_gd( pls );
1083 if ( dev->red15 )
1084 plD_red15_gd( pls );
1085
1086#if GD2_VERS >= 2
1087 if ( ( ( ( ( dev->truecolour > 0 ) && ( dev->palette > 0 ) ) || // In an EXTREMELY convaluted
1088 ( ( dev->truecolour == 0 ) && ( dev->palette == 0 ) ) ) && // manner, all this is just
1089 ( ( pls->ncol1 + pls->ncol0 ) <= 256 ) ) || // asking the question, do we
1090 ( ( ( dev->palette > 0 ) && ( dev->truecolour == 0 ) ) ) ) // want truecolour or not ?
1091 {
1092#endif
1093
1094 dev->im_out = gdImageCreate( pls->xlength, pls->ylength );
1095
1096 setcmap( pls );
1097
1098#if GD2_VERS >= 2
1099}
1100else
1101{
1102 dev->im_out = gdImageCreateTrueColor( pls->xlength, pls->ylength );
1104
1105//
1106// In truecolour mode, the background colour GD makes is ALWAYS black, so to
1107// "simulate" (stimulate?) a background colour other than black, we will just
1108// draw a dirty big rectange covering the whole image and colour it in
1109// whatever colour cmap0[0] happens to be.
1110//
1111// Question to C gurus: while it is slightly illogical and ugly, would:
1112// if ((pls->cmap0[0].r+pls->cmap0[0].g+pls->cmap0[0].b)!=0)
1113// be more computationally efficient than:
1114// if ((pls->cmap0[0].r!=0)||(pls->cmap0[0].g!=0)||(pls->cmap0[0].b!=0))
1115// ???
1116//
1117
1118 if ( ( pls->cmap0[0].r != 0 ) || ( pls->cmap0[0].g != 0 ) ||
1119 ( pls->cmap0[0].b != 0 ) || ( pls->cmap0[0].a != 0.0 ) )
1120 {
1121 gdImageFilledRectangle( dev->im_out, 0, 0, pls->xlength - 1, pls->ylength - 1,
1122 gdTrueColorAlpha( pls->cmap0[0].r, pls->cmap0[0].g,
1123 pls->cmap0[0].b,
1124 plToGdAlpha( pls->cmap0[0].a ) ) );
1125 }
1126}
1127
1128
1129// This ensures the line width is set correctly at the beginning of
1130// each page
1131
1132plD_state_png( pls, PLSTATE_WIDTH );
1133
1134#endif
1135}
1136
1137//--------------------------------------------------------------------------
1138// plD_tidy_png()
1139//
1140// Close graphics file or otherwise clean up.
1141//--------------------------------------------------------------------------
1142
1143void plD_tidy_png( PLStream *pls )
1144{
1145#ifdef PL_HAVE_FREETYPE
1146 if ( pls->dev_text )
1147 {
1148 plD_FreeType_Destroy( pls );
1149 }
1150#endif
1151
1152 plCloseFile( pls );
1153 free_mem( pls->dev );
1154}
1155
1156//--------------------------------------------------------------------------
1157// plD_black15_gd()
1158//
1159// This small function simply redefines index 15 of cmap0, which is
1160// usually set to white, to black, but only if index 0, which is usually
1161// black, has been redefined to white (for example, through -bg).
1162//
1163//--------------------------------------------------------------------------
1164
1165void plD_black15_gd( PLStream *pls )
1166{
1167 if ( pls->ncol0 > 15 )
1168 {
1169 if ( ( pls->cmap0[0].r > 227 ) && ( pls->cmap0[0].g > 227 ) && ( pls->cmap0[0].b > 227 ) )
1170 {
1171 pls->cmap0[15].r = 0;
1172 pls->cmap0[15].g = 0;
1173 pls->cmap0[15].b = 0;
1174 }
1175 }
1176}
1177
1178
1179//--------------------------------------------------------------------------
1180// plD_red15_gd()
1181//
1182//
1183// This function swaps index 1, often the default plotting colour, with
1184// index 15, the last defined colour.
1185//
1186// Colour 15 is usually white, and 1 is usually red, so swapping the two
1187// might be desirable occasionally, but it is principally here for cases
1188// when the background has been set on the command line to white, and the
1189// "def_black15" option has been issued to redefine index 15 as black. By
1190// issuing a command like
1191//
1192// ... -bg ffffff -drvopt def_black15,swp_red15
1193//
1194// the driver will set the background to white, then redefine index 15 of
1195// cmap0, which is usually white to black, then swap index 2 (red) to 15
1196// (white originally, now black), so at the end of the day, the "default"
1197// plotting colour is now black. Why do all of this ? It is a very quick
1198// way of making a nice web-friendly png without having to redefine the
1199// cmaps within your program.
1200//
1201// If you don't like it, don't use it !
1202//
1203//--------------------------------------------------------------------------
1204
1205void plD_red15_gd( PLStream *pls )
1206{
1207 char r = pls->cmap0[1].r;
1208 char g = pls->cmap0[1].g;
1209 char b = pls->cmap0[1].b;
1210
1211 if ( pls->ncol0 > 15 )
1212 {
1213 pls->cmap0[1].r = pls->cmap0[15].r;
1214 pls->cmap0[1].g = pls->cmap0[15].r;
1215 pls->cmap0[1].b = pls->cmap0[15].r;
1216
1217 pls->cmap0[15].r = r;
1218 pls->cmap0[15].g = g;
1219 pls->cmap0[15].b = b;
1220 }
1221}
1222
1223
1224//--------------------------------------------------------------------------
1225// plD_gd_optimise()
1226//
1227//
1228// This function pretty much does exactly what it says - it optimises the
1229// PNG file. It does this by checking to see if all the allocated colours
1230// were actually used. If they were not, then it deallocates them. This
1231// function often results in the PNG file being saved as a 4 bit (16
1232// colour) PNG rather than an 8 bit (256 colour) PNG. The file size
1233// difference is not huge, not as great as for GIFs for example (I think
1234// most of the saving comes from removing redundant entries from the
1235// palette entry in the header); however some modest size savings occur.
1236//
1237// The function isn't always successful - the optimiser will always
1238// deallocate unused colours as it finds them, but GD will only deallocate
1239// them "for real" until 16 colours are used up, and then stop since it
1240// doesn't make a difference if you have 17 colours or 255 colours. The
1241// result of this is you may end up with an image using say, 130 colours,
1242// but you will have 240 colour entries, some of which aren't used, and
1243// aren't blanked out.
1244//
1245// Another side-effect of this function is the relative position of the
1246// colour indices MAY shift as colours are deallocated. I really don't
1247// think this should worry anyone, but if it does, don't optimise the
1248// image !
1249//
1250//--------------------------------------------------------------------------
1251
1252void plD_gd_optimise( PLStream *pls )
1253{
1254 png_Dev *dev = (png_Dev *) pls->dev;
1255 int i, j;
1256 char *bbuf;
1257
1258 bbuf = calloc( 256, (size_t) 1 ); // Allocate a buffer to "check off" colours as they are used
1259 if ( bbuf == NULL )
1260 plexit( "plD_gd_optimise: Out of memory." );
1261
1262 for ( i = 0; i < ( pls->xlength - 1 ); i++ ) // Walk through the image pixel by pixel
1263 { // checking to see what colour it is
1264 for ( j = 0; j < ( pls->ylength - 1 ); j++ ) // and adding it to the list of used colours
1265 {
1266 bbuf[gdImagePalettePixel( dev->im_out, i, j )] = 1;
1267 }
1268 }
1269
1270 for ( i = 0; i < 256; i++ ) // next walk over the colours and deallocate
1271 { // unused ones
1272 if ( bbuf[i] == 0 )
1273 gdImageColorDeallocate( dev->im_out, i );
1274 }
1275
1276 free( bbuf );
1277}
1278
1279
1280#ifdef PLD_png
1281
1282//--------------------------------------------------------------------------
1283// plD_eop_png()
1284//
1285// End of page.
1286//--------------------------------------------------------------------------
1287
1288void plD_eop_png( PLStream *pls )
1289{
1290 png_Dev *dev = (png_Dev *) pls->dev;
1291 int im_size = 0;
1292 int png_compression;
1293 void *im_ptr = NULL;
1294 size_t nwrite;
1295
1296 if ( pls->family || pls->page == 1 )
1297 {
1298 if ( dev->optimise )
1299 {
1300#if GD2_VERS >= 2
1301 if ( ( ( ( ( dev->truecolour > 0 ) && ( dev->palette > 0 ) ) || // In an EXTREMELY convaluted
1302 ( ( dev->truecolour == 0 ) && ( dev->palette == 0 ) ) ) && // manner, all this is just
1303 ( ( pls->ncol1 + pls->ncol0 ) <= 256 ) ) || // asking the question, do we
1304 ( ( ( dev->palette > 0 ) && ( dev->truecolour == 0 ) ) ) ) // want truecolour or not ?
1305 {
1306#endif
1307 plD_gd_optimise( pls );
1308
1309#if GD2_VERS >= 2
1310 }
1311#endif
1312 }
1313
1314
1315 // image is written to output file by the driver
1316 // since if the gd.dll is linked to a different c
1317 // lib a crash occurs - this fix works also in Linux
1318 // gdImagePng(dev->im_out, pls->OutFile);
1319 #if GD2_VERS >= 2
1320
1321 //Set the compression/quality level for PNG files.
1322 // pls->dev_compression values of 1-9 translate to the zlib compression values 1-9
1323 // pls->dev_compression values 10 <= compression <= 99 are divided by 10 to get the zlib
1324 // compression value. Values <=0 or greater than 99 are set to 90 which
1325 // translates to a zlib compression value of 9, the highest quality
1326 // of compression or smallest file size or largest computer time required
1327 // to achieve the compression. Smaller zlib compression values correspond
1328 // to lower qualities of compression (larger file size), but lower
1329 // computer times as well.
1330
1331 png_compression = ( ( pls->dev_compression <= 0 ) || ( pls->dev_compression > 99 ) ) ? 90 : pls->dev_compression;
1332 png_compression = ( png_compression > 9 ) ? ( png_compression / 10 ) : png_compression;
1333 im_ptr = gdImagePngPtrEx( dev->im_out, &im_size, png_compression );
1334 #else
1335 im_ptr = gdImagePngPtr( dev->im_out, &im_size );
1336 #endif
1337 if ( im_ptr )
1338 {
1339 nwrite = fwrite( im_ptr, sizeof ( char ), im_size, pls->OutFile );
1340 if ( nwrite != im_size )
1341 plabort( "gd driver: Error writing png file" );
1342 gdFree( im_ptr );
1343 }
1344
1345 gdImageDestroy( dev->im_out );
1346 dev->im_out = NULL;
1347 }
1348}
1349
1350#endif
1351
1352#ifdef PL_HAVE_FREETYPE
1353
1354//--------------------------------------------------------------------------
1355// void plD_pixel_gd (PLStream *pls, short x, short y)
1356//
1357// callback function, of type "plD_pixel_fp", which specifies how a single
1358// pixel is set in the current colour.
1359//--------------------------------------------------------------------------
1360
1361void plD_pixel_gd( PLStream *pls, short x, short y )
1362{
1363 png_Dev *dev = (png_Dev *) pls->dev;
1364
1365 gdImageSetPixel( dev->im_out, x, y, dev->colour );
1366}
1367
1368//--------------------------------------------------------------------------
1369// void plD_set_pixel_gd (PLStream *pls, short x, short y)
1370//
1371// callback function, of type "plD_pixel_fp", which specifies how a single
1372// pixel is set directly to hardware, using the colour provided
1373//--------------------------------------------------------------------------
1374
1375void plD_set_pixel_gd( PLStream *pls, short x, short y, PLINT colour )
1376{
1377 png_Dev *dev = (png_Dev *) pls->dev;
1378 int R, G, B;
1379 int Colour;
1380
1381 G = GetGValue( colour );
1382 R = GetRValue( colour );
1383 B = GetBValue( colour );
1384
1385 Colour = gdImageColorResolve( dev->im_out, R, G, B );
1386 gdImageSetPixel( dev->im_out, x, y, Colour );
1387}
1388
1389//--------------------------------------------------------------------------
1390// PLINT plD_read_pixel_gd (PLStream *pls, short x, short y)
1391//
1392// callback function, of type "plD_read_pixel_gd", which specifies how a
1393// single pixel's RGB is read (in the destination context), then
1394// returns an RGB encoded int with the info for blending.
1395//--------------------------------------------------------------------------
1396
1397PLINT plD_read_pixel_gd( PLStream *pls, short x, short y )
1398{
1399 png_Dev *dev = (png_Dev *) pls->dev;
1400 PLINT colour;
1401 unsigned char R, G, B;
1402
1403 colour = gdImageGetTrueColorPixel( dev->im_out, x, y );
1404
1405 R = gdTrueColorGetRed( colour );
1406 G = gdTrueColorGetGreen( colour );
1407 B = gdTrueColorGetBlue( colour );
1408
1409 colour = RGB( R, G, B );
1410 return ( colour );
1411}
1412
1413
1414//--------------------------------------------------------------------------
1415// void init_freetype_lv1 (PLStream *pls)
1416//
1417// "level 1" initialisation of the freetype library.
1418// "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
1419// memory to the pls->FT structure, then sets up the pixel callback
1420// function.
1421//--------------------------------------------------------------------------
1422
1423static void init_freetype_lv1( PLStream *pls )
1424{
1425 FT_Data *FT;
1426
1427 plD_FreeType_init( pls );
1428
1429 FT = (FT_Data *) pls->FT;
1430 FT->pixel = (plD_pixel_fp) plD_pixel_gd;
1431 FT->read_pixel = (plD_read_pixel_fp) plD_read_pixel_gd;
1432 FT->set_pixel = (plD_set_pixel_fp) plD_set_pixel_gd;
1433}
1434
1435//--------------------------------------------------------------------------
1436// void init_freetype_lv2 (PLStream *pls)
1437//
1438// "Level 2" initialisation of the freetype library.
1439// "Level 2" fills in a few setting that aren't public until after the
1440// graphics sub-syetm has been initialised.
1441// The "level 2" initialisation fills in a few things that are defined
1442// later in the initialisation process for the GD driver.
1443//
1444// FT->scale is a scaling factor to convert co-ordinates. This is used by
1445// the GD and other drivers to scale back a larger virtual page and this
1446// eliminate the "hidden line removal bug". Set it to 1 if your device
1447// doesn't have scaling.
1448//
1449// Some coordinate systems have zero on the bottom, others have zero on
1450// the top. Freetype does it one way, and most everything else does it the
1451// other. To make sure everything is working ok, we have to "flip" the
1452// coordinates, and to do this we need to know how big in the Y dimension
1453// the page is, and whether we have to invert the page or leave it alone.
1454//
1455// FT->ymax specifies the size of the page FT->invert_y=1 tells us to
1456// invert the y-coordinates, FT->invert_y=0 will not invert the
1457// coordinates.
1458//--------------------------------------------------------------------------
1459
1460static void init_freetype_lv2( PLStream *pls )
1461{
1462 png_Dev *dev = (png_Dev *) pls->dev;
1463 FT_Data *FT = (FT_Data *) pls->FT;
1464
1465 FT->scale = dev->scale;
1466 FT->ymax = dev->pngy;
1467 FT->invert_y = 1;
1468 FT->smooth_text = 0;
1469
1470 if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) ) // do we want to at least *try* for smoothing ?
1471 {
1472 FT->ncol0_org = pls->ncol0; // save a copy of the original size of ncol0
1473 FT->ncol0_xtra = NCOLOURS - ( pls->ncol1 + pls->ncol0 ); // work out how many free slots we have
1474 FT->ncol0_width = FT->ncol0_xtra / ( pls->ncol0 - 1 ); // find out how many different shades of anti-aliasing we can do
1475 if ( FT->ncol0_width > 4 ) // are there enough colour slots free for text smoothing ?
1476 {
1477 if ( FT->ncol0_width > max_number_of_grey_levels_used_in_text_smoothing )
1478 FT->ncol0_width = max_number_of_grey_levels_used_in_text_smoothing; // set a maximum number of shades
1479 plscmap0n( FT->ncol0_org + ( FT->ncol0_width * pls->ncol0 ) ); // redefine the size of cmap0
1480// the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
1481// call in plscmap0 which (a) leads to segfaults since the GD image is
1482// not defined at this point and (b) would be inefficient in any case since
1483// setcmap is always called later (see plD_bop_png) to update the driver
1484// color palette to be consistent with cmap0.
1485 {
1486 PLINT level_save;
1487 level_save = pls->level;
1488 pls->level = 0;
1489 pl_set_extended_cmap0( pls, FT->ncol0_width, FT->ncol0_org ); // call the function to add the extra cmap0 entries and calculate stuff
1490 pls->level = level_save;
1491 }
1492 FT->smooth_text = 1; // Yippee ! We had success setting up the extended cmap0
1493 }
1494 else
1495 plwarn( "Insufficient colour slots available in CMAP0 to do text smoothing." );
1496 }
1497 else if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 1 ) ) // If we have a truecolour device, we wont even bother trying to change the palette
1498 {
1499 FT->smooth_text = 1;
1500 }
1501}
1502
1503#endif
1504
1505
1506#ifdef PLD_jpeg
1507
1508//--------------------------------------------------------------------------
1509// plD_eop_jpeg()
1510//
1511// End of page.
1512//--------------------------------------------------------------------------
1513
1514void plD_eop_jpeg( PLStream *pls )
1515{
1516 png_Dev *dev = (png_Dev *) pls->dev;
1517 int im_size = 0;
1518 void *im_ptr = NULL;
1519 size_t nwrite;
1520 int jpeg_compression;
1521
1522 if ( pls->family || pls->page == 1 )
1523 {
1524 // Set the compression/quality level for JPEG files
1525 // The higher the value, the bigger/better the image is
1526 //
1527 if ( ( pls->dev_compression <= 0 ) || ( pls->dev_compression > 99 ) )
1528 jpeg_compression = 90;
1529 else
1530 jpeg_compression = pls->dev_compression;
1531
1532 // image is written to output file by the driver
1533 // since if the gd.dll is linked to a different c
1534 // lib a crash occurs - this fix works also in Linux
1535 // gdImageJpeg(dev->im_out, pls->OutFile, jpeg_compression);
1536 im_ptr = gdImageJpegPtr( dev->im_out, &im_size, jpeg_compression );
1537 if ( im_ptr )
1538 {
1539 nwrite = fwrite( im_ptr, sizeof ( char ), im_size, pls->OutFile );
1540 if ( nwrite != im_size )
1541 plabort( "gd driver: Error writing png file" );
1542 gdFree( im_ptr );
1543 }
1544
1545 gdImageDestroy( dev->im_out );
1546 dev->im_out = NULL;
1547 }
1548}
1549
1550#endif
1551
1552#ifdef PLD_gif
1553
1554//--------------------------------------------------------------------------
1555// plD_eop_gif()
1556//
1557// End of page.
1558//--------------------------------------------------------------------------
1559
1560void plD_eop_gif( PLStream *pls )
1561{
1562 png_Dev *dev = (png_Dev *) pls->dev;
1563 int im_size = 0;
1564 void *im_ptr = NULL;
1565 size_t nwrite;
1566
1567 if ( pls->family || pls->page == 1 )
1568 {
1569 // image is written to output file by the driver
1570 // since if the gd.dll is linked to a different c
1571 // lib a crash occurs - this fix works also in Linux
1572 // gdImageGif(dev->im_out, pls->OutFile);
1573 im_ptr = gdImageGifPtr( dev->im_out, &im_size );
1574 if ( im_ptr )
1575 {
1576 nwrite = fwrite( im_ptr, sizeof ( char ), im_size, pls->OutFile );
1577 if ( nwrite != im_size )
1578 plabort( "gd driver: Error writing png file" );
1579 gdFree( im_ptr );
1580 }
1581
1582 gdImageDestroy( dev->im_out );
1583 dev->im_out = NULL;
1584 }
1585}
1586
1587#endif
1588
1589
1590//#endif
1591
1592
1593#else
1594int
1596{
1597 return 0;
1598}
1599
1600#endif // PNG
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition disptab.h:68
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition disptab.h:72
void(* plD_bop_fp)(struct PLStream_struct *)
Definition disptab.h:71
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition disptab.h:73
void(* plD_eop_fp)(struct PLStream_struct *)
Definition disptab.h:70
@ plDevType_FileOriented
Definition disptab.h:13
void(* plD_init_fp)(struct PLStream_struct *)
Definition disptab.h:67
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition disptab.h:74
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition disptab.h:69
PLDLLIMPEXP_DRIVER void plD_dispatch_init_gif(PLDispatchTable *pdt)
PLDLLIMPEXP_DRIVER void plD_dispatch_init_jpeg(PLDispatchTable *pdt)
PLDLLIMPEXP_DRIVER void plD_dispatch_init_png(PLDispatchTable *pdt)
int pldummy_png()
Definition gd.c:1595
int plParseDrvOpts(DrvOpt *acc_opt)
Definition plargs.c:1461
void plP_state(PLINT op)
Definition plcore.c:256
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition plcore.c:4238
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition plcore.c:4249
static PLStream * pls[PL_NSTREAMS]
Definition plcore.h:88
void plFamInit(PLStream *pls)
Definition plctrl.c:2751
void plwarn(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1863
void plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
Definition plctrl.c:2530
void plCloseFile(PLStream *pls)
Definition plctrl.c:2635
void plOpenFile(PLStream *pls)
Definition plctrl.c:2571
void plexit(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1958
void plGetFam(PLStream *pls)
Definition plctrl.c:2780
void plabort(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1894
#define PLDLLIMPEXP_DRIVER
Definition pldll.h:81
#define PLPLOT_MM_PER_INCH
Definition plplotP.h:313
#define GRAPHICS_MODE
Definition plplotP.h:288
#define PIXELS_X
Definition plplotP.h:304
#define PLSTATE_WIDTH
Definition plplotP.h:362
#define PLSTATE_CMAP0
Definition plplotP.h:366
#define PLPLOT_DEFAULT_WIDTH_PIXELS
Definition plplotP.h:329
#define PLPLOT_DEFAULT_HEIGHT_PIXELS
Definition plplotP.h:330
#define PLSTATE_COLOR1
Definition plplotP.h:364
#define PLPLOT_DEFAULT_PIXELS_PER_INCH
Definition plplotP.h:326
#define PLSTATE_CMAP1
Definition plplotP.h:367
#define PL_RGB_COLOR
Definition plplotP.h:285
@ DRV_INT
Definition plplotP.h:758
#define PLSTATE_COLOR0
Definition plplotP.h:363
#define free_mem(a)
Definition plplotP.h:182
#define PIXELS_Y
Definition plplotP.h:305
#define PLESC_HAS_TEXT
Definition plplot.h:290
float PLFLT
Definition plplot.h:163
#define plscmap0n
Definition plplot.h:793
#define plspage
Definition plplot.h:831
#define PLESC_FILL
Definition plplot.h:279
int PLINT
Definition plplot.h:181
static void fill_polygon(PLStream *pls)
Definition ps.c:677