UI: SVG Thumbnails #109567

Merged
Harley Acheson merged 11 commits from Harley/blender:SvgThumbs into main 2023-07-12 22:39:30 +02:00
15 changed files with 1616 additions and 13 deletions

View File

@ -22,6 +22,7 @@ endif()
add_subdirectory(rangetree)
add_subdirectory(nanosvg)
add_subdirectory(wcwidth)
if(WITH_BULLET)

21
extern/nanosvg/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2002-2022 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
PUBLIC .
../../source/blender/blenlib
)
set(SRC
nanosvg.h
nanosvgrast.h
blender_nanosvg.c
blender_raster.c
)
set(LIB
)
blender_add_lib(extern_nanosvg "${SRC}" "${INC}" "" "${LIB}")
add_library(bf::extern::nanosvg ALIAS extern_nanosvg)

10
extern/nanosvg/blender_nanosvg.c vendored Normal file
View File

@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#define NANOSVG_IMPLEMENTATION
#define NANOSVG_ALL_COLOR_KEYWORDS
#include <stdio.h>
#include "BLI_utildefines.h"
#include "nanosvg.h"

6
extern/nanosvg/blender_raster.c vendored Normal file
View File

@ -0,0 +1,6 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"

1458
extern/nanosvg/nanosvgrast.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1504,7 +1504,7 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
BLI_assert(preview->flags &
(FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
FILE_TYPE_OBJECT_IO | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
if (preview->flags & FILE_TYPE_IMAGE) {
source = THB_SOURCE_IMAGE;
@ -1519,6 +1519,9 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
else if (preview->flags & FILE_TYPE_FTFONT) {
source = THB_SOURCE_FONT;
}
else if (preview->flags & FILE_TYPE_OBJECT_IO) {
source = THB_SOURCE_OBJECT_IO;
}
IMB_thumb_path_lock(preview->filepath);
/* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
@ -1620,8 +1623,9 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
if (!(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)))
if (!(entry->typeflag &
(FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_OBJECT_IO |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)))
{
return;
}

View File

@ -32,6 +32,7 @@ set(SRC
intern/format_hdr.cc
intern/format_png.cc
intern/format_psd.cc
intern/format_svg.cc
intern/format_targa.cc
intern/format_tiff.cc
intern/imageprocess.cc
@ -82,6 +83,7 @@ set(LIB
PRIVATE bf::intern::guardedalloc
bf_intern_memutil
bf_intern_opencolorio
PRIVATE bf::extern::nanosvg
${JPEG_LIBRARIES}
)

View File

@ -31,6 +31,7 @@ typedef enum ThumbSource {
THB_SOURCE_MOVIE,
THB_SOURCE_BLEND,
THB_SOURCE_FONT,
THB_SOURCE_OBJECT_IO,
} ThumbSource;
/**

View File

@ -290,6 +290,19 @@ struct ImBuf *imb_load_psd(const unsigned char *mem,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Format: SVG - Only for thumbnails.
* \{ */
struct ImBuf *imb_load_filepath_thumbnail_svg(const char *filepath,
const int flags,
const size_t max_thumb_size,
char colorspace[],
size_t *r_width,
size_t *r_height);
/** \} */
#ifdef __cplusplus
};
#endif

View File

@ -199,6 +199,22 @@ const ImFileType IMB_FILE_TYPES[] = {
/*default_save_role*/ COLOR_ROLE_DEFAULT_BYTE,
},
#endif
{
Harley marked this conversation as resolved
Review

There should be a code-comment explaining why only the thumbnail callback is set as it's not obvious.

There should be a code-comment explaining why only the thumbnail callback is set as it's not obvious.
/* Only implementing thumbnailing for SVG file type to support specialized importers.
* General file loading, if wanted, would require a better library and would have to
* support features like user-specified resolution. */
/*init*/ nullptr,
/*exit*/ nullptr,
/*is_a*/ nullptr,
/*load*/ nullptr,
/*load_filepath*/ nullptr,
/*load_filepath_thumbnail*/ imb_load_filepath_thumbnail_svg,
/*save*/ nullptr,
/*flag*/ 0,
/*filetype*/ IMB_FTYPE_NONE,
/*default_save_role*/ COLOR_ROLE_DEFAULT_BYTE,
},
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 0, 0, 0},
};

View File

@ -0,0 +1,66 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
*
* SVG vector graphics format support for the purpose of thumbnail-display.
* While loading these as an #ImBuf is trivial to support, it would expose
* limitations of NANOSVG and users may end up needing more advanced options
* specific to loading vector graphics (such as resolution control), see #109567 for details.
*/
#include "IMB_colormanagement.h"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
Harley marked this conversation as resolved
Review

Could the C-only function call a static local function? (to avoid extern "C" the whole file).

