Graphviz 16.1.1~dev.20260922.0048
Loading...
Searching...
No Matches
gvloadimage_webp.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 <inttypes.h>
15#include <stdbool.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <util/gv_ftell.h>
21#include <util/gv_math.h>
22#include <util/prisize_t.h>
23
25#include <gvc/gvio.h>
26
27#ifdef HAVE_WEBP
28#ifdef HAVE_PANGOCAIRO
29#include <cairo.h>
30#include <webp/decode.h>
31
32static const char* const kStatusMessages[] = {
33 "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
34 "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
35};
36
37enum {
38 FORMAT_WEBP_CAIRO,
39};
40
41static void webp_freeimage(usershape_t *us)
42{
43 cairo_surface_destroy(us->data);
44}
45
46static cairo_surface_t* webp_really_loadimage(const char *in_file, FILE* const in)
47{
48 WebPDecoderConfig config;
49 WebPDecBuffer* const output_buffer = &config.output;
50 WebPBitstreamFeatures* const bitstream = &config.input;
51 VP8StatusCode status = VP8_STATUS_OK;
52 cairo_surface_t *surface = NULL; /* source surface */
53 int ok;
54 void* data = NULL;
55
56 if (!WebPInitDecoderConfig(&config)) {
57 fprintf(stderr, "Error: WebP library version mismatch!\n");
58 return NULL;
59 }
60
61 const int64_t data_size = fseek(in, 0, SEEK_END) < 0 ? -1 : gv_ftell(in);
62 if (data_size < 0 || fseek(in, 0, SEEK_SET) < 0) {
63 fprintf(stderr, "Error: WebP could not read %s\n", in_file);
64 return NULL;
65 }
66 data = malloc((size_t)data_size);
67 ok = data_size == 0 || (data != NULL && fread(data, (size_t)data_size, 1, in) == 1);
68 if (!ok) {
69 fprintf(stderr, "Error: WebP could not read %" PRId64
70 " bytes of data from %s\n", data_size, in_file);
71 free(data);
72 return NULL;
73 }
74
75 status = WebPGetFeatures(data, (size_t)data_size, bitstream);
76 if (status != VP8_STATUS_OK) {
77 goto end;
78 }
79
80 output_buffer->colorspace = MODE_RGBA;
81 status = WebPDecode(data, (size_t)data_size, &config);
82
83 /* FIXME - this is ugly */
84 if (! bitstream->has_alpha) {
85 assert(output_buffer->width >= 0);
86 assert(output_buffer->height >= 0);
87 argb2rgba((size_t)output_buffer->width, (size_t)output_buffer->height,
88 output_buffer->u.RGBA.rgba);
89 }
90
91end:
92 free(data);
93 ok = status == VP8_STATUS_OK;
94 if (!ok) {
95 fprintf(stderr, "Error: WebP decoding of %s failed.\n", in_file);
96 fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]);
97 return NULL;
98 }
99
100 surface = cairo_image_surface_create_for_data (
101 output_buffer->u.RGBA.rgba,
102 CAIRO_FORMAT_ARGB32,
103 output_buffer->width,
104 output_buffer->height,
105 output_buffer->u.RGBA.stride);
106
107 return surface;
108}
109
110// get image either from cached surface, or from freshly loaded surface
111static cairo_surface_t *webp_loadimage(usershape_t *us) {
112 cairo_surface_t *surface = NULL; /* source surface */
113
114 assert(us);
115 assert(us->name);
116
117 if (us->data) {
118 if (us->datafree == webp_freeimage)
119 surface = us->data; /* use cached data */
120 else {
121 us->datafree(us); /* free incompatible cache data */
122 us->datafree = NULL;
123 us->data = NULL;
124 }
125 }
126 if (!surface) { /* read file into cache */
128 return NULL;
129 switch (us->type) {
130 case FT_WEBP:
131 if ((surface = webp_really_loadimage(us->name, us->f)))
132 cairo_surface_reference(surface);
133 break;
134 default:
135 surface = NULL;
136 }
137 if (surface) {
138 us->data = surface;
139 us->datafree = webp_freeimage;
140 }
142 }
143 return surface;
144}
145
146/* paint image into required location in graph */
147static void webp_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, bool filled)
148{
149 (void)filled;
150
151 cairo_t *cr = job->context; /* target context */
152 cairo_surface_t *surface; /* source surface */
153
154 surface = webp_loadimage(us);
155 if (surface) {
156 cairo_save(cr);
157 cairo_translate(cr, b.LL.x, -b.UR.y);
158 cairo_scale(cr, (b.UR.x - b.LL.x) / us->w, (b.UR.y - b.LL.y) / us->h);
159 cairo_set_source_surface (cr, surface, 0, 0);
160 cairo_paint (cr);
161 cairo_restore(cr);
162 }
163}
164
165static gvloadimage_engine_t engine_webp = {
166 webp_loadimage_cairo
167};
168#endif
169#endif
170
172#ifdef HAVE_WEBP
173#ifdef HAVE_PANGOCAIRO
174 {FORMAT_WEBP_CAIRO, "webp:cairo", 1, &engine_webp, NULL},
175#endif
176#endif
177 {0, NULL, 0, NULL, NULL}
178};
static int in(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1643
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)
bool ok(Agraph_t *g)
Definition gv.cpp:366
Abstraction over ftell
static int64_t gv_ftell(FILE *stream)
ftell, accounting for platform limitations
Definition gv_ftell.h:12
Arithmetic helper functions.
static void argb2rgba(size_t width, size_t height, unsigned char *data)
Definition gv_math.h:112
gvplugin_installed_t gvloadimage_webp_types[]
void * context
Definition gvcjob.h:295
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
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
FILE * f
Definition usershape.h:58
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_WEBP
Definition usershape.h:27