Integrate jpeg-quantsmooth
Also, don't pointlessly store JPEGs in an ARGB Cairo surface.
This commit is contained in:
parent
46edd4406c
commit
2d4cab52b3
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "wuffs-mirror-release-c"]
|
||||
path = wuffs-mirror-release-c
|
||||
url = https://github.com/google/wuffs-mirror-release-c
|
||||
[submodule "jpeg-quantsmooth"]
|
||||
path = jpeg-quantsmooth
|
||||
url = https://github.com/ilyakurdyukov/jpeg-quantsmooth.git
|
||||
|
9
fastiv.c
9
fastiv.c
@ -231,6 +231,7 @@ make_key_window(void)
|
||||
/* Or perhaps "blur-symbolic", also in the extended set. */ \
|
||||
XX(SMOOTH, T("blend-tool-symbolic", "Smooth scaling")) \
|
||||
XX(CHECKERBOARD, T("checkerboard-symbolic", "Highlight transparency")) \
|
||||
XX(ENHANCE, T("heal-symbolic", "Enhance low-quality JPEG")) \
|
||||
/* XX(COLOR, B("preferences-color-symbolic", "Color management")) */ \
|
||||
XX(SAVE, B("document-save-as-symbolic", "Save as...")) \
|
||||
XX(PRINT, B("document-print-symbolic", "Print...")) \
|
||||
@ -1091,6 +1092,7 @@ make_view_toolbar(void)
|
||||
toolbar_toggler(TOOLBAR_FIT, "scale-to-fit");
|
||||
toolbar_toggler(TOOLBAR_SMOOTH, "filter");
|
||||
toolbar_toggler(TOOLBAR_CHECKERBOARD, "checkerboard");
|
||||
toolbar_toggler(TOOLBAR_ENHANCE, "enhance");
|
||||
toolbar_command(TOOLBAR_PRINT, FIV_VIEW_COMMAND_PRINT);
|
||||
toolbar_command(TOOLBAR_SAVE, FIV_VIEW_COMMAND_SAVE_PAGE);
|
||||
toolbar_command(TOOLBAR_INFO, FIV_VIEW_COMMAND_INFO);
|
||||
@ -1109,12 +1111,19 @@ make_view_toolbar(void)
|
||||
G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_SMOOTH]);
|
||||
g_signal_connect(g.view, "notify::checkerboard",
|
||||
G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_CHECKERBOARD]);
|
||||
g_signal_connect(g.view, "notify::enhance",
|
||||
G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_ENHANCE]);
|
||||
|
||||
g_object_notify(G_OBJECT(g.view), "scale");
|
||||
g_object_notify(G_OBJECT(g.view), "playing");
|
||||
g_object_notify(G_OBJECT(g.view), "scale-to-fit");
|
||||
g_object_notify(G_OBJECT(g.view), "filter");
|
||||
g_object_notify(G_OBJECT(g.view), "checkerboard");
|
||||
g_object_notify(G_OBJECT(g.view), "enhance");
|
||||
|
||||
#ifndef HAVE_JPEG_QS
|
||||
gtk_widget_set_no_show_all(g.toolbar[TOOLBAR_ENHANCE], TRUE);
|
||||
#endif
|
||||
|
||||
GCallback callback = G_CALLBACK(on_view_actions_changed);
|
||||
g_signal_connect(g.view, "notify::has-image", callback, NULL);
|
||||
|
122
fiv-io.c
122
fiv-io.c
@ -24,6 +24,16 @@
|
||||
|
||||
#include <spng.h>
|
||||
#include <turbojpeg.h>
|
||||
|
||||
#ifdef HAVE_JPEG_QS
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
// This library is tricky to build, simply make it work at all.
|
||||
#define NO_SIMD
|
||||
#include <jpeg-quantsmooth/quantsmooth.h>
|
||||
#undef NO_SIMD
|
||||
#endif // HAVE_JPEG_QS
|
||||
|
||||
#ifdef HAVE_LIBRAW
|
||||
#include <libraw.h>
|
||||
#endif // HAVE_LIBRAW
|
||||
@ -159,7 +169,7 @@ try_append_page(cairo_surface_t *surface, cairo_surface_t **result,
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// --- Wuffs -------------------------------------------------------------------
|
||||
|
||||
// From libwebp, verified to exactly match [x * a / 255].
|
||||
#define PREMULTIPLY8(a, x) (((uint32_t) (x) * (uint32_t) (a) * 32897U) >> 23)
|
||||
@ -614,6 +624,8 @@ open_wuffs_using(wuffs_base__image_decoder *(*allocate)(),
|
||||
return surface;
|
||||
}
|
||||
|
||||
// --- JPEG --------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
trivial_cmyk_to_host_byte_order_argb(unsigned char *p, int len)
|
||||
{
|
||||
@ -747,10 +759,10 @@ open_libjpeg_turbo(const gchar *data, gsize len, GError **error)
|
||||
|
||||
int pixel_format = (colorspace == TJCS_CMYK || colorspace == TJCS_YCCK)
|
||||
? TJPF_CMYK
|
||||
: (G_BYTE_ORDER == G_LITTLE_ENDIAN ? TJPF_BGRA : TJPF_ARGB);
|
||||
: (G_BYTE_ORDER == G_LITTLE_ENDIAN ? TJPF_BGRX : TJPF_XRGB);
|
||||
|
||||
cairo_surface_t *surface =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
|
||||
cairo_status_t surface_status = cairo_surface_status(surface);
|
||||
if (surface_status != CAIRO_STATUS_SUCCESS) {
|
||||
set_error(error, cairo_status_to_string(surface_status));
|
||||
@ -791,6 +803,97 @@ open_libjpeg_turbo(const gchar *data, gsize len, GError **error)
|
||||
return surface;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#ifdef HAVE_JPEG_QS
|
||||
|
||||
struct libjpeg_error_mgr {
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf buf;
|
||||
GError **error;
|
||||
};
|
||||
|
||||
static void
|
||||
libjpeg_error_exit(j_common_ptr cinfo)
|
||||
{
|
||||
struct libjpeg_error_mgr *err = (struct libjpeg_error_mgr *) cinfo->err;
|
||||
char buf[JMSG_LENGTH_MAX] = "";
|
||||
(*cinfo->err->format_message)(cinfo, buf);
|
||||
set_error(err->error, buf);
|
||||
longjmp(err->buf, 1);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
open_libjpeg_enhanced(const gchar *data, gsize len, GError **error)
|
||||
{
|
||||
cairo_surface_t *volatile surface = NULL;
|
||||
|
||||
struct libjpeg_error_mgr jerr = {.error = error};
|
||||
struct jpeg_decompress_struct cinfo = {.err = jpeg_std_error(&jerr.pub)};
|
||||
jerr.pub.error_exit = libjpeg_error_exit;
|
||||
if (setjmp(jerr.buf)) {
|
||||
g_clear_pointer(&surface, cairo_surface_destroy);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, (const unsigned char *) data, len);
|
||||
(void) jpeg_read_header(&cinfo, true);
|
||||
if (cinfo.jpeg_color_space == JCS_CMYK ||
|
||||
cinfo.jpeg_color_space == JCS_YCCK)
|
||||
cinfo.out_color_space = JCS_CMYK;
|
||||
else if (G_BYTE_ORDER == G_BIG_ENDIAN)
|
||||
cinfo.out_color_space = JCS_EXT_XRGB;
|
||||
else
|
||||
cinfo.out_color_space = JCS_EXT_BGRX;
|
||||
|
||||
jpeg_calc_output_dimensions(&cinfo);
|
||||
int width = cinfo.output_width;
|
||||
int height = cinfo.output_height;
|
||||
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
|
||||
cairo_status_t surface_status = cairo_surface_status(surface);
|
||||
if (surface_status != CAIRO_STATUS_SUCCESS) {
|
||||
set_error(error, cairo_status_to_string(surface_status));
|
||||
longjmp(jerr.buf, 1);
|
||||
}
|
||||
|
||||
unsigned char *surface_data = cairo_image_surface_get_data(surface);
|
||||
int surface_stride = cairo_image_surface_get_stride(surface);
|
||||
JSAMPARRAY lines = (*cinfo.mem->alloc_small)(
|
||||
(j_common_ptr) &cinfo, JPOOL_IMAGE, sizeof *lines * height);
|
||||
for (int i = 0; i < height; i++)
|
||||
lines[i] = surface_data + i * surface_stride;
|
||||
|
||||
// Go for the maximum quality setting.
|
||||
jpegqs_control_t opts = {
|
||||
.flags = JPEGQS_DIAGONALS | JPEGQS_JOINT_YUV | JPEGQS_UPSAMPLE_UV,
|
||||
.threads = g_get_num_processors(),
|
||||
.niter = 3,
|
||||
};
|
||||
|
||||
(void) jpegqs_start_decompress(&cinfo, &opts);
|
||||
while (cinfo.output_scanline < cinfo.output_height)
|
||||
(void) jpeg_read_scanlines(&cinfo, lines + cinfo.output_scanline,
|
||||
cinfo.output_height - cinfo.output_scanline);
|
||||
if (cinfo.out_color_space == JCS_CMYK)
|
||||
trivial_cmyk_to_host_byte_order_argb(
|
||||
surface_data, cinfo.output_width * cinfo.output_height);
|
||||
cairo_surface_mark_dirty(surface);
|
||||
(void) jpegqs_finish_decompress(&cinfo);
|
||||
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
parse_jpeg_metadata(surface, data, len);
|
||||
return surface;
|
||||
}
|
||||
|
||||
#else
|
||||
#define open_libjpeg_enhanced open_libjpeg_turbo
|
||||
#endif
|
||||
|
||||
// --- Optional dependencies ---------------------------------------------------
|
||||
|
||||
#ifdef HAVE_LIBRAW // ---------------------------------------------------------
|
||||
|
||||
static cairo_surface_t *
|
||||
@ -1831,7 +1934,7 @@ cairo_user_data_key_t fiv_io_key_page_next;
|
||||
cairo_user_data_key_t fiv_io_key_page_previous;
|
||||
|
||||
cairo_surface_t *
|
||||
fiv_io_open(const gchar *path, GError **error)
|
||||
fiv_io_open(const gchar *path, gboolean enhance, GError **error)
|
||||
{
|
||||
// TODO(p): Don't always load everything into memory, test type first,
|
||||
// so that we can reject non-pictures early. Wuffs only needs the first
|
||||
@ -1852,14 +1955,15 @@ fiv_io_open(const gchar *path, GError **error)
|
||||
if (!g_file_get_contents(path, &data, &len, error))
|
||||
return NULL;
|
||||
|
||||
cairo_surface_t *surface = fiv_io_open_from_data(data, len, path, error);
|
||||
cairo_surface_t *surface =
|
||||
fiv_io_open_from_data(data, len, path, enhance, error);
|
||||
free(data);
|
||||
return surface;
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
fiv_io_open_from_data(
|
||||
const char *data, size_t len, const gchar *path, GError **error)
|
||||
fiv_io_open_from_data(const char *data, size_t len, const gchar *path,
|
||||
gboolean enhance, GError **error)
|
||||
{
|
||||
wuffs_base__slice_u8 prefix =
|
||||
wuffs_base__make_slice_u8((uint8_t *) data, len);
|
||||
@ -1884,7 +1988,9 @@ fiv_io_open_from_data(
|
||||
error);
|
||||
break;
|
||||
case WUFFS_BASE__FOURCC__JPEG:
|
||||
surface = open_libjpeg_turbo(data, len, error);
|
||||
surface = enhance
|
||||
? open_libjpeg_enhanced(data, len, error)
|
||||
: open_libjpeg_turbo(data, len, error);
|
||||
break;
|
||||
default:
|
||||
#ifdef HAVE_LIBRAW // ---------------------------------------------------------
|
||||
|
7
fiv-io.h
7
fiv-io.h
@ -55,9 +55,10 @@ extern cairo_user_data_key_t fiv_io_key_page_next;
|
||||
/// There is no wrap-around. This is a weak pointer.
|
||||
extern cairo_user_data_key_t fiv_io_key_page_previous;
|
||||
|
||||
cairo_surface_t *fiv_io_open(const gchar *path, GError **error);
|
||||
cairo_surface_t *fiv_io_open_from_data(
|
||||
const char *data, size_t len, const gchar *path, GError **error);
|
||||
cairo_surface_t *fiv_io_open(
|
||||
const gchar *path, gboolean enhance, GError **error);
|
||||
cairo_surface_t *fiv_io_open_from_data(const char *data, size_t len,
|
||||
const gchar *path, gboolean enhance, GError **error);
|
||||
|
||||
int fiv_io_filecmp(GFile *f1, GFile *f2);
|
||||
|
||||
|
46
fiv-view.c
46
fiv-view.c
@ -40,9 +40,12 @@ struct _FivView {
|
||||
FivIoOrientation orientation; ///< Current page orientation
|
||||
bool filter; ///< Smooth scaling toggle
|
||||
bool checkerboard; ///< Show checkerboard background
|
||||
bool enhance; ///< Try to enhance picture data
|
||||
bool scale_to_fit; ///< Image no larger than the allocation
|
||||
double scale; ///< Scaling factor
|
||||
|
||||
cairo_surface_t *enhance_swap; ///< Quick swap in/out
|
||||
|
||||
int remaining_loops; ///< Greater than zero if limited
|
||||
gint64 frame_time; ///< Current frame's start, µs precision
|
||||
gulong frame_update_connection; ///< GdkFrameClock::update
|
||||
@ -95,6 +98,7 @@ enum {
|
||||
PROP_SCALE_TO_FIT,
|
||||
PROP_FILTER,
|
||||
PROP_CHECKERBOARD,
|
||||
PROP_ENHANCE,
|
||||
PROP_PLAYING,
|
||||
PROP_HAS_IMAGE,
|
||||
PROP_CAN_ANIMATE,
|
||||
@ -110,6 +114,7 @@ fiv_view_finalize(GObject *gobject)
|
||||
{
|
||||
FivView *self = FIV_VIEW(gobject);
|
||||
cairo_surface_destroy(self->image);
|
||||
g_clear_pointer(&self->enhance_swap, cairo_surface_destroy);
|
||||
g_free(self->path);
|
||||
|
||||
G_OBJECT_CLASS(fiv_view_parent_class)->finalize(gobject);
|
||||
@ -133,6 +138,9 @@ fiv_view_get_property(
|
||||
case PROP_CHECKERBOARD:
|
||||
g_value_set_boolean(value, self->checkerboard);
|
||||
break;
|
||||
case PROP_ENHANCE:
|
||||
g_value_set_boolean(value, self->enhance);
|
||||
break;
|
||||
case PROP_PLAYING:
|
||||
g_value_set_boolean(value, !!self->frame_update_connection);
|
||||
break;
|
||||
@ -173,6 +181,10 @@ fiv_view_set_property(
|
||||
if (self->checkerboard != g_value_get_boolean(value))
|
||||
fiv_view_command(self, FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD);
|
||||
break;
|
||||
case PROP_ENHANCE:
|
||||
if (self->enhance != g_value_get_boolean(value))
|
||||
fiv_view_command(self, FIV_VIEW_COMMAND_TOGGLE_ENHANCE);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
@ -1044,6 +1056,9 @@ fiv_view_class_init(FivViewClass *klass)
|
||||
view_properties[PROP_CHECKERBOARD] = g_param_spec_boolean(
|
||||
"checkerboard", "Show checkerboard", "Highlight transparent background",
|
||||
TRUE, G_PARAM_READWRITE);
|
||||
view_properties[PROP_ENHANCE] = g_param_spec_boolean(
|
||||
"enhance", "Enhance JPEG", "Enhance low-quality JPEG",
|
||||
TRUE, G_PARAM_READWRITE);
|
||||
view_properties[PROP_PLAYING] = g_param_spec_boolean(
|
||||
"playing", "Playing animation", "An animation is running",
|
||||
FALSE, G_PARAM_READABLE);
|
||||
@ -1095,12 +1110,20 @@ fiv_view_init(FivView *self)
|
||||
gboolean
|
||||
fiv_view_open(FivView *self, const gchar *path, GError **error)
|
||||
{
|
||||
cairo_surface_t *surface = fiv_io_open(path, error);
|
||||
cairo_surface_t *surface = fiv_io_open(path, self->enhance, error);
|
||||
if (!surface)
|
||||
return FALSE;
|
||||
if (self->image)
|
||||
cairo_surface_destroy(self->image);
|
||||
|
||||
// This is extremely expensive, and only works sometimes.
|
||||
g_clear_pointer(&self->enhance_swap, cairo_surface_destroy);
|
||||
if (self->enhance) {
|
||||
self->enhance = FALSE;
|
||||
g_object_notify_by_pspec(
|
||||
G_OBJECT(self), view_properties[PROP_ENHANCE]);
|
||||
}
|
||||
|
||||
self->frame = self->page = NULL;
|
||||
self->image = surface;
|
||||
switch_page(self, self->image);
|
||||
@ -1134,6 +1157,21 @@ frame_step(FivView *self, int step)
|
||||
gtk_widget_queue_draw(GTK_WIDGET(self));
|
||||
}
|
||||
|
||||
static void
|
||||
swap_enhanced_image(FivView *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
cairo_surface_t *surface = self->enhance_swap;
|
||||
if (!surface)
|
||||
surface = fiv_io_open(self->path, self->enhance, &error);
|
||||
if (!surface) {
|
||||
show_error_dialog(get_toplevel(GTK_WIDGET(self)), error);
|
||||
} else {
|
||||
self->enhance_swap = self->image;
|
||||
switch_page(self, (self->image = surface));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fiv_view_command(FivView *self, FivViewCommand command)
|
||||
{
|
||||
@ -1187,6 +1225,12 @@ fiv_view_command(FivView *self, FivViewCommand command)
|
||||
g_object_notify_by_pspec(
|
||||
G_OBJECT(self), view_properties[PROP_CHECKERBOARD]);
|
||||
gtk_widget_queue_draw(widget);
|
||||
break; case FIV_VIEW_COMMAND_TOGGLE_ENHANCE:
|
||||
self->enhance = !self->enhance;
|
||||
g_object_notify_by_pspec(
|
||||
G_OBJECT(self), view_properties[PROP_ENHANCE]);
|
||||
swap_enhanced_image(self);
|
||||
|
||||
break; case FIV_VIEW_COMMAND_PRINT:
|
||||
print(self);
|
||||
break; case FIV_VIEW_COMMAND_SAVE_PAGE:
|
||||
|
@ -43,6 +43,7 @@ typedef enum _FivViewCommand {
|
||||
|
||||
FIV_VIEW_COMMAND_TOGGLE_FILTER,
|
||||
FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD,
|
||||
FIV_VIEW_COMMAND_TOGGLE_ENHANCE,
|
||||
FIV_VIEW_COMMAND_PRINT,
|
||||
FIV_VIEW_COMMAND_SAVE_PAGE,
|
||||
FIV_VIEW_COMMAND_INFO,
|
||||
|
1
jpeg-quantsmooth
Submodule
1
jpeg-quantsmooth
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c86c6418ea6c827513d206694847033f9ca50151
|
@ -28,6 +28,7 @@ gdkpixbuf = dependency('gdk-pixbuf-2.0', required : get_option('gdk-pixbuf'))
|
||||
dependencies = [
|
||||
dependency('gtk+-3.0'),
|
||||
dependency('libturbojpeg'),
|
||||
dependency('libjpeg', required : get_option('jpeg-qs')),
|
||||
dependency('spng', version : '>=0.7.0',
|
||||
default_options: 'default_library=static'),
|
||||
dependency('pixman-1'),
|
||||
@ -47,6 +48,8 @@ dependencies = [
|
||||
conf = configuration_data()
|
||||
conf.set_quoted('PROJECT_NAME', meson.project_name())
|
||||
conf.set_quoted('PROJECT_VERSION', meson.project_version())
|
||||
# TODO(p): Wrap it in a Meson subproject, try to enable SIMD.
|
||||
conf.set('HAVE_JPEG_QS', get_option('jpeg-qs').enabled())
|
||||
conf.set('HAVE_LIBRAW', libraw.found())
|
||||
conf.set('HAVE_LIBRSVG', librsvg.found())
|
||||
conf.set('HAVE_XCURSOR', xcursor.found())
|
||||
|
@ -1,3 +1,5 @@
|
||||
option('jpeg-qs', type : 'feature', value : 'enabled',
|
||||
description : 'Build with JPEG Quant Smooth integration')
|
||||
option('libraw', type : 'feature', value : 'auto',
|
||||
description : 'Build with raw photo support, requires LibRaw')
|
||||
option('librsvg', type : 'feature', value : 'auto',
|
||||
|
107
resources/heal-symbolic.svg
Normal file
107
resources/heal-symbolic.svg
Normal file
@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<filter id="a" height="100%" width="100%" x="0%" y="0%">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
</filter>
|
||||
<mask id="b">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="c">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="d">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="e">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="f">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="g">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="h">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="i">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="j">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="k">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="l">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="m">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="n">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="o">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="p">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="q">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<mask id="r">
|
||||
<g filter="url(#a)">
|
||||
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="s">
|
||||
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/>
|
||||
</g>
|
||||
<g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 16 748 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 17 747 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 18 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 16 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 17 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 19 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<path d="m 8.4375 1.480469 c -0.21875 0.179687 -0.410156 0.410156 -0.546875 0.675781 l -4.65625 9.125 c -0.542969 1.070312 -0.109375 2.386719 0.96875 2.960938 l 0.945313 0.496093 c 1.074218 0.570313 2.371093 0.175781 2.914062 -0.894531 l 4.660156 -9.121094 c 0.542969 -1.070312 0.109375 -2.390625 -0.96875 -2.960937 l -0.945312 -0.496094 c -0.804688 -0.429687 -1.726563 -0.320313 -2.371094 0.214844 z m -1.472656 4.464843 c 0.332031 -0.246093 0.8125 -0.179687 1.0625 0.140626 c 0.253906 0.320312 0.1875 0.789062 -0.140625 1.035156 c -0.332031 0.246094 -0.8125 0.183594 -1.0625 -0.140625 c -0.253907 -0.320313 -0.1875 -0.789063 0.140625 -1.035157 z m -0.992188 1.980469 c 0.328125 -0.246093 0.808594 -0.183593 1.0625 0.136719 c 0.25 0.324219 0.1875 0.792969 -0.144531 1.039062 c -0.328125 0.246094 -0.808594 0.179688 -1.0625 -0.140624 c -0.25 -0.320313 -0.1875 -0.789063 0.144531 -1.035157 z m 3.023438 -1.011719 c 0.328125 -0.246093 0.808594 -0.183593 1.0625 0.140626 c 0.25 0.320312 0.1875 0.789062 -0.144532 1.035156 c -0.328124 0.246094 -0.808593 0.183594 -1.0625 -0.140625 c -0.25 -0.320313 -0.1875 -0.789063 0.144532 -1.035157 z m -0.992188 1.980469 c 0.328125 -0.246093 0.808594 -0.183593 1.0625 0.136719 c 0.25 0.324219 0.183594 0.792969 -0.144531 1.039062 c -0.328125 0.242188 -0.8125 0.179688 -1.0625 -0.140624 c -0.25 -0.320313 -0.1875 -0.789063 0.144531 -1.035157 z m 0 0" fill="#2e3436"/>
|
||||
<path d="m 3.59375 3 c -0.839844 -0.035156 -1.609375 0.4375 -1.96875 1.28125 l -0.4375 1 c -0.480469 1.128906 0 2.46875 1.09375 3 l 0.875 0.40625 l 2.4375 -4.90625 l -1.15625 -0.5625 c -0.273438 -0.132812 -0.5625 -0.207031 -0.84375 -0.21875 z m 9.28125 4.28125 l -2.46875 4.90625 l 1.21875 0.59375 c 1.09375 0.53125 2.332031 0.066406 2.8125 -1.0625 l 0.4375 -1 c 0.480469 -1.128906 0 -2.46875 -1.09375 -3 z m 0 0" fill="#2e3436" fill-opacity="0.501961"/>
|
||||
<g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 136 776 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/>
|
||||
</g>
|
||||
<g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -96 -756)">
|
||||
<path d="m 219 758 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
@ -5,5 +5,6 @@
|
||||
<file preprocess="xml-stripblanks">funnel-symbolic.svg</file>
|
||||
<file preprocess="xml-stripblanks">blend-tool-symbolic.svg</file>
|
||||
<file preprocess="xml-stripblanks">checkerboard-symbolic.svg</file>
|
||||
<file preprocess="xml-stripblanks">heal-symbolic.svg</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
Loading…
Reference in New Issue
Block a user