Could the C-only function call a static local function? (to avoid `extern "C"` the whole file).
#include "nanosvg.h"
#include "nanosvgrast.h"
Harley marked this conversation as resolved Outdated

Also note here, that only thumbnails are supported and why.

Also note here, that only thumbnails are supported and why.

It's not so obvious where this kind of info should be included, I'd prefer the file header, as this comment isn't a doc-string for the function, e.g.

/* SPDX-FileCopyrightText: 2023 Blender Foundation
 *
 * SPDX-License-Identifier: GPL-2.0-or-later */

/** \file
 * \ingroup imbuf
 *
 * SVG vector graphics format support for the purpose of thumbnail-display.
 * While loading these as an #ImBuf is trivial to support, it would expose
 * limitations of NANOSVG and users may end up needing more advanced options
 * spesific to loading vector graphics (such as resolution control), see #109567 for details.
 */
It's not so obvious where this kind of info should be included, I'd prefer the file header, as this comment isn't a doc-string for the function, e.g. ``` /* SPDX-FileCopyrightText: 2023 Blender Foundation * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup imbuf * * SVG vector graphics format support for the purpose of thumbnail-display. * While loading these as an #ImBuf is trivial to support, it would expose * limitations of NANOSVG and users may end up needing more advanced options * spesific to loading vector graphics (such as resolution control), see #109567 for details. */ ```
ImBuf *imb_load_filepath_thumbnail_svg(const char *filepath,
const int /* flags */,
const size_t max_thumb_size,
char colorspace[],
size_t *r_width,
size_t *r_height)
{
NSVGimage *image = nsvgParseFromFile(filepath, "px", 96.0f);
if (image == nullptr) {
return nullptr;
}
if (image->width == 0 || image->height == 0) {
nsvgDelete(image);
return nullptr;
}
int w = int(image->width);
int h = int(image->height);
/* Return full size of the image. */
*r_width = size_t(w);
*r_height = size_t(h);
NSVGrasterizer *rast = nsvgCreateRasterizer();
if (rast == nullptr) {
nsvgDelete(image);
return nullptr;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
const float scale = float(max_thumb_size) / MAX2(w, h);
const int dest_w = MAX2(int(w * scale), 1);
const int dest_h = MAX2(int(h * scale), 1);
ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rect);
if (ibuf != nullptr) {
nsvgRasterize(rast, image, 0, 0, scale, ibuf->byte_buffer.data, dest_w, dest_h, dest_w * 4);
nsvgDeleteRasterizer(rast);
nsvgDelete(image);
IMB_flipy(ibuf);
}
return ibuf;
}

View File

@ -361,7 +361,8 @@ static ImBuf *thumb_create_ex(const char *file_path,
}
}
else {
if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT, THB_SOURCE_OBJECT_IO))
{
/* only load if we didn't give an image */
if (img == nullptr) {
switch (source) {
@ -374,6 +375,12 @@ static ImBuf *thumb_create_ex(const char *file_path,
case THB_SOURCE_FONT:
img = IMB_thumb_load_font(file_path, tsize, tsize);
break;
case THB_SOURCE_OBJECT_IO: {
if (BLI_path_extension_check(file_path, ".svg")) {
img = IMB_thumb_load_image(file_path, tsize, nullptr);
}
break;
}
default:
BLI_assert_unreachable(); /* This should never happen */
}

View File

@ -11,11 +11,12 @@ set(INC
../../bmesh
../../depsgraph
../../editors/include
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/clog
../../../../intern/utfconv
../../../../extern/nanosvg
../../../../intern/guardedalloc
../../../../intern/utfconv
)
set(INC_SYS
@ -32,15 +33,13 @@ set(SRC
intern/gpencil_io_export_base.hh
intern/gpencil_io_import_base.hh
intern/gpencil_io_import_svg.hh
# Only so this file is known by CMake.
../../../../extern/nanosvg/nanosvg.h
)
set(LIB
bf_blenkernel
bf_blenlib
PRIVATE bf::dna
PRIVATE bf::extern::nanosvg
PRIVATE bf::intern::guardedalloc
bf_io_common
)

View File

@ -23,10 +23,6 @@
#include "gpencil_io.h"
#include "gpencil_io_import_svg.hh"
/* Custom flags for NanoSVG. */
#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
using blender::MutableSpan;

View File

@ -112,6 +112,9 @@ static PyObject *bpy_utils_previews_load(PyObject *UNUSED(self), PyObject *args)
else if (STREQ(path_type_s, "FONT")) {
path_type = THB_SOURCE_FONT;
}
else if (STREQ(path_type_s, "OBJECT_IO")) {
path_type = THB_SOURCE_OBJECT_IO;
}
else {
PyErr_Format(PyExc_ValueError,
"load: invalid '%s' filetype, only [" STR_SOURCE_TYPES