Graphviz 16.1.1~dev.20260914.1518
Loading...
Searching...
No Matches
gvloadimage_gdk.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <stdbool.h>
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <util/alloc.h>
19#include <util/agxbuf.h>
20#include <util/gv_ftell.h>
21
23#include <gvc/gvio.h>
24
25#include <cairo.h>
26#include <gdk-pixbuf/gdk-pixbuf.h>
27#include <gdk/gdk.h>
28
29enum {
34};
35
36static void gdk_set_mimedata_from_file (cairo_surface_t *image, const char *mime_type, const char *file)
37{
38 unsigned char *data = NULL;
39
40 FILE *const fp = fopen(file, "rb");
41 if (fp == NULL)
42 return;
43 const int64_t len = fseek(fp, 0, SEEK_END) < 0 ? -1 : gv_ftell(fp);
44 if (fseek(fp, 0, SEEK_SET) == 0 && len > 0)
45 data = malloc((size_t)len);
46 if (data) {
47 if (fread(data, (size_t)len, 1, fp) != 1) {
48 free (data);
49 data = NULL;
50 }
51 }
52 fclose(fp);
53
54 if (data) {
55 if (cairo_surface_set_mime_data(image, mime_type, data,
56 (unsigned long)len, free, data) !=
57 CAIRO_STATUS_SUCCESS) {
58 free(data);
59 return;
60 }
61 agxbuf id = {0};
62 agxbprint(&id, "gvloadimage_gdk-%s", file);
63 char *const unique_id = agxbdisown(&id);
64 if (cairo_surface_set_mime_data(image, CAIRO_MIME_TYPE_UNIQUE_ID,
65 (unsigned char *)unique_id,
66 strlen(unique_id), free, unique_id) !=
67 CAIRO_STATUS_SUCCESS) {
68 free(unique_id);
69 }
70 }
71}
72
73static void gdk_set_mimedata(cairo_surface_t *image, usershape_t *us)
74{
75 switch (us->type) {
76 case FT_PNG:
77 gdk_set_mimedata_from_file (image, CAIRO_MIME_TYPE_PNG, us->name);
78 break;
79 case FT_JPEG:
80 gdk_set_mimedata_from_file (image, CAIRO_MIME_TYPE_JPEG, us->name);
81 break;
82 default:
83 break;
84 }
85}
86
88typedef struct {
89 cairo_surface_t *surface;
90 GdkPixbuf *origin;
91} data_t;
92
93static void gdk_freeimage(usershape_t *us)
94{
95 assert(us->data != NULL);
96 data_t *const data = us->data;
97 const bool is_last = cairo_surface_get_reference_count(data->surface) == 1;
98 cairo_surface_destroy(data->surface);
99 if (is_last) {
100 free(data->origin);
101 free(data);
102 }
103}
104
105static cairo_surface_t* gdk_loadimage(GVJ_t * job, usershape_t *us)
106{
107 cairo_t *cr = job->context; /* target context */
108 GdkPixbuf *image = NULL;
109 cairo_surface_t *cairo_image = NULL;
110
111 assert(job);
112 assert(us);
113 assert(us->name);
114
115 if (us->data) {
116 if (us->datafree == gdk_freeimage) {
117 // use cached data
118 data_t *const data = us->data;
119 cairo_image = cairo_surface_reference(data->surface);
120 } else {
121 us->datafree(us); /* free incompatible cache data */
122 us->datafree = NULL;
123 us->data = NULL;
124 }
125 }
126 if (!cairo_image) { /* read file into cache */
128 return NULL;
129 switch (us->type) {
130 case FT_PNG:
131 case FT_JPEG:
132 case FT_BMP:
133 case FT_ICO:
134 case FT_TIFF:
135 // FIXME - should be using a stream reader
136 image = gdk_pixbuf_new_from_file(us->name, NULL);
137 break;
138 default:
139 image = NULL;
140 }
141 if (image) {
142 cairo_save (cr);
143 gdk_cairo_set_source_pixbuf (cr, image, 0, 0);
144 cairo_pattern_t *const pattern = cairo_get_source(cr);
145 assert(cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SURFACE);
146 cairo_pattern_get_surface (pattern, &cairo_image);
147 cairo_image = cairo_surface_reference (cairo_image);
148 cairo_restore (cr);
149 gdk_set_mimedata (cairo_image, us);
150 data_t *const data = gv_alloc(sizeof(data_t));
151 *data = (data_t){.surface = cairo_surface_reference(cairo_image),
152 .origin = image};
153 us->data = data;
155 }
157 }
158 return cairo_image;
159}
160
161static void gdk_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, bool filled)
162{
163 (void)filled;
164
165 cairo_t *cr = job->context; /* target context */
166 cairo_surface_t *const image = gdk_loadimage(job, us);
167 if (image) {
168 cairo_save(cr);
169 cairo_translate(cr, b.LL.x, -b.UR.y);
170 cairo_scale(cr, (b.UR.x - b.LL.x) / us->w, (b.UR.y - b.LL.y) / us->h);
171 cairo_set_source_surface (cr, image, 0, 0);
172 cairo_paint (cr);
173 cairo_restore(cr);
174 cairo_surface_destroy (image);
175 }
176}
177
181
183 {FORMAT_BMP_CAIRO, "bmp:cairo", 1, &engine_gdk, NULL},
184 {FORMAT_JPEG_CAIRO, "jpe:cairo", 2, &engine_gdk, NULL},
185 {FORMAT_JPEG_CAIRO, "jpg:cairo", 2, &engine_gdk, NULL},
186 {FORMAT_JPEG_CAIRO, "jpeg:cairo", 2, &engine_gdk, NULL},
187 {FORMAT_PNG_CAIRO, "png:cairo", -1, &engine_gdk, NULL},
188 {FORMAT_ICO_CAIRO, "ico:cairo", 1, &engine_gdk, NULL},
189 {0, NULL, 0, NULL, NULL}
190};
Dynamically expanding string buffers.
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:345
Memory allocation wrappers that exit on failure.
static void * gv_alloc(size_t size)
Definition alloc.h:47
static double len(glCompPoint p)
Definition glutils.c:138
void * malloc(YYSIZE_T)
void free(void *)
node NULL
Definition grammar.y:181
void gvusershape_file_release(usershape_t *us)
bool gvusershape_file_access(usershape_t *us)
Abstraction over ftell
static int64_t gv_ftell(FILE *stream)
ftell, accounting for platform limitations
Definition gv_ftell.h:12
gvplugin_installed_t gvloadimage_gdk_types[]
static void gdk_loadimage_cairo(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static void gdk_set_mimedata_from_file(cairo_surface_t *image, const char *mime_type, const char *file)
static gvloadimage_engine_t engine_gdk
static void gdk_freeimage(usershape_t *us)
static cairo_surface_t * gdk_loadimage(GVJ_t *job, usershape_t *us)
@ FORMAT_BMP_CAIRO
@ FORMAT_ICO_CAIRO
@ FORMAT_PNG_CAIRO
@ FORMAT_JPEG_CAIRO
static void gdk_set_mimedata(cairo_surface_t *image, usershape_t *us)
T_cell image
Definition htmlparse.y:334
void * context
Definition gvcjob.h:295
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
resources allocated for loaded images
GdkPixbuf * origin
cairo_surface_t * surface
ingroup plugin_api
Definition gvplugin.h:35
double x
Definition geom.h:29
double y
Definition geom.h:29
const char * name
Definition usershape.h:54
void(* datafree)(usershape_t *us)
Definition usershape.h:65
void * data
Definition usershape.h:63
imagetype_t type
Definition usershape.h:59
double h
Definition usershape.h:61
double w
Definition usershape.h:61
@ FT_BMP
Definition usershape.h:25
@ FT_ICO
Definition usershape.h:27
@ FT_TIFF
Definition usershape.h:27
@ FT_JPEG
Definition usershape.h:25
@ FT_PNG
Definition usershape.h:25