1 /*
2
3 rl2paint -- Cairco graphics functions
4
5 version 0.1, 2013 September 29
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the RasterLite2 library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2013
28 the Initial Developer. All Rights Reserved.
29
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41
42 */
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <math.h>
47
48 #ifdef LOADABLE_EXTENSION
49 #include "rasterlite2/sqlite.h"
50 #endif
51
52 #include "rasterlite2/rasterlite2.h"
53 #include "rasterlite2/rl2graphics.h"
54 #include "rasterlite2_private.h"
55
56 #ifdef __ANDROID__ /* Android specific */
57 #include <cairo.h>
58 #include <cairo-svg.h>
59 #include <cairo-pdf.h>
60 #else /* any other standard platform (Win, Linux, Mac) */
61 #include <cairo/cairo.h>
62 #include <cairo/cairo-svg.h>
63 #include <cairo/cairo-pdf.h>
64 #endif /* end Android conditionals */
65
66 #define RL2_SURFACE_IMG 2671
67 #define RL2_SURFACE_SVG 1267
68 #define RL2_SURFACE_PDF 1276
69
70 struct rl2_graphics_pen
71 {
72 /* a struct wrapping a Cairo Pen */
73 double red;
74 double green;
75 double blue;
76 double alpha;
77 double width;
78 double lengths[4];
79 int lengths_count;
80 };
81
82 struct rl2_graphics_brush
83 {
84 /* a struct wrapping a Cairo Brush */
85 int is_solid_color;
86 int is_linear_gradient;
87 int is_pattern;
88 double red;
89 double green;
90 double blue;
91 double alpha;
92 double x0;
93 double y0;
94 double x1;
95 double y1;
96 double red2;
97 double green2;
98 double blue2;
99 double alpha2;
100 cairo_pattern_t *pattern;
101 };
102
103 typedef struct rl2_graphics_context
104 {
105 /* a Cairo based painting context */
106 int type;
107 cairo_surface_t *surface;
108 cairo_surface_t *clip_surface;
109 cairo_t *cairo;
110 cairo_t *clip_cairo;
111 struct rl2_graphics_pen current_pen;
112 struct rl2_graphics_brush current_brush;
113 double font_red;
114 double font_green;
115 double font_blue;
116 double font_alpha;
117 int is_font_outlined;
118 double font_outline_width;
119 } RL2GraphContext;
120 typedef RL2GraphContext *RL2GraphContextPtr;
121
122 typedef struct rl2_graphics_pattern_brush
123 {
124 /* a Cairo based pattern brush */
125 int width;
126 int height;
127 unsigned char *rgba;
128 cairo_surface_t *bitmap;
129 cairo_pattern_t *pattern;
130 } RL2GraphPatternBrush;
131 typedef RL2GraphPatternBrush *RL2GraphPatternBrushPtr;
132
133 typedef struct rl2_graphics_font
134 {
135 /* a struct wrapping a Cairo Font */
136 double size;
137 int is_outlined;
138 double outline_width;
139 int style;
140 int weight;
141 double red;
142 double green;
143 double blue;
144 double alpha;
145 } RL2GraphFont;
146 typedef RL2GraphFont *RL2GraphFontPtr;
147
148 typedef struct rl2_graphics_bitmap
149 {
150 /* a Cairo based symbol bitmap */
151 int width;
152 int height;
153 unsigned char *rgba;
154 cairo_surface_t *bitmap;
155 cairo_pattern_t *pattern;
156 } RL2GraphBitmap;
157 typedef RL2GraphBitmap *RL2GraphBitmapPtr;
158
159 RL2_DECLARE rl2GraphicsContextPtr
rl2_graph_create_context(int width,int height)160 rl2_graph_create_context (int width, int height)
161 {
162 /* creating a generic Graphics Context */
163 RL2GraphContextPtr ctx;
164
165 ctx = malloc (sizeof (RL2GraphContext));
166 if (!ctx)
167 return NULL;
168
169 ctx->type = RL2_SURFACE_IMG;
170 ctx->clip_surface = NULL;
171 ctx->clip_cairo = NULL;
172 ctx->surface =
173 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
174 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
175 ;
176 else
177 goto error1;
178 ctx->cairo = cairo_create (ctx->surface);
179 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
180 goto error2;
181
182 /* setting up a default Black Pen */
183 ctx->current_pen.red = 0.0;
184 ctx->current_pen.green = 0.0;
185 ctx->current_pen.blue = 0.0;
186 ctx->current_pen.alpha = 1.0;
187 ctx->current_pen.width = 1.0;
188 ctx->current_pen.lengths[0] = 1.0;
189 ctx->current_pen.lengths_count = 1;
190
191 /* setting up a default Black Brush */
192 ctx->current_brush.is_solid_color = 1;
193 ctx->current_brush.is_linear_gradient = 0;
194 ctx->current_brush.is_pattern = 0;
195 ctx->current_brush.red = 0.0;
196 ctx->current_brush.green = 0.0;
197 ctx->current_brush.blue = 0.0;
198 ctx->current_brush.alpha = 1.0;
199 ctx->current_brush.pattern = NULL;
200
201 /* priming a transparent background */
202 cairo_rectangle (ctx->cairo, 0, 0, width, height);
203 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
204 cairo_fill (ctx->cairo);
205
206 /* setting up default Font options */
207 ctx->font_red = 0.0;
208 ctx->font_green = 0.0;
209 ctx->font_blue = 0.0;
210 ctx->font_alpha = 1.0;
211 ctx->is_font_outlined = 0;
212 ctx->font_outline_width = 0.0;
213 return (rl2GraphicsContextPtr) ctx;
214 error2:
215 cairo_destroy (ctx->cairo);
216 cairo_surface_destroy (ctx->surface);
217 return NULL;
218 error1:
219 cairo_surface_destroy (ctx->surface);
220 return NULL;
221 }
222
223 static void
destroy_context(RL2GraphContextPtr ctx)224 destroy_context (RL2GraphContextPtr ctx)
225 {
226 /* memory cleanup - destroying a Graphics Context */
227 if (ctx == NULL)
228 return;
229 cairo_destroy (ctx->cairo);
230 cairo_surface_destroy (ctx->surface);
231 free (ctx);
232 }
233
234 static void
destroy_svg_context(RL2GraphContextPtr ctx)235 destroy_svg_context (RL2GraphContextPtr ctx)
236 {
237 /* freeing an SVG Graphics Context */
238 if (ctx == NULL)
239 return;
240 cairo_surface_show_page (ctx->surface);
241 cairo_destroy (ctx->cairo);
242 cairo_surface_finish (ctx->surface);
243 cairo_surface_destroy (ctx->surface);
244 free (ctx);
245 }
246
247 static void
destroy_pdf_context(RL2GraphContextPtr ctx)248 destroy_pdf_context (RL2GraphContextPtr ctx)
249 {
250 /* freeing an PDF Graphics Context */
251 if (ctx == NULL)
252 return;
253 cairo_surface_finish (ctx->clip_surface);
254 cairo_surface_destroy (ctx->clip_surface);
255 cairo_destroy (ctx->clip_cairo);
256 cairo_surface_show_page (ctx->surface);
257 cairo_destroy (ctx->cairo);
258 cairo_surface_finish (ctx->surface);
259 cairo_surface_destroy (ctx->surface);
260 free (ctx);
261 }
262
263 RL2_DECLARE void
rl2_graph_destroy_context(rl2GraphicsContextPtr context)264 rl2_graph_destroy_context (rl2GraphicsContextPtr context)
265 {
266 /* memory cleanup - destroying a Graphics Context */
267 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
268 if (ctx == NULL)
269 return;
270 if (ctx->type == RL2_SURFACE_SVG)
271 destroy_svg_context (ctx);
272 else if (ctx->type == RL2_SURFACE_PDF)
273 destroy_pdf_context (ctx);
274 else
275 destroy_context (ctx);
276 }
277
278 RL2_DECLARE rl2GraphicsContextPtr
rl2_graph_create_svg_context(const char * path,int width,int height)279 rl2_graph_create_svg_context (const char *path, int width, int height)
280 {
281 /* creating an SVG Graphics Context */
282 RL2GraphContextPtr ctx;
283
284 ctx = malloc (sizeof (RL2GraphContext));
285 if (!ctx)
286 return NULL;
287
288 ctx->type = RL2_SURFACE_SVG;
289 ctx->clip_surface = NULL;
290 ctx->clip_cairo = NULL;
291 ctx->surface =
292 cairo_svg_surface_create (path, (double) width, (double) height);
293
294 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
295 ;
296 else
297 goto error1;
298 ctx->cairo = cairo_create (ctx->surface);
299 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
300 goto error2;
301
302 /* setting up a default Black Pen */
303 ctx->current_pen.red = 0.0;
304 ctx->current_pen.green = 0.0;
305 ctx->current_pen.blue = 0.0;
306 ctx->current_pen.alpha = 1.0;
307 ctx->current_pen.width = 1.0;
308 ctx->current_pen.lengths[0] = 1.0;
309 ctx->current_pen.lengths_count = 1;
310
311 /* setting up a default Black Brush */
312 ctx->current_brush.is_solid_color = 1;
313 ctx->current_brush.is_linear_gradient = 0;
314 ctx->current_brush.is_pattern = 0;
315 ctx->current_brush.red = 0.0;
316 ctx->current_brush.green = 0.0;
317 ctx->current_brush.blue = 0.0;
318 ctx->current_brush.alpha = 1.0;
319 ctx->current_brush.pattern = NULL;
320
321 /* priming a transparent background */
322 cairo_rectangle (ctx->cairo, 0, 0, width, height);
323 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
324 cairo_fill (ctx->cairo);
325
326 /* setting up default Font options */
327 ctx->font_red = 0.0;
328 ctx->font_green = 0.0;
329 ctx->font_blue = 0.0;
330 ctx->font_alpha = 1.0;
331 ctx->is_font_outlined = 0;
332 ctx->font_outline_width = 0.0;
333 return (rl2GraphicsContextPtr) ctx;
334 error2:
335 cairo_destroy (ctx->cairo);
336 cairo_surface_destroy (ctx->surface);
337 return NULL;
338 error1:
339 cairo_surface_destroy (ctx->surface);
340 return NULL;
341 }
342
343 RL2_DECLARE rl2GraphicsContextPtr
rl2_graph_create_pdf_context(const char * path,int dpi,double page_width,double page_height,double margin_width,double margin_height)344 rl2_graph_create_pdf_context (const char *path, int dpi, double page_width,
345 double page_height, double margin_width,
346 double margin_height)
347 {
348 /* creating a PDF Graphics Context */
349 RL2GraphContextPtr ctx;
350 double scale = 72.0 / (double) dpi;
351 double page2_width = page_width * 72.0;
352 double page2_height = page_height * 72.0;
353 double horz_margin_sz = margin_width * 72.0;
354 double vert_margin_sz = margin_height * 72.0;
355 double img_width = (page_width - (margin_width * 2.0)) * 72.0;
356 double img_height = (page_height - (margin_height * 2.0)) * 72.0;
357
358 ctx = malloc (sizeof (RL2GraphContext));
359 if (ctx == NULL)
360 return NULL;
361
362 ctx->type = RL2_SURFACE_PDF;
363 ctx->clip_surface = NULL;
364 ctx->clip_cairo = NULL;
365 ctx->surface = cairo_pdf_surface_create (path, page2_width, page2_height);
366 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
367 ;
368 else
369 goto error1;
370 ctx->cairo = cairo_create (ctx->surface);
371 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
372 goto error2;
373
374 /* priming a transparent background */
375 cairo_rectangle (ctx->cairo, 0, 0, page2_width, page2_height);
376 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
377 cairo_fill (ctx->cairo);
378
379 /* clipped surface respecting free margins */
380 ctx->clip_surface =
381 cairo_surface_create_for_rectangle (ctx->surface, horz_margin_sz,
382 vert_margin_sz, img_width,
383 img_height);
384 if (cairo_surface_status (ctx->clip_surface) == CAIRO_STATUS_SUCCESS)
385 ;
386 else
387 goto error3;
388 ctx->clip_cairo = cairo_create (ctx->clip_surface);
389 if (cairo_status (ctx->clip_cairo) == CAIRO_STATUS_NO_MEMORY)
390 goto error4;
391
392 /* setting up a default Black Pen */
393 ctx->current_pen.red = 0.0;
394 ctx->current_pen.green = 0.0;
395 ctx->current_pen.blue = 0.0;
396 ctx->current_pen.alpha = 1.0;
397 ctx->current_pen.width = 1.0;
398 ctx->current_pen.lengths[0] = 1.0;
399 ctx->current_pen.lengths_count = 1;
400
401 /* setting up a default Black Brush */
402 ctx->current_brush.is_solid_color = 1;
403 ctx->current_brush.is_linear_gradient = 0;
404 ctx->current_brush.is_pattern = 0;
405 ctx->current_brush.red = 0.0;
406 ctx->current_brush.green = 0.0;
407 ctx->current_brush.blue = 0.0;
408 ctx->current_brush.alpha = 1.0;
409 ctx->current_brush.pattern = NULL;
410
411 /* scaling accordingly to DPI resolution */
412 cairo_scale (ctx->clip_cairo, scale, scale);
413
414 /* setting up default Font options */
415 ctx->font_red = 0.0;
416 ctx->font_green = 0.0;
417 ctx->font_blue = 0.0;
418 ctx->font_alpha = 1.0;
419 ctx->is_font_outlined = 0;
420 ctx->font_outline_width = 0.0;
421 return (rl2GraphicsContextPtr) ctx;
422 error4:
423 cairo_destroy (ctx->clip_cairo);
424 cairo_surface_destroy (ctx->clip_surface);
425 cairo_destroy (ctx->cairo);
426 cairo_surface_destroy (ctx->surface);
427 return NULL;
428 error3:
429 cairo_surface_destroy (ctx->clip_surface);
430 cairo_destroy (ctx->cairo);
431 cairo_surface_destroy (ctx->surface);
432 return NULL;
433 error2:
434 cairo_destroy (ctx->cairo);
435 cairo_surface_destroy (ctx->surface);
436 return NULL;
437 error1:
438 cairo_surface_destroy (ctx->surface);
439 return NULL;
440 }
441
442 static cairo_status_t
pdf_write_func(void * ptr,const unsigned char * data,unsigned int length)443 pdf_write_func (void *ptr, const unsigned char *data, unsigned int length)
444 {
445 /* writing into the in-memory PDF target */
446 rl2PrivMemPdfPtr mem = (rl2PrivMemPdfPtr) ptr;
447 if (mem == NULL)
448 return CAIRO_STATUS_WRITE_ERROR;
449
450 if (mem->write_offset + (int) length < mem->size)
451 {
452 /* inserting into the current buffer */
453 memcpy (mem->buffer + mem->write_offset, data, length);
454 mem->write_offset += length;
455 }
456 else
457 {
458 /* expanding the current buffer */
459 int new_sz = mem->size + length + (64 * 1024);
460 unsigned char *save = mem->buffer;
461 mem->buffer = realloc (mem->buffer, new_sz);
462 if (mem->buffer == NULL)
463 {
464 free (save);
465 return CAIRO_STATUS_WRITE_ERROR;
466 }
467 mem->size = new_sz;
468 memcpy (mem->buffer + mem->write_offset, data, length);
469 mem->write_offset += length;
470 }
471 return CAIRO_STATUS_SUCCESS;
472 }
473
474 RL2_DECLARE rl2GraphicsContextPtr
rl2_graph_create_mem_pdf_context(rl2MemPdfPtr mem_pdf,int dpi,double page_width,double page_height,double margin_width,double margin_height)475 rl2_graph_create_mem_pdf_context (rl2MemPdfPtr mem_pdf, int dpi,
476 double page_width, double page_height,
477 double margin_width, double margin_height)
478 {
479 /* creating an in-memory PDF Graphics Context */
480 RL2GraphContextPtr ctx;
481 double scale = 72.0 / (double) dpi;
482 double page2_width = page_width * 72.0;
483 double page2_height = page_height * 72.0;
484 double horz_margin_sz = margin_width * 72.0;
485 double vert_margin_sz = margin_height * 72.0;
486 double img_width = (page_width - (margin_width * 2.0)) * 72.0;
487 double img_height = (page_height - (margin_height * 2.0)) * 72.0;
488
489 ctx = malloc (sizeof (RL2GraphContext));
490 if (ctx == NULL)
491 return NULL;
492
493 ctx->type = RL2_SURFACE_PDF;
494 ctx->clip_surface = NULL;
495 ctx->clip_cairo = NULL;
496 ctx->surface =
497 cairo_pdf_surface_create_for_stream (pdf_write_func, mem_pdf,
498 page2_width, page2_height);
499 if (cairo_surface_status (ctx->surface) == CAIRO_STATUS_SUCCESS)
500 ;
501 else
502 goto error1;
503 ctx->cairo = cairo_create (ctx->surface);
504 if (cairo_status (ctx->cairo) == CAIRO_STATUS_NO_MEMORY)
505 goto error2;
506
507 /* priming a transparent background */
508 cairo_rectangle (ctx->cairo, 0, 0, page2_width, page2_height);
509 cairo_set_source_rgba (ctx->cairo, 0.0, 0.0, 0.0, 0.0);
510 cairo_fill (ctx->cairo);
511
512 /* clipped surface respecting free margins */
513 ctx->clip_surface =
514 cairo_surface_create_for_rectangle (ctx->surface, horz_margin_sz,
515 vert_margin_sz, img_width,
516 img_height);
517 if (cairo_surface_status (ctx->clip_surface) == CAIRO_STATUS_SUCCESS)
518 ;
519 else
520 goto error3;
521 ctx->clip_cairo = cairo_create (ctx->clip_surface);
522 if (cairo_status (ctx->clip_cairo) == CAIRO_STATUS_NO_MEMORY)
523 goto error4;
524
525 /* setting up a default Black Pen */
526 ctx->current_pen.red = 0.0;
527 ctx->current_pen.green = 0.0;
528 ctx->current_pen.blue = 0.0;
529 ctx->current_pen.alpha = 1.0;
530 ctx->current_pen.width = 1.0;
531 ctx->current_pen.lengths[0] = 1.0;
532 ctx->current_pen.lengths_count = 1;
533
534 /* setting up a default Black Brush */
535 ctx->current_brush.is_solid_color = 1;
536 ctx->current_brush.is_linear_gradient = 0;
537 ctx->current_brush.is_pattern = 0;
538 ctx->current_brush.red = 0.0;
539 ctx->current_brush.green = 0.0;
540 ctx->current_brush.blue = 0.0;
541 ctx->current_brush.alpha = 1.0;
542 ctx->current_brush.pattern = NULL;
543
544 /* scaling accordingly to DPI resolution */
545 cairo_scale (ctx->clip_cairo, scale, scale);
546
547 /* setting up default Font options */
548 ctx->font_red = 0.0;
549 ctx->font_green = 0.0;
550 ctx->font_blue = 0.0;
551 ctx->font_alpha = 1.0;
552 ctx->is_font_outlined = 0;
553 ctx->font_outline_width = 0.0;
554 return (rl2GraphicsContextPtr) ctx;
555 error4:
556 cairo_destroy (ctx->clip_cairo);
557 cairo_surface_destroy (ctx->clip_surface);
558 cairo_destroy (ctx->cairo);
559 cairo_surface_destroy (ctx->surface);
560 return NULL;
561 error3:
562 cairo_surface_destroy (ctx->clip_surface);
563 cairo_destroy (ctx->cairo);
564 cairo_surface_destroy (ctx->surface);
565 return NULL;
566 error2:
567 cairo_destroy (ctx->cairo);
568 cairo_surface_destroy (ctx->surface);
569 return NULL;
570 error1:
571 cairo_surface_destroy (ctx->surface);
572 return NULL;
573 }
574
575 RL2_DECLARE int
rl2_graph_set_pen(rl2GraphicsContextPtr context,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha,double width,int style)576 rl2_graph_set_pen (rl2GraphicsContextPtr context, unsigned char red,
577 unsigned char green, unsigned char blue, unsigned char alpha,
578 double width, int style)
579 {
580 /* creating a Color Pen */
581 double d_red = (double) red / 255.0;
582 double d_green = (double) green / 255.0;
583 double d_blue = (double) blue / 255.0;
584 double d_alpha = (double) alpha / 255.0;
585 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
586 if (ctx == NULL)
587 return 0;
588
589 ctx->current_pen.width = width;
590 ctx->current_pen.red = d_red;
591 ctx->current_pen.green = d_green;
592 ctx->current_pen.blue = d_blue;
593 ctx->current_pen.alpha = d_alpha;
594 switch (style)
595 {
596 case RL2_PENSTYLE_DOT:
597 ctx->current_pen.lengths[0] = 2;
598 ctx->current_pen.lengths[1] = 2;
599 ctx->current_pen.lengths_count = 2;
600 break;
601 case RL2_PENSTYLE_LONG_DASH:
602 ctx->current_pen.lengths[0] = 16;
603 ctx->current_pen.lengths[1] = 8;
604 ctx->current_pen.lengths_count = 2;
605 break;
606 case RL2_PENSTYLE_SHORT_DASH:
607 ctx->current_pen.lengths[0] = 8;
608 ctx->current_pen.lengths[1] = 4;
609 ctx->current_pen.lengths_count = 2;
610 break;
611 case RL2_PENSTYLE_DOT_DASH:
612 ctx->current_pen.lengths[0] = 8;
613 ctx->current_pen.lengths[1] = 4;
614 ctx->current_pen.lengths[2] = 2;
615 ctx->current_pen.lengths[3] = 4;
616 ctx->current_pen.lengths_count = 4;
617 break;
618 default:
619 ctx->current_pen.lengths[0] = 1;
620 ctx->current_pen.lengths[1] = 0;
621 ctx->current_pen.lengths_count = 2;
622 };
623 return 1;
624 }
625
626 RL2_DECLARE int
rl2_graph_set_brush(rl2GraphicsContextPtr context,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)627 rl2_graph_set_brush (rl2GraphicsContextPtr context, unsigned char red,
628 unsigned char green, unsigned char blue,
629 unsigned char alpha)
630 {
631 /* setting up a Color Brush */
632 double d_red = (double) red / 255.0;
633 double d_green = (double) green / 255.0;
634 double d_blue = (double) blue / 255.0;
635 double d_alpha = (double) alpha / 255.0;
636 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
637 if (ctx == NULL)
638 return 0;
639
640 ctx->current_brush.is_solid_color = 1;
641 ctx->current_brush.is_linear_gradient = 0;
642 ctx->current_brush.is_pattern = 0;
643 ctx->current_brush.red = d_red;
644 ctx->current_brush.green = d_green;
645 ctx->current_brush.blue = d_blue;
646 ctx->current_brush.alpha = d_alpha;
647 return 1;
648 }
649
650 RL2_DECLARE int
rl2_graph_set_linear_gradient_brush(rl2GraphicsContextPtr context,double x,double y,double width,double height,unsigned char red1,unsigned char green1,unsigned char blue1,unsigned char alpha1,unsigned char red2,unsigned char green2,unsigned char blue2,unsigned char alpha2)651 rl2_graph_set_linear_gradient_brush (rl2GraphicsContextPtr context, double x,
652 double y, double width, double height,
653 unsigned char red1, unsigned char green1,
654 unsigned char blue1, unsigned char alpha1,
655 unsigned char red2, unsigned char green2,
656 unsigned char blue2, unsigned char alpha2)
657 {
658 /* setting up a Linear Gradient Brush */
659 double d_red = (double) red1 / 255.0;
660 double d_green = (double) green1 / 255.0;
661 double d_blue = (double) blue1 / 255.0;
662 double d_alpha = (double) alpha1 / 255.0;
663 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
664 if (ctx == NULL)
665 return 0;
666
667 ctx->current_brush.is_solid_color = 0;
668 ctx->current_brush.is_linear_gradient = 1;
669 ctx->current_brush.is_pattern = 0;
670 ctx->current_brush.red = d_red;
671 ctx->current_brush.green = d_green;
672 ctx->current_brush.blue = d_blue;
673 ctx->current_brush.alpha = d_alpha;
674 ctx->current_brush.x0 = x;
675 ctx->current_brush.y0 = y;
676 ctx->current_brush.x1 = x + width;
677 ctx->current_brush.y1 = y + height;
678 d_red = (double) red2 / 255.0;
679 d_green = (double) green2 / 255.0;
680 d_blue = (double) blue2 / 255.0;
681 d_alpha = (double) alpha2 / 255.0;
682 ctx->current_brush.red2 = d_red;
683 ctx->current_brush.green2 = d_green;
684 ctx->current_brush.blue2 = d_blue;
685 ctx->current_brush.alpha2 = d_alpha;
686 return 1;
687 }
688
689 RL2_DECLARE int
rl2_graph_set_pattern_brush(rl2GraphicsContextPtr context,rl2GraphicsPatternPtr brush)690 rl2_graph_set_pattern_brush (rl2GraphicsContextPtr context,
691 rl2GraphicsPatternPtr brush)
692 {
693 /* setting up a Pattern Brush */
694 RL2GraphPatternBrushPtr pattern = (RL2GraphPatternBrushPtr) brush;
695 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
696
697 if (ctx == NULL)
698 return 0;
699 if (pattern == NULL)
700 return 0;
701
702 ctx->current_brush.is_solid_color = 0;
703 ctx->current_brush.is_linear_gradient = 0;
704 ctx->current_brush.is_pattern = 1;
705
706 ctx->current_brush.pattern = pattern->pattern;
707 return 1;
708 }
709
710 RL2_DECLARE int
rl2_graph_set_font(rl2GraphicsContextPtr context,rl2GraphicsFontPtr font)711 rl2_graph_set_font (rl2GraphicsContextPtr context, rl2GraphicsFontPtr font)
712 {
713 /* setting up the current font */
714 cairo_t *cairo;
715 int style = CAIRO_FONT_SLANT_NORMAL;
716 int weight = CAIRO_FONT_WEIGHT_NORMAL;
717 double size;
718 RL2GraphFontPtr fnt = (RL2GraphFontPtr) font;
719 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
720
721 if (ctx == NULL)
722 return 0;
723 if (fnt == NULL)
724 return 0;
725 if (ctx->type == RL2_SURFACE_PDF)
726 cairo = ctx->clip_cairo;
727 else
728 cairo = ctx->cairo;
729
730 if (fnt->style == RL2_FONTSTYLE_ITALIC)
731 style = CAIRO_FONT_SLANT_ITALIC;
732 if (fnt->weight == RL2_FONTWEIGHT_BOLD)
733 weight = CAIRO_FONT_WEIGHT_BOLD;
734 cairo_select_font_face (cairo, "monospace", style, weight);
735 size = fnt->size;
736 if (fnt->is_outlined)
737 size += fnt->outline_width;
738 cairo_set_font_size (cairo, size);
739 ctx->font_red = fnt->red;
740 ctx->font_green = fnt->green;
741 ctx->font_blue = fnt->blue;
742 ctx->font_alpha = fnt->alpha;
743 ctx->is_font_outlined = fnt->is_outlined;
744 ctx->font_outline_width = fnt->outline_width;
745
746 return 1;
747 }
748
749 static int
rl2cr_endian_arch()750 rl2cr_endian_arch ()
751 {
752 /* checking if target CPU is a little-endian one */
753 union cvt
754 {
755 unsigned char byte[4];
756 int int_value;
757 } convert;
758 convert.int_value = 1;
759 if (convert.byte[0] == 0)
760 return 0;
761 return 1;
762 }
763
764 static void
adjust_for_endianness(unsigned char * rgbaArray,int width,int height)765 adjust_for_endianness (unsigned char *rgbaArray, int width, int height)
766 {
767 /* Adjusting from RGBA to ARGB respecting platform endianness */
768 int x;
769 int y;
770 unsigned char red;
771 unsigned char green;
772 unsigned char blue;
773 unsigned char alpha;
774 unsigned char *p_in = rgbaArray;
775 unsigned char *p_out = rgbaArray;
776 int little_endian = rl2cr_endian_arch ();
777
778 for (y = 0; y < height; y++)
779 {
780 for (x = 0; x < width; x++)
781 {
782 red = *p_in++;
783 green = *p_in++;
784 blue = *p_in++;
785 alpha = *p_in++;
786 if (little_endian)
787 {
788 *p_out++ = blue;
789 *p_out++ = green;
790 *p_out++ = red;
791 *p_out++ = alpha;
792 }
793 else
794 {
795 *p_out++ = alpha;
796 *p_out++ = red;
797 *p_out++ = green;
798 *p_out++ = blue;
799 }
800 }
801 }
802 }
803
804 RL2_DECLARE rl2GraphicsPatternPtr
rl2_graph_create_pattern(unsigned char * rgbaArray,int width,int height)805 rl2_graph_create_pattern (unsigned char *rgbaArray, int width, int height)
806 {
807 /* creating a pattern brush */
808 RL2GraphPatternBrushPtr pattern;
809
810 if (rgbaArray == NULL)
811 return NULL;
812
813 adjust_for_endianness (rgbaArray, width, height);
814 pattern = malloc (sizeof (RL2GraphPatternBrush));
815 if (pattern == NULL)
816 return NULL;
817 pattern->width = width;
818 pattern->height = height;
819 pattern->rgba = rgbaArray;
820 pattern->bitmap =
821 cairo_image_surface_create_for_data (rgbaArray, CAIRO_FORMAT_ARGB32,
822 width, height, width * 4);
823 pattern->pattern = cairo_pattern_create_for_surface (pattern->bitmap);
824 cairo_pattern_set_extend (pattern->pattern, CAIRO_EXTEND_REPEAT);
825 return (rl2GraphicsPatternPtr) pattern;
826 }
827
828 RL2_DECLARE void
rl2_graph_destroy_pattern(rl2GraphicsPatternPtr brush)829 rl2_graph_destroy_pattern (rl2GraphicsPatternPtr brush)
830 {
831 /* destroying a pattern brush */
832 RL2GraphPatternBrushPtr pattern = (RL2GraphPatternBrushPtr) brush;
833
834 if (pattern == NULL)
835 return;
836
837 cairo_pattern_destroy (pattern->pattern);
838 cairo_surface_destroy (pattern->bitmap);
839 if (pattern->rgba != NULL)
840 free (pattern->rgba);
841 free (pattern);
842 }
843
844 RL2_DECLARE rl2GraphicsFontPtr
rl2_graph_create_font(double size,int style,int weight)845 rl2_graph_create_font (double size, int style, int weight)
846 {
847 /* creating a font */
848 RL2GraphFontPtr fnt;
849
850 fnt = malloc (sizeof (RL2GraphFont));
851 if (fnt == NULL)
852 return NULL;
853 if (size < 1.0)
854 fnt->size = 1.0;
855 else if (size > 32.0)
856 fnt->size = 32.0;
857 else
858 fnt->size = size;
859 if (style == RL2_FONTSTYLE_ITALIC)
860 fnt->style = RL2_FONTSTYLE_ITALIC;
861 else
862 fnt->style = RL2_FONTSTYLE_NORMAL;
863 if (weight == RL2_FONTWEIGHT_BOLD)
864 fnt->weight = RL2_FONTWEIGHT_BOLD;
865 else
866 fnt->weight = RL2_FONTWEIGHT_NORMAL;
867 fnt->is_outlined = 0;
868 fnt->outline_width = 0.0;
869 fnt->red = 0.0;
870 fnt->green = 0.0;
871 fnt->blue = 0.0;
872 fnt->alpha = 1.0;
873 return (rl2GraphicsFontPtr) fnt;
874 }
875
876 RL2_DECLARE void
rl2_graph_destroy_font(rl2GraphicsFontPtr font)877 rl2_graph_destroy_font (rl2GraphicsFontPtr font)
878 {
879 /* destroying a font */
880 RL2GraphFontPtr fnt = (RL2GraphFontPtr) font;
881
882 if (fnt == NULL)
883 return;
884
885 free (fnt);
886 }
887
888 RL2_DECLARE int
rl2_graph_font_set_color(rl2GraphicsFontPtr font,unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)889 rl2_graph_font_set_color (rl2GraphicsFontPtr font, unsigned char red,
890 unsigned char green, unsigned char blue,
891 unsigned char alpha)
892 {
893 /* setting up the font color */
894 RL2GraphFontPtr fnt = (RL2GraphFontPtr) font;
895
896 if (fnt == NULL)
897 return 0;
898
899 fnt->red = (double) red / 255.0;
900 fnt->green = (double) green / 255.0;
901 fnt->blue = (double) blue / 255.0;
902 fnt->alpha = (double) alpha / 255.0;
903 return 1;
904 }
905
906 RL2_DECLARE int
rl2_graph_font_set_outline(rl2GraphicsFontPtr font,double width)907 rl2_graph_font_set_outline (rl2GraphicsFontPtr font, double width)
908 {
909 /* setting up the font outline */
910 RL2GraphFontPtr fnt = (RL2GraphFontPtr) font;
911
912 if (fnt == NULL)
913 return 0;
914
915 if (width <= 0.0)
916 {
917 fnt->is_outlined = 0;
918 fnt->outline_width = 0.0;
919 }
920 else
921 {
922 fnt->is_outlined = 1;
923 fnt->outline_width = width;
924 }
925 return 1;
926 }
927
928 RL2_DECLARE rl2GraphicsBitmapPtr
rl2_graph_create_bitmap(unsigned char * rgbaArray,int width,int height)929 rl2_graph_create_bitmap (unsigned char *rgbaArray, int width, int height)
930 {
931 /* creating a bitmap */
932 RL2GraphBitmapPtr bmp;
933
934 if (rgbaArray == NULL)
935 return NULL;
936
937 adjust_for_endianness (rgbaArray, width, height);
938 bmp = malloc (sizeof (RL2GraphBitmap));
939 if (bmp == NULL)
940 return NULL;
941 bmp->width = width;
942 bmp->height = height;
943 bmp->rgba = rgbaArray;
944 bmp->bitmap =
945 cairo_image_surface_create_for_data (rgbaArray, CAIRO_FORMAT_ARGB32,
946 width, height, width * 4);
947 bmp->pattern = cairo_pattern_create_for_surface (bmp->bitmap);
948 return (rl2GraphicsBitmapPtr) bmp;
949 }
950
951 RL2_DECLARE void
rl2_graph_destroy_bitmap(rl2GraphicsBitmapPtr bitmap)952 rl2_graph_destroy_bitmap (rl2GraphicsBitmapPtr bitmap)
953 {
954 /* destroying a bitmap */
955 RL2GraphBitmapPtr bmp = (RL2GraphBitmapPtr) bitmap;
956
957 if (bmp == NULL)
958 return;
959
960 cairo_pattern_destroy (bmp->pattern);
961 cairo_surface_destroy (bmp->bitmap);
962 if (bmp->rgba != NULL)
963 free (bmp->rgba);
964 free (bmp);
965 }
966
967 static void
set_current_brush(RL2GraphContextPtr ctx)968 set_current_brush (RL2GraphContextPtr ctx)
969 {
970 /* setting up the current Brush */
971 cairo_t *cairo;
972 if (ctx->type == RL2_SURFACE_PDF)
973 cairo = ctx->clip_cairo;
974 else
975 cairo = ctx->cairo;
976 if (ctx->current_brush.is_solid_color)
977 {
978 /* using a Solid Color Brush */
979 cairo_set_source_rgba (cairo, ctx->current_brush.red,
980 ctx->current_brush.green,
981 ctx->current_brush.blue,
982 ctx->current_brush.alpha);
983 }
984 else if (ctx->current_brush.is_linear_gradient)
985 {
986 /* using a Linear Gradient Brush */
987 cairo_pattern_t *pattern =
988 cairo_pattern_create_linear (ctx->current_brush.x0,
989 ctx->current_brush.y0,
990 ctx->current_brush.x1,
991 ctx->current_brush.y1);
992 cairo_pattern_add_color_stop_rgba (pattern, 0.0,
993 ctx->current_brush.red,
994 ctx->current_brush.green,
995 ctx->current_brush.blue,
996 ctx->current_brush.alpha);
997 cairo_pattern_add_color_stop_rgba (pattern, 1.0,
998 ctx->current_brush.red2,
999 ctx->current_brush.green2,
1000 ctx->current_brush.blue2,
1001 ctx->current_brush.alpha2);
1002 cairo_set_source (cairo, pattern);
1003 cairo_pattern_destroy (pattern);
1004 }
1005 else if (ctx->current_brush.is_pattern)
1006 {
1007 /* using a Pattern Brush */
1008 cairo_set_source (cairo, ctx->current_brush.pattern);
1009 }
1010 }
1011
1012 static void
set_current_pen(RL2GraphContextPtr ctx)1013 set_current_pen (RL2GraphContextPtr ctx)
1014 {
1015 /* setting up the current Pen */
1016 cairo_t *cairo;
1017 if (ctx->type == RL2_SURFACE_PDF)
1018 cairo = ctx->clip_cairo;
1019 else
1020 cairo = ctx->cairo;
1021 cairo_set_line_width (cairo, ctx->current_pen.width);
1022 cairo_set_source_rgba (cairo, ctx->current_pen.red,
1023 ctx->current_pen.green, ctx->current_pen.blue,
1024 ctx->current_pen.alpha);
1025 cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
1026 cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
1027 cairo_set_dash (cairo, ctx->current_pen.lengths,
1028 ctx->current_pen.lengths_count, 0.0);
1029 }
1030
1031 RL2_DECLARE int
rl2_graph_draw_rectangle(rl2GraphicsContextPtr context,double x,double y,double width,double height)1032 rl2_graph_draw_rectangle (rl2GraphicsContextPtr context, double x, double y,
1033 double width, double height)
1034 {
1035 /* Drawing a filled rectangle */
1036 cairo_t *cairo;
1037 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1038 if (ctx == NULL)
1039 return 0;
1040 if (ctx->type == RL2_SURFACE_PDF)
1041 cairo = ctx->clip_cairo;
1042 else
1043 cairo = ctx->cairo;
1044
1045 cairo_rectangle (cairo, x, y, width, height);
1046 set_current_brush (ctx);
1047 cairo_fill_preserve (cairo);
1048 set_current_pen (ctx);
1049 cairo_stroke (cairo);
1050 return 1;
1051 }
1052
1053 RL2_DECLARE int
rl2_graph_draw_rounded_rectangle(rl2GraphicsContextPtr context,double x,double y,double width,double height,double radius)1054 rl2_graph_draw_rounded_rectangle (rl2GraphicsContextPtr context, double x,
1055 double y, double width, double height,
1056 double radius)
1057 {
1058 /* Drawing a filled rectangle with rounded corners */
1059 cairo_t *cairo;
1060 double degrees = M_PI / 180.0;
1061 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1062 if (ctx == NULL)
1063 return 0;
1064 if (ctx->type == RL2_SURFACE_PDF)
1065 cairo = ctx->clip_cairo;
1066 else
1067 cairo = ctx->cairo;
1068
1069 cairo_new_sub_path (cairo);
1070 cairo_arc (cairo, x + width - radius, y + radius, radius,
1071 -90 * degrees, 0 * degrees);
1072 cairo_arc (cairo, x + width - radius, y + height - radius, radius,
1073 0 * degrees, 90 * degrees);
1074 cairo_arc (cairo, x + radius, y + height - radius, radius,
1075 90 * degrees, 180 * degrees);
1076 cairo_arc (cairo, x + radius, y + radius, radius, 180 * degrees,
1077 270 * degrees);
1078 cairo_close_path (cairo);
1079 set_current_brush (ctx);
1080 cairo_fill_preserve (cairo);
1081 set_current_pen (ctx);
1082 cairo_stroke (cairo);
1083 return 1;
1084 }
1085
1086 RL2_DECLARE int
rl2_graph_draw_ellipse(rl2GraphicsContextPtr context,double x,double y,double width,double height)1087 rl2_graph_draw_ellipse (rl2GraphicsContextPtr context, double x, double y,
1088 double width, double height)
1089 {
1090 /* Drawing a filled ellipse */
1091 cairo_t *cairo;
1092 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1093 if (ctx == NULL)
1094 return 0;
1095 if (ctx->type == RL2_SURFACE_PDF)
1096 cairo = ctx->clip_cairo;
1097 else
1098 cairo = ctx->cairo;
1099
1100 cairo_save (cairo);
1101 cairo_translate (cairo, x + (width / 2.0), y + (height / 2.0));
1102 cairo_scale (cairo, width / 2.0, height / 2.0);
1103 cairo_arc (cairo, 0.0, 0.0, 1.0, 0.0, 2.0 * M_PI);
1104 cairo_restore (cairo);
1105 set_current_brush (ctx);
1106 cairo_fill_preserve (cairo);
1107 set_current_pen (ctx);
1108 cairo_stroke (cairo);
1109 return 1;
1110 }
1111
1112 RL2_DECLARE int
rl2_graph_draw_circle_sector(rl2GraphicsContextPtr context,double center_x,double center_y,double radius,double from_angle,double to_angle)1113 rl2_graph_draw_circle_sector (rl2GraphicsContextPtr context, double center_x,
1114 double center_y, double radius, double from_angle,
1115 double to_angle)
1116 {
1117 /* drawing a filled circular sector */
1118 cairo_t *cairo;
1119 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1120 if (ctx == NULL)
1121 return 0;
1122 if (ctx->type == RL2_SURFACE_PDF)
1123 cairo = ctx->clip_cairo;
1124 else
1125 cairo = ctx->cairo;
1126
1127 cairo_move_to (cairo, center_x, center_y);
1128 cairo_arc (cairo, center_x, center_y, radius, from_angle, to_angle);
1129 cairo_line_to (cairo, center_x, center_y);
1130 set_current_brush (ctx);
1131 cairo_fill_preserve (cairo);
1132 set_current_pen (ctx);
1133 cairo_stroke (cairo);
1134 return 1;
1135 }
1136
1137 RL2_DECLARE int
rl2_graph_stroke_line(rl2GraphicsContextPtr context,double x0,double y0,double x1,double y1)1138 rl2_graph_stroke_line (rl2GraphicsContextPtr context, double x0, double y0,
1139 double x1, double y1)
1140 {
1141 /* Stroking a line */
1142 cairo_t *cairo;
1143 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1144 if (ctx == NULL)
1145 return 0;
1146 if (ctx->type == RL2_SURFACE_PDF)
1147 cairo = ctx->clip_cairo;
1148 else
1149 cairo = ctx->cairo;
1150
1151 cairo_move_to (cairo, x0, y0);
1152 cairo_line_to (cairo, x1, y1);
1153 set_current_pen (ctx);
1154 cairo_stroke (cairo);
1155 return 1;
1156 }
1157
1158 RL2_DECLARE int
rl2_graph_move_to_point(rl2GraphicsContextPtr context,double x,double y)1159 rl2_graph_move_to_point (rl2GraphicsContextPtr context, double x, double y)
1160 {
1161 /* Moving to a Path Point */
1162 cairo_t *cairo;
1163 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1164 if (ctx == NULL)
1165 return 0;
1166 if (ctx->type == RL2_SURFACE_PDF)
1167 cairo = ctx->clip_cairo;
1168 else
1169 cairo = ctx->cairo;
1170 cairo_move_to (cairo, x, y);
1171 return 1;
1172 }
1173
1174 RL2_DECLARE int
rl2_graph_add_line_to_path(rl2GraphicsContextPtr context,double x,double y)1175 rl2_graph_add_line_to_path (rl2GraphicsContextPtr context, double x, double y)
1176 {
1177 /* Adding a Line to a Path */
1178 cairo_t *cairo;
1179 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1180 if (ctx == NULL)
1181 return 0;
1182 if (ctx->type == RL2_SURFACE_PDF)
1183 cairo = ctx->clip_cairo;
1184 else
1185 cairo = ctx->cairo;
1186 cairo_line_to (cairo, x, y);
1187 return 1;
1188 }
1189
1190 RL2_DECLARE int
rl2_graph_close_subpath(rl2GraphicsContextPtr context)1191 rl2_graph_close_subpath (rl2GraphicsContextPtr context)
1192 {
1193 /* Closing a SubPath */
1194 cairo_t *cairo;
1195 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1196 if (ctx == NULL)
1197 return 0;
1198 if (ctx->type == RL2_SURFACE_PDF)
1199 cairo = ctx->clip_cairo;
1200 else
1201 cairo = ctx->cairo;
1202 cairo_close_path (cairo);
1203 return 1;
1204 }
1205
1206 RL2_DECLARE int
rl2_graph_stroke_path(rl2GraphicsContextPtr context,int preserve)1207 rl2_graph_stroke_path (rl2GraphicsContextPtr context, int preserve)
1208 {
1209 /* Stroking a path */
1210 cairo_t *cairo;
1211 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1212 if (ctx == NULL)
1213 return 0;
1214 if (ctx->type == RL2_SURFACE_PDF)
1215 cairo = ctx->clip_cairo;
1216 else
1217 cairo = ctx->cairo;
1218
1219 set_current_pen (ctx);
1220 if (preserve == RL2_PRESERVE_PATH)
1221 cairo_stroke_preserve (cairo);
1222 else
1223 cairo_stroke (cairo);
1224 return 1;
1225 }
1226
1227 RL2_DECLARE int
rl2_graph_fill_path(rl2GraphicsContextPtr context,int preserve)1228 rl2_graph_fill_path (rl2GraphicsContextPtr context, int preserve)
1229 {
1230 /* Filling a path */
1231 cairo_t *cairo;
1232 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1233 if (ctx == NULL)
1234 return 0;
1235 if (ctx->type == RL2_SURFACE_PDF)
1236 cairo = ctx->clip_cairo;
1237 else
1238 cairo = ctx->cairo;
1239
1240 set_current_brush (ctx);
1241 if (preserve == RL2_PRESERVE_PATH)
1242 cairo_fill_preserve (cairo);
1243 else
1244 cairo_fill (cairo);
1245 return 1;
1246 }
1247
1248 RL2_DECLARE int
rl2_graph_get_text_extent(rl2GraphicsContextPtr context,const char * text,double * pre_x,double * pre_y,double * width,double * height,double * post_x,double * post_y)1249 rl2_graph_get_text_extent (rl2GraphicsContextPtr context, const char *text,
1250 double *pre_x, double *pre_y, double *width,
1251 double *height, double *post_x, double *post_y)
1252 {
1253 /* measuring the text extent (using the current font) */
1254 cairo_t *cairo;
1255 cairo_text_extents_t extents;
1256 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1257
1258 if (ctx == NULL)
1259 return 0;
1260 if (ctx->type == RL2_SURFACE_PDF)
1261 cairo = ctx->clip_cairo;
1262 else
1263 cairo = ctx->cairo;
1264
1265 cairo_text_extents (cairo, text, &extents);
1266 *pre_x = extents.x_bearing;
1267 *pre_y = extents.y_bearing;
1268 *width = extents.width;
1269 *height = extents.height;
1270 *post_x = extents.x_advance;
1271 *post_y = extents.y_advance;
1272 return 1;
1273 }
1274
1275 RL2_DECLARE int
rl2_graph_draw_text(rl2GraphicsContextPtr context,const char * text,double x,double y,double angle)1276 rl2_graph_draw_text (rl2GraphicsContextPtr context, const char *text, double x,
1277 double y, double angle)
1278 {
1279 /* drawing a text string (using the current font) */
1280 cairo_t *cairo;
1281 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1282
1283 if (ctx == NULL)
1284 return 0;
1285 if (ctx->type == RL2_SURFACE_PDF)
1286 cairo = ctx->clip_cairo;
1287 else
1288 cairo = ctx->cairo;
1289
1290 cairo_save (cairo);
1291 cairo_translate (cairo, x, y);
1292 cairo_rotate (cairo, angle);
1293 if (ctx->is_font_outlined)
1294 {
1295 /* outlined font */
1296 cairo_move_to (cairo, 0.0, 0.0);
1297 cairo_text_path (cairo, text);
1298 cairo_set_source_rgba (cairo, ctx->font_red, ctx->font_green,
1299 ctx->font_blue, ctx->font_alpha);
1300 cairo_fill_preserve (cairo);
1301 cairo_set_source_rgba (cairo, 1.0, 1.0, 1.0, ctx->font_alpha);
1302 cairo_set_line_width (cairo, ctx->font_outline_width);
1303 cairo_stroke (cairo);
1304 }
1305 else
1306 {
1307 /* no outline */
1308 cairo_set_source_rgba (cairo, ctx->font_red, ctx->font_green,
1309 ctx->font_blue, ctx->font_alpha);
1310 cairo_move_to (cairo, 0.0, 0.0);
1311 cairo_show_text (cairo, text);
1312 }
1313 cairo_restore (cairo);
1314 return 1;
1315 }
1316
1317 RL2_DECLARE int
rl2_graph_draw_bitmap(rl2GraphicsContextPtr context,rl2GraphicsBitmapPtr bitmap,int x,int y)1318 rl2_graph_draw_bitmap (rl2GraphicsContextPtr context,
1319 rl2GraphicsBitmapPtr bitmap, int x, int y)
1320 {
1321 /* drawing a symbol bitmap */
1322 cairo_t *cairo;
1323 cairo_surface_t *surface;
1324 RL2GraphBitmapPtr bmp = (RL2GraphBitmapPtr) bitmap;
1325 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1326
1327 if (ctx == NULL)
1328 return 0;
1329 if (bmp == NULL)
1330 return 0;
1331 if (ctx->type == RL2_SURFACE_PDF)
1332 {
1333 surface = ctx->clip_surface;
1334 cairo = ctx->clip_cairo;
1335 }
1336 else
1337 {
1338 surface = ctx->surface;
1339 cairo = ctx->cairo;
1340 }
1341
1342 cairo_save (cairo);
1343 cairo_scale (cairo, 1, 1);
1344 cairo_translate (cairo, x, y);
1345 cairo_set_source (cairo, bmp->pattern);
1346 cairo_rectangle (cairo, 0, 0, bmp->width, bmp->height);
1347 cairo_fill (cairo);
1348 cairo_restore (cairo);
1349 cairo_surface_flush (surface);
1350 return 1;
1351 }
1352
1353 RL2_DECLARE int
rl2_graph_draw_rescaled_bitmap(rl2GraphicsContextPtr context,rl2GraphicsBitmapPtr bitmap,double scale_x,double scale_y,int x,int y)1354 rl2_graph_draw_rescaled_bitmap (rl2GraphicsContextPtr context,
1355 rl2GraphicsBitmapPtr bitmap, double scale_x,
1356 double scale_y, int x, int y)
1357 {
1358 /* drawing a rescaled bitmap */
1359 cairo_t *cairo;
1360 cairo_surface_t *surface;
1361 RL2GraphBitmapPtr bmp = (RL2GraphBitmapPtr) bitmap;
1362 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1363
1364 if (ctx == NULL)
1365 return 0;
1366 if (bmp == NULL)
1367 return 0;
1368 if (ctx->type == RL2_SURFACE_PDF)
1369 {
1370 surface = ctx->clip_surface;
1371 cairo = ctx->clip_cairo;
1372 }
1373 else
1374 {
1375 surface = ctx->surface;
1376 cairo = ctx->cairo;
1377 }
1378
1379 cairo_save (cairo);
1380 cairo_translate (cairo, x, y);
1381 cairo_scale (cairo, scale_x, scale_y);
1382 cairo_set_source (cairo, bmp->pattern);
1383 cairo_paint (cairo);
1384 cairo_restore (cairo);
1385 cairo_surface_flush (surface);
1386 return 1;
1387 }
1388
1389 RL2_DECLARE unsigned char *
rl2_graph_get_context_rgb_array(rl2GraphicsContextPtr context)1390 rl2_graph_get_context_rgb_array (rl2GraphicsContextPtr context)
1391 {
1392 /* creating an RGB buffer from the given Context */
1393 int width;
1394 int height;
1395 int x;
1396 int y;
1397 unsigned char *p_in;
1398 unsigned char *p_out;
1399 unsigned char *rgb;
1400 int little_endian = rl2cr_endian_arch ();
1401 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1402
1403 if (ctx == NULL)
1404 return NULL;
1405
1406 width = cairo_image_surface_get_width (ctx->surface);
1407 height = cairo_image_surface_get_height (ctx->surface);
1408 rgb = malloc (width * height * 3);
1409 if (rgb == NULL)
1410 return NULL;
1411
1412 p_in = cairo_image_surface_get_data (ctx->surface);
1413 p_out = rgb;
1414 for (y = 0; y < height; y++)
1415 {
1416 for (x = 0; x < width; x++)
1417 {
1418 unsigned char r;
1419 unsigned char g;
1420 unsigned char b;
1421 if (little_endian)
1422 {
1423 b = *p_in++;
1424 g = *p_in++;
1425 r = *p_in++;
1426 p_in++; /* skipping Alpha */
1427 }
1428 else
1429 {
1430 p_in++; /* skipping Alpha */
1431 r = *p_in++;
1432 g = *p_in++;
1433 b = *p_in++;
1434 }
1435 *p_out++ = r;
1436 *p_out++ = g;
1437 *p_out++ = b;
1438 }
1439 }
1440 return rgb;
1441 }
1442
1443 RL2_DECLARE unsigned char *
rl2_graph_get_context_alpha_array(rl2GraphicsContextPtr context)1444 rl2_graph_get_context_alpha_array (rl2GraphicsContextPtr context)
1445 {
1446 /* creating an Alpha buffer from the given Context */
1447 int width;
1448 int height;
1449 int x;
1450 int y;
1451 unsigned char *p_in;
1452 unsigned char *p_out;
1453 unsigned char *alpha;
1454 int little_endian = rl2cr_endian_arch ();
1455 RL2GraphContextPtr ctx = (RL2GraphContextPtr) context;
1456
1457 if (ctx == NULL)
1458 return NULL;
1459
1460 width = cairo_image_surface_get_width (ctx->surface);
1461 height = cairo_image_surface_get_height (ctx->surface);
1462 alpha = malloc (width * height);
1463 if (alpha == NULL)
1464 return NULL;
1465
1466 p_in = cairo_image_surface_get_data (ctx->surface);
1467 p_out = alpha;
1468 for (y = 0; y < height; y++)
1469 {
1470 for (x = 0; x < width; x++)
1471 {
1472 if (little_endian)
1473 {
1474 p_in += 3; /* skipping RGB */
1475 *p_out++ = *p_in++;
1476 }
1477 else
1478 {
1479 *p_out++ = *p_in++;
1480 p_in += 3; /* skipping RGB */
1481 }
1482 }
1483 }
1484 return alpha;
1485 }
1486
1487 RL2_DECLARE int
rl2_rgba_to_pdf(unsigned int width,unsigned int height,unsigned char * rgba,unsigned char ** pdf,int * pdf_size)1488 rl2_rgba_to_pdf (unsigned int width, unsigned int height,
1489 unsigned char *rgba, unsigned char **pdf, int *pdf_size)
1490 {
1491 /* attempting to create an RGB PDF map */
1492 rl2MemPdfPtr mem = NULL;
1493 rl2GraphicsContextPtr ctx = NULL;
1494 rl2GraphicsBitmapPtr bmp = NULL;
1495 int dpi;
1496 double w_150 = (double) width / 150.0;
1497 double h_150 = (double) height / 150.0;
1498 double w_300 = (double) width / 300.0;
1499 double h_300 = (double) height / 300.0;
1500 double w_600 = (double) width / 600.0;
1501 double h_600 = (double) height / 600.0;
1502 double page_width;
1503 double page_height;
1504
1505 if (w_150 <= 6.3 && h_150 <= 9.7)
1506 {
1507 /* A4 portrait - 150 DPI */
1508 page_width = 8.3;
1509 page_height = 11.7;
1510 dpi = 150;
1511 }
1512 else if (w_150 <= 9.7 && h_150 < 6.3)
1513 {
1514 /* A4 landscape - 150 DPI */
1515 page_width = 11.7;
1516 page_height = 8.3;;
1517 dpi = 150;
1518 }
1519 else if (w_300 <= 6.3 && h_300 <= 9.7)
1520 {
1521 /* A4 portrait - 300 DPI */
1522 page_width = 8.3;
1523 page_height = 11.7;;
1524 dpi = 300;
1525 }
1526 else if (w_300 <= 9.7 && h_300 < 6.3)
1527 {
1528 /* A4 landscape - 300 DPI */
1529 page_width = 11.7;
1530 page_height = 8.3;;
1531 dpi = 300;
1532 }
1533 else if (w_600 <= 6.3 && h_600 <= 9.7)
1534 {
1535 /* A4 portrait - 600 DPI */
1536 page_width = 8.3;
1537 page_height = 11.7;;
1538 dpi = 600;
1539 }
1540 else
1541 {
1542 /* A4 landscape - 600 DPI */
1543 page_width = 11.7;
1544 page_height = 8.3;;
1545 dpi = 600;
1546 }
1547
1548 mem = rl2_create_mem_pdf_target ();
1549 if (mem == NULL)
1550 goto error;
1551
1552 ctx =
1553 rl2_graph_create_mem_pdf_context (mem, dpi, page_width, page_height,
1554 1.0, 1.0);
1555 if (ctx == NULL)
1556 goto error;
1557 bmp = rl2_graph_create_bitmap (rgba, width, height);
1558 rgba = NULL;
1559 if (bmp == NULL)
1560 goto error;
1561 /* rendering the Bitmap */
1562 if (ctx != NULL)
1563 rl2_graph_draw_bitmap (ctx, bmp, 0, 0);
1564 rl2_graph_destroy_bitmap (bmp);
1565 rl2_graph_destroy_context (ctx);
1566 /* retrieving the PDF memory block */
1567 if (rl2_get_mem_pdf_buffer (mem, pdf, pdf_size) != RL2_OK)
1568 goto error;
1569 rl2_destroy_mem_pdf_target (mem);
1570
1571 return RL2_OK;
1572
1573 error:
1574 if (bmp != NULL)
1575 rl2_graph_destroy_bitmap (bmp);
1576 if (ctx != NULL)
1577 rl2_graph_destroy_context (ctx);
1578 if (mem != NULL)
1579 rl2_destroy_mem_pdf_target (mem);
1580 return RL2_ERROR;
1581 }
1582
1583 RL2_DECLARE int
rl2_gray_pdf(unsigned int width,unsigned int height,unsigned char ** pdf,int * pdf_size)1584 rl2_gray_pdf (unsigned int width, unsigned int height, unsigned char **pdf,
1585 int *pdf_size)
1586 {
1587 /* attempting to create an all-Gray PDF */
1588 rl2MemPdfPtr mem = NULL;
1589 rl2GraphicsContextPtr ctx = NULL;
1590 int dpi;
1591 double w_150 = (double) width / 150.0;
1592 double h_150 = (double) height / 150.0;
1593 double w_300 = (double) width / 300.0;
1594 double h_300 = (double) height / 300.0;
1595 double w_600 = (double) width / 600.0;
1596 double h_600 = (double) height / 600.0;
1597 double page_width;
1598 double page_height;
1599
1600 if (w_150 <= 6.3 && h_150 <= 9.7)
1601 {
1602 /* A4 portrait - 150 DPI */
1603 page_width = 8.3;
1604 page_height = 11.7;
1605 dpi = 150;
1606 }
1607 else if (w_150 <= 9.7 && h_150 < 6.3)
1608 {
1609 /* A4 landscape - 150 DPI */
1610 page_width = 11.7;
1611 page_height = 8.3;;
1612 dpi = 150;
1613 }
1614 else if (w_300 <= 6.3 && h_300 <= 9.7)
1615 {
1616 /* A4 portrait - 300 DPI */
1617 page_width = 8.3;
1618 page_height = 11.7;;
1619 dpi = 300;
1620 }
1621 else if (w_300 <= 9.7 && h_300 < 6.3)
1622 {
1623 /* A4 landscape - 300 DPI */
1624 page_width = 11.7;
1625 page_height = 8.3;;
1626 dpi = 300;
1627 }
1628 else if (w_600 <= 6.3 && h_600 <= 9.7)
1629 {
1630 /* A4 portrait - 600 DPI */
1631 page_width = 8.3;
1632 page_height = 11.7;;
1633 dpi = 600;
1634 }
1635 else
1636 {
1637 /* A4 landscape - 600 DPI */
1638 page_width = 11.7;
1639 page_height = 8.3;;
1640 dpi = 600;
1641 }
1642
1643 mem = rl2_create_mem_pdf_target ();
1644 if (mem == NULL)
1645 goto error;
1646
1647 ctx =
1648 rl2_graph_create_mem_pdf_context (mem, dpi, page_width, page_height,
1649 1.0, 1.0);
1650 if (ctx == NULL)
1651 goto error;
1652 rl2_graph_set_pen (ctx, 255, 0, 0, 255, 2.0, RL2_PENSTYLE_SOLID);
1653 rl2_graph_set_brush (ctx, 128, 128, 128, 255);
1654 rl2_graph_draw_rounded_rectangle (ctx, 0, 0, width, height, width / 10.0);
1655
1656 rl2_graph_destroy_context (ctx);
1657 /* retrieving the PDF memory block */
1658 if (rl2_get_mem_pdf_buffer (mem, pdf, pdf_size) != RL2_OK)
1659 goto error;
1660 rl2_destroy_mem_pdf_target (mem);
1661
1662 return RL2_OK;
1663
1664 error:
1665 if (ctx != NULL)
1666 rl2_graph_destroy_context (ctx);
1667 if (mem != NULL)
1668 rl2_destroy_mem_pdf_target (mem);
1669 return RL2_ERROR;
1670 }
1671
1672 RL2_DECLARE rl2MemPdfPtr
rl2_create_mem_pdf_target(void)1673 rl2_create_mem_pdf_target (void)
1674 {
1675 /* creating an initially empty in-memory PDF target */
1676 rl2PrivMemPdfPtr mem = malloc (sizeof (rl2PrivMemPdf));
1677 if (mem == NULL)
1678 return NULL;
1679 mem->write_offset = 0;
1680 mem->size = 64 * 1024;
1681 mem->buffer = malloc (mem->size);
1682 if (mem->buffer == NULL)
1683 {
1684 free (mem);
1685 return NULL;
1686 }
1687 return (rl2MemPdfPtr) mem;
1688 }
1689
1690 RL2_DECLARE void
rl2_destroy_mem_pdf_target(rl2MemPdfPtr target)1691 rl2_destroy_mem_pdf_target (rl2MemPdfPtr target)
1692 {
1693 /* memory cleanup - destroying an in-memory PDF target */
1694 rl2PrivMemPdfPtr mem = (rl2PrivMemPdfPtr) target;
1695 if (mem == NULL)
1696 return;
1697 if (mem->buffer != NULL)
1698 free (mem->buffer);
1699 free (mem);
1700 }
1701
1702 RL2_DECLARE int
rl2_get_mem_pdf_buffer(rl2MemPdfPtr target,unsigned char ** buffer,int * size)1703 rl2_get_mem_pdf_buffer (rl2MemPdfPtr target, unsigned char **buffer, int *size)
1704 {
1705 /* exporting the internal buffer */
1706 rl2PrivMemPdfPtr mem = (rl2PrivMemPdfPtr) target;
1707 if (mem == NULL)
1708 return RL2_ERROR;
1709 if (mem->buffer == NULL)
1710 return RL2_ERROR;
1711 *buffer = mem->buffer;
1712 mem->buffer = NULL;
1713 *size = mem->write_offset;
1714 return RL2_OK;
1715 }
1716