22#include <boost/algorithm/string.hpp>
23#include <boost/operators.hpp>
24#include <boost/optional/optional.hpp>
25#include <cairomm/context.h>
26#include <cairomm/matrix.h>
27#include <cairomm/pattern.h>
28#include <cairomm/refptr.h>
29#include <cairomm/surface.h>
32#include <gdk-pixbuf/gdk-pixbuf.h>
33#include <glib/gstdio.h>
34#include <glibmm/fileutils.h>
47#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 6)
48#define CAIRO_HAS_HAIRLINE
90 : _pixbuf(gdk_pixbuf_new_from_data(
91 cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8,
92 cairo_image_surface_get_width(s), cairo_image_surface_get_height(s),
93 cairo_image_surface_get_stride(s),
97 , _pixel_format(PF_CAIRO)
108 , _pixel_format(PF_GDK)
109 , _cairo_store(false)
112 _surface = cairo_image_surface_create_for_data(
113 gdk_pixbuf_get_pixels(
_pixbuf), CAIRO_FORMAT_ARGB32,
118 : _pixbuf(gdk_pixbuf_copy(other._pixbuf))
119 , _surface(cairo_image_surface_create_for_data(
120 gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32,
121 gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf)))
122 , _mod_time(other._mod_time)
124 , _pixel_format(other._pixel_format)
125 , _cairo_store(false)
136#if !GDK_PIXBUF_CHECK_VERSION(2, 41, 0)
142 GdkPixbufLoader *loader, guchar *decoded, gsize decoded_len, GError **error)
145 gsize bytes_left = decoded_len;
146 gsize secret_limit = 0xffff;
147 guchar *decoded_head = decoded;
148 while (bytes_left && success) {
149 gsize bytes = (bytes_left > secret_limit) ? secret_limit : bytes_left;
150 success = gdk_pixbuf_loader_write(loader, decoded_head, bytes, error);
151 decoded_head += bytes;
157#define gdk_pixbuf_loader_write _workaround_issue_70__gdk_pixbuf_loader_write
169 copy = gdk_pixbuf_copy(
_pixbuf);
173 auto cropped = gdk_pixbuf_new_subpixbuf(source,
177 g_object_unref(copy);
179 return new Pixbuf(cropped);
188 GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
190 if (!loader)
return nullptr;
192 gsize decoded_len = 0;
193 guchar *decoded = g_base64_decode(
data, &decoded_len);
195 if (gdk_pixbuf_loader_write(loader, decoded, decoded_len,
nullptr)) {
196 gdk_pixbuf_loader_close(loader,
nullptr);
209 GdkPixbufFormat *
fmt = gdk_pixbuf_loader_get_format(loader);
210 gchar *fmt_name = gdk_pixbuf_format_get_name(
fmt);
220 g_object_unref(loader);
224 gsize decoded_len = 0;
225 guchar *decoded = g_base64_decode(
data, &decoded_len);
228 if (!svgDoc || !svgDoc->getRoot()) {
232 double dpi = prefs->
getDouble(
"/dialogs/import/defaultxdpi/value", 96.0);
233 if (svgdpi && svgdpi > 0) {
240 const double svgWidth_px = svgWidth.
value(
"px");
241 const double svgHeight_px = svgHeight.
value(
"px");
242 if (svgWidth_px < 0 || svgHeight_px < 0) {
243 g_warning(
"create_from_data_uri: malformed document: svgWidth_px=%f, svgHeight_px=%f", svgWidth_px,
249 Geom::Rect area(0, 0, svgWidth_px, svgHeight_px);
254 if (
buf ==
nullptr) {
255 std::cerr <<
"Pixbuf::create_from_data: failed to load contents: " << std::endl;
271 if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) {
275 int val = g_stat(fn.c_str(), &stdir);
276 if (val == 0 && stdir.st_mode & S_IFDIR){
281 gchar *
data =
nullptr;
283 GError *error =
nullptr;
285 if (g_file_get_contents(fn.c_str(), &
data, &
len, &error)) {
287 if (error !=
nullptr) {
288 std::cerr <<
"Pixbuf::create_from_file: " << error->message << std::endl;
289 std::cerr <<
" (" << fn <<
")" << std::endl;
299 std::cerr <<
"Pixbuf::create_from_file: failed to get contents: " << fn << std::endl;
309 buf = gdk_pixbuf_apply_embedded_orientation(
buf);
320 if (
auto opt_str = gdk_pixbuf_get_option(
buf,
"orientation")) {
321 switch ((
int)g_ascii_strtoll(opt_str, NULL, 10)) {
346#if GLIB_CHECK_VERSION(2,67,3)
347 auto datacopy = (gchar *)g_memdup2(buffer.data(), buffer.size());
349 auto datacopy = (gchar *)g_memdup(buffer.data(), buffer.size());
356 bool has_ori =
false;
358 GError *error =
nullptr;
361 GdkPixbufLoader *loader =
nullptr;
362 std::string::size_type idx;
365 if(idx != std::string::npos)
367 if (boost::iequals(fn.substr(idx+1).c_str(),
"svg")) {
371 if (!svgDoc || !svgDoc->getRoot()) {
376 double dpi = prefs->
getDouble(
"/dialogs/import/defaultxdpi/value", 96.0);
377 if (svgdpi && svgdpi > 0) {
385 const double svgWidth_px = std::min(svgWidth.
value(
"px"), dpi * 100);
386 const double svgHeight_px = std::min(svgHeight.
value(
"px"), dpi * 100);
387 if (svgWidth_px < 0 || svgHeight_px < 0) {
388 g_warning(
"create_from_buffer: malformed document: svgWidth_px=%f, svgHeight_px=%f", svgWidth_px,
393 Geom::Rect area(0, 0, svgWidth_px, svgHeight_px);
401 if (
buf ==
nullptr) {
410 loader = gdk_pixbuf_loader_new();
411 gdk_pixbuf_loader_write(loader, (guchar *)
data,
len, &error);
412 if (error !=
nullptr) {
413 std::cerr <<
"Pixbuf::create_from_file: " << error->message << std::endl;
414 std::cerr <<
" (" << fn <<
")" << std::endl;
416 g_object_unref(loader);
420 gdk_pixbuf_loader_close(loader, &error);
421 if (error !=
nullptr) {
422 std::cerr <<
"Pixbuf::create_from_file: " << error->message << std::endl;
423 std::cerr <<
" (" << fn <<
")" << std::endl;
425 g_object_unref(loader);
429 buf = gdk_pixbuf_loader_get_pixbuf(loader);
443 }
else if(!has_ori) {
446 GdkPixbufFormat *
fmt = gdk_pixbuf_loader_get_format(loader);
447 gchar *fmt_name = gdk_pixbuf_format_get_name(
fmt);
450 g_object_unref(loader);
453 std::cerr <<
"Pixbuf::create_from_file: failed to load contents: " << fn << std::endl;
470 if (convert_format) {
522 return Cairo::RefPtr<Cairo::Surface>(
new Cairo::Surface(
getSurfaceRaw(),
false));
529 static gchar
const *mimetypes[] = {
530 CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG,
nullptr };
531 static guint mimetypes_len = g_strv_length(
const_cast<gchar**
>(mimetypes));
533 guchar
const *
data =
nullptr;
535 for (guint i = 0; i < mimetypes_len; ++i) {
536 unsigned long len_long = 0;
538 if (
data !=
nullptr) {
540 mimetype = mimetypes[i];
561 return gdk_pixbuf_get_pixels(
_pixbuf);
569 if (gdk_pixbuf_get_has_alpha(
_pixbuf))
return;
572 _pixbuf = gdk_pixbuf_add_alpha(old, FALSE, 0, 0, 0);
578 gchar
const *mimetype =
nullptr;
580 if (format ==
"jpeg") {
581 mimetype = CAIRO_MIME_TYPE_JPEG;
582 }
else if (format ==
"jpeg2000") {
583 mimetype = CAIRO_MIME_TYPE_JP2;
584 }
else if (format ==
"png") {
585 mimetype = CAIRO_MIME_TYPE_PNG;
588 if (mimetype !=
nullptr) {
609 g_assert_not_reached();
622 gdk_pixbuf_get_pixels(pb),
623 gdk_pixbuf_get_width(pb),
624 gdk_pixbuf_get_height(pb),
625 gdk_pixbuf_get_rowstride(pb));
635 gdk_pixbuf_get_pixels(pb),
636 gdk_pixbuf_get_width(pb),
637 gdk_pixbuf_get_height(pb),
638 gdk_pixbuf_get_rowstride(pb));
663 if (!optimize_stroke) {
678 std::array<Geom::Point, 3> points;
679 for (
int i = 0; i < 3; i++) {
683 Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]);
684 Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]);
685 if (!optimize_stroke) {
686 cairo_curve_to(cr, b1[X], b1[Y], b2[X], b2[Y], points[2][X], points[2][Y]);
691 cairo_curve_to(cr, b1[X], b1[Y], b2[X], b2[Y], points[2][X], points[2][Y]);
701 std::array<Geom::Point, 4> points;
702 for (
int i = 0; i < 4; i++) {
709 if (!optimize_stroke) {
710 cairo_curve_to(cr, points[1][X], points[1][Y], points[2][X], points[2][Y], points[3][X], points[3][Y]);
717 cairo_curve_to(cr, points[1][X], points[1][Y], points[2][X], points[2][Y], points[3][X], points[3][Y]);
727 if (arc->isChord()) {
731 Geom::Affine xform = arc->unitCircleTransform() * trans;
733 if(std::isnan(arc->initialAngle()) || std::isnan(arc->finalAngle())) {
734 g_warning(
"Bad angle while drawing EllipticalArc");
742 cairo_transform(cr, &cm);
746 cairo_arc(cr, 0, 0, 1, arc->initialAngle(), arc->finalAngle());
748 cairo_arc_negative(cr, 0, 0, 1, arc->initialAngle(), arc->finalAngle());
759 for (
const auto & iter : sbasis_path) {
783 cairo_close_path(ct);
812 if (!optimize_stroke) {
813 cairo_close_path(ct);
844 for(
const auto & it : pathv) {
857 for(
const auto & it : pathv) {
872 cairo_path_t *path = cairo_copy_path(ct);
876 auto path_freer =
scope_exit([&] { cairo_path_destroy(path); });
879 auto end = &path->data[path->num_data];
880 for (
auto p = &path->data[0]; p <
end; p += p->header.
length) {
881 switch (p->header.type) {
882 case CAIRO_PATH_MOVE_TO:
883 if (p->header.length != 2)
885 res.moveTo(
Geom::Point(p[1].point.x, p[1].point.y));
888 case CAIRO_PATH_LINE_TO:
889 if (p->header.length != 2)
891 res.lineTo(
Geom::Point(p[1].point.x, p[1].point.y));
894 case CAIRO_PATH_CURVE_TO:
895 if (p->header.length != 4)
901 case CAIRO_PATH_CLOSE_PATH:
902 if (p->header.length != 1)
918 if(
data !=
nullptr ) {
930 if( cairo_surface_get_content(
surface ) != CAIRO_CONTENT_ALPHA ) {
984 auto c = color.
toRGBA(opacity);
989 auto c = color.
toRGBA(opacity);
1026 cairo_transform(ct, &cm);
1034 cairo_pattern_set_matrix(cp, &cm);
1040#ifdef CAIRO_HAS_HAIRLINE
1041 cairo_set_hairline(ct,
true);
1044 double x = 1.0, y = 0.0;
1045 cairo_device_to_user_distance(ct, &x, &y);
1046 cairo_set_line_width(ct, std::hypot(x, y));
1052#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
1053 cairo_pattern_set_dither(pattern, enabled ? CAIRO_DITHER_BEST : CAIRO_DITHER_NONE);
1067 if (cairo_surface_get_type(s) == CAIRO_SURFACE_TYPE_IMAGE) {
1069 cairo_surface_flush(s);
1070 int stride = cairo_image_surface_get_stride(s);
1071 int h = cairo_image_surface_get_height(s);
1072 memcpy(cairo_image_surface_get_data(ns), cairo_image_surface_get_data(s),
stride * h);
1073 cairo_surface_mark_dirty(ns);
1076 cairo_t *ct = cairo_create(ns);
1077 cairo_set_source_surface(ct, s, 0, 0);
1078 cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
1089Cairo::RefPtr<Cairo::ImageSurface>
1095 auto new_surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32,
width,
height);
1099 new_surface->mark_dirty();
1124 cairo_surface_get_device_scale( s, &x_scale, &y_scale );
1126 assert (x_scale > 0);
1127 assert (y_scale > 0);
1130 cairo_surface_create_similar(s,
c,
1146 cairo_t *ct = cairo_create(alpha);
1147 cairo_set_source_surface(ct, s, 0, 0);
1148 cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
1158 cairo_content_t imgt = cairo_surface_get_content(
image);
1159 cairo_content_t bgt = cairo_surface_get_content(bg);
1162 if (bgt == CAIRO_CONTENT_ALPHA && imgt == CAIRO_CONTENT_ALPHA) {
1174 if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_IMAGE &&
1175 cairo_surface_get_type(dest) == CAIRO_SURFACE_TYPE_IMAGE &&
1176 cairo_image_surface_get_format(src) == cairo_image_surface_get_format(dest) &&
1177 cairo_image_surface_get_height(src) == cairo_image_surface_get_height(dest) &&
1178 cairo_image_surface_get_width(src) == cairo_image_surface_get_width(dest) &&
1179 cairo_image_surface_get_stride(src) == cairo_image_surface_get_stride(dest))
1182 cairo_surface_flush(src);
1183 int stride = cairo_image_surface_get_stride(src);
1184 int h = cairo_image_surface_get_height(src);
1185 memcpy(cairo_image_surface_get_data(dest), cairo_image_surface_get_data(src),
stride * h);
1186 cairo_surface_mark_dirty(dest);
1189 cairo_t *ct = cairo_create(dest);
1190 cairo_set_source_surface(ct, src, 0, 0);
1191 cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
1205 assert(cairo_surface_get_type(
surface) == CAIRO_SURFACE_TYPE_IMAGE);
1206 return cairo_image_surface_get_width(
surface);
1215 assert(cairo_surface_get_type(
surface) == CAIRO_SURFACE_TYPE_IMAGE);
1216 return cairo_image_surface_get_height(
surface);
1221 rf = gf = bf = af = 0.0;
1226 unsigned char *
data = cairo_image_surface_get_data(
surface);
1229 if (
width * 4 != cairo_image_surface_get_stride(
surface)) {
1230 g_warning(
"Stride and width don't match, expect zero buffer for average color.");
1233 unsigned char *mask_data =
nullptr;
1235 cairo_surface_flush(mask);
1236 if (
width != cairo_image_surface_get_width(mask)
1237 ||
height != cairo_image_surface_get_height(mask)) {
1238 g_warning(
"Mask size must be exactly the same size as the image surface.");
1241 mask_data = cairo_image_surface_get_data(mask);
1246 EXTRACT_ARGB32(*
reinterpret_cast<guint32*
>(
data), a, r, g, b)
1248 double amount = mask_data ? mask_data[p] / 255.0 : 1.0;
1249 rf += r / 255.0 * amount;
1250 gf += g / 255.0 * amount;
1251 bf += b / 255.0 * amount;
1252 af += a / 255.0 * amount;
1267 auto status = cairo_pattern_get_rgba(pattern, &red, &green, &blue, &alpha);
1268 if (status != CAIRO_STATUS_PATTERN_TYPE_MISMATCH) {
1274 status = cairo_pattern_get_surface (pattern, &
surface);
1275 if (status != CAIRO_STATUS_PATTERN_TYPE_MISMATCH) {
1277 auto *pxbsurface = cairo_image_surface_get_data(
surface);
1278 return *
reinterpret_cast<guint32 const *
>(pxbsurface);
1291 double r, g, b, a = 0.0;
1293 auto color = Colors::Color(Colors::Space::Type::RGB, {r / a, g / a, b / a, a / count});
1302 double cc = c1/255.0;
1304 if( cc < 0.04045 ) {
1307 cc = pow( (cc+0.055)/1.055, 2.4 );
1320 double cc = c1/255.0;
1322 if( cc < 0.0031308 ) {
1325 cc = pow( cc, 1.0/2.4 )*1.055-0.055;
1336 EXTRACT_ARGB32(in, a, r, g, b);
1342 ASSEMBLE_ARGB32(out, a, r, g, b);
1359 EXTRACT_ARGB32(in, a, r, g, b);
1365 ASSEMBLE_ARGB32(out, a, r, g, b);
1375 switch (cairo_operator) {
1376 case CAIRO_OPERATOR_MULTIPLY:
1378 case CAIRO_OPERATOR_SCREEN:
1380 case CAIRO_OPERATOR_DARKEN:
1382 case CAIRO_OPERATOR_LIGHTEN:
1384 case CAIRO_OPERATOR_OVERLAY:
1386 case CAIRO_OPERATOR_COLOR_DODGE:
1388 case CAIRO_OPERATOR_COLOR_BURN:
1390 case CAIRO_OPERATOR_HARD_LIGHT:
1392 case CAIRO_OPERATOR_SOFT_LIGHT:
1394 case CAIRO_OPERATOR_DIFFERENCE:
1396 case CAIRO_OPERATOR_EXCLUSION:
1398 case CAIRO_OPERATOR_HSL_HUE:
1400 case CAIRO_OPERATOR_HSL_SATURATION:
1402 case CAIRO_OPERATOR_HSL_COLOR:
1404 case CAIRO_OPERATOR_HSL_LUMINOSITY:
1406 case CAIRO_OPERATOR_OVER:
1419 switch (css_blend) {
1421 return CAIRO_OPERATOR_MULTIPLY;
1423 return CAIRO_OPERATOR_SCREEN;
1425 return CAIRO_OPERATOR_DARKEN;
1427 return CAIRO_OPERATOR_LIGHTEN;
1429 return CAIRO_OPERATOR_OVERLAY;
1431 return CAIRO_OPERATOR_COLOR_DODGE;
1433 return CAIRO_OPERATOR_COLOR_BURN;
1435 return CAIRO_OPERATOR_HARD_LIGHT;
1437 return CAIRO_OPERATOR_SOFT_LIGHT;
1439 return CAIRO_OPERATOR_DIFFERENCE;
1441 return CAIRO_OPERATOR_EXCLUSION;
1443 return CAIRO_OPERATOR_HSL_HUE;
1445 return CAIRO_OPERATOR_HSL_SATURATION;
1447 return CAIRO_OPERATOR_HSL_COLOR;
1449 return CAIRO_OPERATOR_HSL_LUMINOSITY;
1451 return CAIRO_OPERATOR_OVER;
1453 g_error(
"Invalid SPBlendMode %d", css_blend);
1454 return CAIRO_OPERATOR_OVER;
1471 constexpr int width = 10;
1472 constexpr int line_width = 10;
1474 auto surface = Cairo::ImageSurface::create(Cairo::ImageSurface::Format::ARGB32,
width, 1);
1475 auto context = Cairo::Context::create(
surface);
1476 context->rectangle(0, 0, line_width / 2.0, 1);
1481 auto pattern = Cairo::SurfacePattern::create(
surface);
1482 pattern->set_extend(Cairo::SurfacePattern::Extend::REPEAT);
1483 pattern->set_filter(Cairo::SurfacePattern::Filter::NEAREST);
1484 pattern->set_matrix(Cairo::rotation_matrix(3 * M_PI / 4));
1494 auto color_a = Colors::Color(rgba, use_alpha);
1497 color_a.enableOpacity(
false);
1499 cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2*
w, 2*h);
1501 cairo_t *ct = cairo_create(s);
1502 cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
1512 cairo_pattern_set_extend(p, CAIRO_EXTEND_REPEAT);
1513 cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
1515 cairo_surface_destroy(s);
1528 const auto a = color_alpha;
1532 double half = sw / 2;
1536 auto grad_top = Cairo::LinearGradient::create(0,
corners[0][Y] + half, 0,
corners[0][Y] - half);
1537 auto grad_right = Cairo::LinearGradient::create(
corners[1][X], 0,
corners[1][X] + sw, 0);
1538 auto grad_bottom = Cairo::LinearGradient::create(0,
corners[2][Y], 0,
corners[2][Y] + sw);
1539 auto grad_left = Cairo::LinearGradient::create(
corners[0][X] + half, 0,
corners[0][X] - half, 0);
1548 const auto denominator = exp(A) - 1;
1549 for (
int i = 0; i <=
N; ++i) {
1550 auto pos =
static_cast<double>(i) /
N;
1553 auto alpha = (exp(A * t) - 1) / denominator;
1554 grad_top->add_color_stop_rgba(pos, r, g, b, alpha * a);
1555 grad_bottom->add_color_stop_rgba(pos, r, g, b, alpha * a);
1556 grad_right->add_color_stop_rgba(pos, r, g, b, alpha * a);
1557 grad_left->add_color_stop_rgba(pos, r, g, b, alpha * a);
1558 grad_btm_right->add_color_stop_rgba(pos, r, g, b, alpha * a);
1559 grad_top_right->add_color_stop_rgba(pos, r, g, b, alpha * a);
1560 grad_btm_left->add_color_stop_rgba(pos, r, g, b, alpha * a);
1563 grad_top_left->add_color_stop_rgba(2 * (pos - 0.5), r, g, b, alpha * a);
1569 ctx->set_source(grad_top);
1574 ctx->set_source(grad_right);
1579 ctx->set_source(grad_bottom);
1584 ctx->set_source(grad_left);
1589 ctx->set_source(grad_btm_right);
1592 ctx->rectangle(
corners[3][X] - half,
corners[3][Y], std::min(sw, rect.
width() + half), sw);
1593 ctx->set_source(grad_btm_left);
1598 ctx->set_source(grad_top_right);
1601 ctx->rectangle(
corners[0][X] - half,
corners[0][Y] - half, half, half);
1602 ctx->set_source(grad_top_left);
1618 guchar *pixels = cairo_image_surface_get_data(s);
1619 int w = cairo_image_surface_get_width(s);
1620 int h = cairo_image_surface_get_height(s);
1621 int rs = cairo_image_surface_get_stride(s);
1625 GdkPixbuf *pb = gdk_pixbuf_new_from_data(
1626 pixels, GDK_COLORSPACE_RGB, TRUE, 8,
1641 cairo_surface_destroy(
surface);
1651 if constexpr (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1652 a = (
c & 0xff000000) >> 24;
1654 a = (
c & 0x000000ff);
1663 if constexpr (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1664 r = (
c & 0x000000ff);
1665 g = (
c & 0x0000ff00) >> 8;
1666 b = (
c & 0x00ff0000) >> 16;
1668 r = (
c & 0xff000000) >> 24;
1669 g = (
c & 0x00ff0000) >> 16;
1670 b = (
c & 0x0000ff00) >> 8;
1679 return (a << 24) | (r << 16) | (g << 8) | b;
1690 guint32 a = (
c & 0xff000000) >> 24;
1697 guint32 r = (
c & 0x00ff0000) >> 16;
1708 if constexpr (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1709 return r | (g << 8) | (b << 16) | (a << 24);
1711 return (r << 24) | (g << 16) | (b << 8) | a;
1729 for (
size_t i = 0; i < h; ++i) {
1731 for (
size_t j = 0; j <
w; ++j) {
1749 for (
size_t i = 0; i < h; ++i) {
1751 for (
size_t j = 0; j <
w; ++j) {
1761 a = (in & 0x000000ff);
1765 ASSEMBLE_ARGB32(px, a, r, g, b)
1777 guint32 a = (
c & 0xff000000) >> 24;
1778 guint32 r = (
c & 0x00ff0000) >> 16;
1789 guint32 o = (r << 24) | (g << 16) | (b << 8) | (a);
1796 return ((1063 * r + 3576 * g + 361 * b) * 257 + 2500) / 5000;
1801 for (
int x = 0; x < 256; x++) {
1802 const uint16_t hex = 0x101 * x;
1807 "get_luminance function doesn't produce expected luminance values");
1814const guchar*
pixbuf_to_png(guchar
const**rows, guchar* px,
int num_rows,
int num_cols,
int stride,
int color_type,
int bit_depth)
1816 int n_fields = 1 + (color_type&2) + (color_type&4)/4;
1817 const guchar* new_data = (
const guchar*)malloc(((n_fields * bit_depth * num_cols + 7)/8) * num_rows);
1818 char* ptr = (
char*) new_data;
1822 for (
int row = 0; row < num_rows; ++row) {
1823 rows[row] = (
const guchar*)ptr;
1824 for (
int col = 0; col < num_cols; ++col) {
1827 guint64 pix3 = (*pixel & 0xff000000) >> 24;
1828 guint64 pix2 = (*pixel & 0x00ff0000) >> 16;
1829 guint64 pix1 = (*pixel & 0x0000ff00) >> 8;
1830 guint64 pix0 = (*pixel & 0x000000ff);
1832 uint64_t a, r, g, b;
1833 if constexpr (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1848 if (color_type & 2) {
1852 if (color_type & 4) {
1860 *((guint64*)ptr) = (guint64)((pix3<<56)+(pix3<<48)+(pix2<<40)+(pix2<<32)+(pix1<<24)+(pix1<<16)+(pix0<<8)+(pix0));
1862 if (bit_depth == 8) {
1867 *((guint16*)ptr) = (r<<8)+r;
1868 *((guint16*)(ptr+2)) = (g<<8)+g;
1869 *((guint16*)(ptr+4)) = (b<<8)+b;
1873 if (bit_depth == 16) {
1874 if constexpr (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1875 *(guint16*)ptr = ((gray & 0xff00)>>8) + ((gray & 0x00ff)<<8);
1877 *(guint16*)ptr = gray;
1884 *((guint16*)(ptr+2)) = a + (a<<8);
1885 }
else if (bit_depth == 8) {
1886 *ptr = guint8(gray >> 8);
1888 *((guint8*)(ptr+1)) = a;
1892 int realpad = 8 - bit_depth - pad;
1893 *ptr += guint8((gray >> (16-bit_depth))<<realpad);
1895 *(ptr+1) += guint8((a >> (8-bit_depth))<<(bit_depth + realpad));
1899 pad += bit_depth*n_fields;
Path - a sequence of contiguous curves.
Cartesian point / 2D vector and related operations.
3x3 affine transformation matrix.
Cairo software blending templates.
void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter &&filter)
static uint32_t srgb_to_linear_argb32(uint32_t in)
static cairo_user_data_key_t ink_color_interpolation_key
Key for cairo_surface_t to keep track of current color interpolation value Only the address of the st...
SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface)
void ink_cairo_draw_drop_shadow(const Cairo::RefPtr< Cairo::Context > &ctx, const Geom::Rect &rect, double size, guint32 color, double color_alpha)
Draw drop shadow around the 'rect' with given 'size' and 'color'; shadow extends to the right and bot...
SPBlendMode ink_cairo_operator_to_css_blend(cairo_operator_t cairo_operator)
static void feed_path_to_cairo(cairo_t *ct, Geom::Path const &path)
Feeds path-creating calls to the cairo context translating them from the Path.
void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out)
void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int stride)
Convert pixel data from GdkPixbuf format to ARGB.
static double ink_cairo_surface_average_color_internal(cairo_surface_t *surface, cairo_surface_t *mask, double &rf, double &gf, double &bf, double &af)
int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface)
Cairo::RefPtr< Cairo::Pattern > ink_cairo_pattern_create_slanting_stripes(uint32_t color)
cairo_surface_t * ink_cairo_extract_alpha(cairo_surface_t *s)
Extract the alpha channel into a new surface.
int ink_cairo_surface_srgb_to_linear(cairo_surface_t *surface)
void ink_cairo_set_source_color(Cairo::RefPtr< Cairo::Context > ctx, Inkscape::Colors::Color const &color, double opacity)
The following functions interact between Inkscape color model, and cairo surface rendering.
cairo_surface_t * ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c)
cairo_surface_t * ink_cairo_surface_create_identical(cairo_surface_t *s)
Create a surface that differs only in pixel content.
static void feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const &trans, Geom::Rect const &view, bool optimize_stroke)
void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m)
cairo_surface_t * ink_cairo_surface_copy(cairo_surface_t *s)
Create an exact copy of a surface.
void ink_cairo_pattern_add_color_stop(cairo_pattern_t *ptn, double offset, Inkscape::Colors::Color const &color, double opacity)
const guchar * pixbuf_to_png(guchar const **rows, guchar *px, int num_rows, int num_cols, int stride, int color_type, int bit_depth)
Converts a pixbuf to a PNG data structure.
void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m)
void feed_pathvector_to_cairo(cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width)
Feeds path-creating calls to the cairo context translating them from the PathVector,...
guint32 rgba_from_argb32(guint32 c)
Convert one pixel from ARGB to GdkPixbuf format.
void ink_cairo_pattern_set_dither(cairo_pattern_t *pattern, bool enabled)
int ink_cairo_surface_get_width(cairo_surface_t *surface)
Return width in pixels.
guint32 argb32_from_rgba(guint32 in)
Convert a pixel in 0xRRGGBBAA format to Cairo ARGB32 format.
cairo_pattern_t * ink_cairo_pattern_create(Inkscape::Colors::Color const &color, double opacity)
std::optional< Geom::PathVector > extract_pathvector_from_cairo(cairo_t *ct)
void ink_cairo_surface_blit(cairo_surface_t *src, cairo_surface_t *dest)
static guint32 linear_to_srgb(const guint32 c, const guint32 a)
static uint32_t linear_to_srgb_argb32(uint32_t in)
guint32 pixbuf_from_argb32(guint32 c, guint32 bgcolor)
Convert one pixel from ARGB to GdkPixbuf format.
int ink_cairo_surface_get_height(cairo_surface_t *surface)
Return height in pixels.
Colors::Color ink_cairo_surface_average_color(cairo_surface_t *surface, cairo_surface_t *mask)
Get the average color from the given surface.
void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride, guint32 bgcolor)
Convert pixel data from ARGB to GdkPixbuf format.
cairo_pattern_t * ink_cairo_pattern_create_checkerboard(guint32 rgba, bool use_alpha)
void ink_cairo_set_hairline(cairo_t *ct)
guint32 ink_cairo_pattern_get_argb32(cairo_pattern_t *pattern)
void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba)
guint32 argb32_from_pixbuf(guint32 c)
void ink_cairo_pixbuf_cleanup(guchar *, void *data)
Cleanup function for GdkPixbuf.
static constexpr uint16_t get_luminance(uint32_t r, uint32_t g, uint32_t b)
void ink_matrix_to_cairo(cairo_matrix_t &cm, Geom::Affine const &m)
static guint32 srgb_to_linear(const guint32 c, const guint32 a)
void ink_matrix_to_2geom(Geom::Affine &m, cairo_matrix_t const &cm)
cairo_surface_t * ink_cairo_surface_create_output(cairo_surface_t *image, cairo_surface_t *bg)
cairo_operator_t ink_css_blend_to_cairo_operator(SPBlendMode css_blend)
GdkPixbuf * ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s)
Converts the Cairo surface to a GdkPixbuf pixel format, without allocating extra memory.
void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci)
Set the color_interpolation_value for a Cairo surface.
Cairo integration helpers.
G_GNUC_CONST guint32 premul_alpha(const guint32 color, const guint32 alpha)
G_GNUC_CONST guint32 unpremul_alpha(const guint32 color, const guint32 alpha)
struct _GdkPixbuf GdkPixbuf
Cairo::RefPtr< Cairo::ImageSurface > surface
3x3 matrix representing an affine transformation.
Bezier curve with compile-time specified order.
Two-dimensional Bezier curve of arbitrary order.
Point controlPoint(unsigned ix) const
Access control points of the curve.
Abstract continuous curve on a plane defined on [0,1].
Axis aligned, non-empty, generic rectangle.
bool intersects(GenericRect< C > const &r) const
Check whether the rectangles have any common points.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
void expandBy(C amount)
Expand the rectangle in both directions by the specified amount.
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Axis-aligned rectangle that can be empty.
Store paths to a PathVector.
bool empty() const
Check whether the vector contains any paths.
Sequence of contiguous curves, aka spline.
bool closed() const
Check whether the path is closed.
bool empty() const
Check whether path is empty.
const_iterator end_open() const
Point initialPoint() const
Get the first point in the path.
const_iterator begin() const
Two-dimensional point that doubles as a vector.
Coord length() const
Compute the distance from origin.
Axis aligned, non-empty rectangle.
Rotation around the origin.
uint32_t toRGBA(double opacity=1.0) const
Return an sRGB conversion of the color in RGBA int32 format.
Class to hold image data for raster images.
guchar const * getMimeData(gsize &len, std::string &mimetype) const
Retrieves the original compressed data for the surface, if any.
Pixbuf(cairo_surface_t *s)
Create a pixbuf from a Cairo surface.
static GdkPixbuf * apply_embedded_orientation(GdkPixbuf *buf)
Pixbuf * cropTo(const Geom::IntRect &area) const
Create a new Pixbuf with the image cropped to the given area.
PixelFormat _pixel_format
guchar const * pixels() const
Cairo::RefPtr< Cairo::Surface > getSurface()
GdkPixbuf * getPixbufRaw(bool convert_format=true)
Converts the pixbuf to GdkPixbuf pixel format.
GdkPixbuf * getPixbufRaw() const
void ensurePixelFormat(PixelFormat fmt)
Convert the internal pixel format between CAIRO and GDK formats.
cairo_surface_t * getSurfaceRaw()
Converts the pixbuf to Cairo pixel format and returns an image surface which can be used as a source.
static Pixbuf * create_from_file(std::string const &fn, double svgddpi=0)
static void ensure_argb32(GdkPixbuf *pb)
Converts GdkPixbuf's data to premultiplied ARGB.
static Geom::Affine get_embedded_orientation(GdkPixbuf *buf)
Gets any available orientation data and returns it as an affine.
static void ensure_pixbuf(GdkPixbuf *pb)
Converts GdkPixbuf's data back to its native format.
void _setMimeData(guchar *data, gsize len, Glib::ustring const &format)
cairo_surface_t * _surface
static Pixbuf * create_from_buffer(std::string const &, double svgddpi=0, std::string const &fn="")
static Pixbuf * create_from_data_uri(gchar const *uri, double svgdpi=0)
Preference storage class.
double getDouble(Glib::ustring const &pref_path, double def=0.0, Glib::ustring const &unit="")
Retrieve a floating point value.
static Preferences * get()
Access the singleton Preferences object.
double value(Unit const *u) const
Return the quantity's value in the specified unit.
static std::unique_ptr< SPDocument > createNewDocFromMem(std::span< char const > buffer, bool keepalive, std::string const &filename="")
constexpr double SP_RGBA32_G_F(uint32_t v)
constexpr double SP_RGBA32_R_F(uint32_t v)
constexpr double SP_RGBA32_A_F(uint32_t v)
constexpr uint32_t SP_RGBA32_F_COMPOSE(double r, double g, double b, double a)
constexpr double SP_RGBA32_B_F(uint32_t v)
vector< vpsc::Rectangle * > rs
_cairo_pattern cairo_pattern_t
struct _cairo_surface cairo_surface_t
std::unique_ptr< Magick::Image > image
void shift(T &a, T &b, T const &c)
Path cubicbezierpath_from_sbasis(D2< SBasis > const &B, double tol)
Affine identity()
Create an identity matrix.
Color make_contrasted_color(Color const &orig, double amount)
Make a darker or lighter version of the color, useful for making checkerboards.
Helper class to stream background task notifications as a series of messages.
static bool _workaround_issue_70__gdk_pixbuf_loader_write(GdkPixbufLoader *loader, guchar *decoded, gsize decoded_len, GError **error)
Incremental file read introduced to workaround https://gitlab.gnome.org/GNOME/gdk-pixbuf/issues/70.
void cairo_rectangle(cairo_t *cr, Geom::Rect const &r)
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void cairo_curve_to(cairo_t *cr, Geom::Point p1, Geom::Point p2, Geom::Point p3)
callback interface for SVG path data
PathVector - a sequence of subpaths.
Inkscape::Pixbuf * sp_generate_internal_bitmap(SPDocument *document, Geom::Rect const &area, double dpi, std::vector< SPItem const * > items, bool opaque, uint32_t const *checkerboard_color, double device_scale, std::optional< Antialiasing > antialias)
Generates a bitmap from given items.
Singleton class to access the preferences file in a convenient way.
Conversion between SBasis and Bezier basis polynomials.
@ SP_CSS_BLEND_LUMINOSITY
@ SP_CSS_BLEND_DIFFERENCE
@ SP_CSS_BLEND_COLORDODGE
@ SP_CSS_BLEND_SATURATION
@ SP_CSS_COLOR_INTERPOLATION_SRGB
@ SP_CSS_COLOR_INTERPOLATION_AUTO
@ SP_CSS_COLOR_INTERPOLATION_LINEARRGB
void cairo_set_source_rgba(cairo_t *cr, colour c)
std::tuple< char const *, Base64Data > extract_uri_data(char const *uri_data)
Attempt to extract the data in a data uri, but does not decode the base64.
URI functions as per 4.3.4 of CSS 2.1 http://www.w3.org/TR/CSS21/syndata.html#uri.
Cairo::RectangleInt geom_to_cairo(const Geom::IntRect &rect)