Skip to content

Commit

Permalink
Use stb scaling if we don't necessarily have to link SWS.
Browse files Browse the repository at this point in the history
SWS is huge, and brings a lot of dependencies not necessarily
desired when we disable video decoding. In that case, just use
STB resizing.

Issue: #140
  • Loading branch information
hzeller committed Jan 8, 2025
1 parent 20995bc commit 6497c23
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 56 deletions.
40 changes: 22 additions & 18 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,13 @@ if(WITH_TURBOJPEG)
target_compile_definitions(timg PUBLIC WITH_TIMG_JPEG)
target_link_libraries(timg
PkgConfig::TURBOJPEG
PkgConfig::EXIF
PkgConfig::AVUTIL
PkgConfig::SWSCALE)
PkgConfig::EXIF)
endif()

if(WITH_OPENSLIDE_SUPPORT)
target_sources(timg PUBLIC openslide-source.h openslide-source.cc)
target_compile_definitions(timg PUBLIC WITH_TIMG_OPENSLIDE_SUPPORT)
target_link_libraries(timg PkgConfig::OPENSLIDE
PkgConfig::AVUTIL
PkgConfig::SWSCALE)
target_link_libraries(timg PkgConfig::OPENSLIDE)
endif()

if(WITH_VIDEO_DECODING)
Expand All @@ -100,26 +96,37 @@ if(WITH_VIDEO_DECODING)
target_link_libraries(timg PkgConfig::LIBAV_DEVICE)
add_definitions(-DHAVE_AVDEVICE)
endif()
set(SHOULD_SCALE_SWS ON) # we link it anyway
endif()

if(WITH_STB_IMAGE)
# STB usuall does not come with pkg-config. Just check if we see the include
# Always want image resize2, if not, use third_party/
include(CheckIncludeFileCXX)
CHECK_INCLUDE_FILE_CXX(stb/stb_image.h HAVE_STB)
CHECK_INCLUDE_FILE_CXX(stb/stb_image.h HAVE_SYSTEM_STB)
target_sources(timg PUBLIC stb-image-source.h stb-image-source.cc)
if(NOT HAVE_STB)
message("--> Using STB from third_party/ instead")
if(NOT HAVE_SYSTEM_STB)
message("--> Using STB from third_party/")
target_include_directories(timg PRIVATE ${CMAKE_SOURCE_DIR}/third_party)
set(STB_RESIZE_VERSION2 true) # distributing resize2 in third_party/
else()
CHECK_INCLUDE_FILE_CXX(stb/stb_image_resize2.h STB_RESIZE_VERSION2)
endif()
if(STB_RESIZE_VERSION2)
target_compile_definitions(timg PUBLIC STB_RESIZE_VERSION2)
endif()
target_compile_definitions(timg PUBLIC WITH_TIMG_STB)
endif()

# TODO: for scaling, there is also zimg to explore
if(SHOULD_SCALE_SWS)
target_link_libraries(timg
PkgConfig::AVUTIL
PkgConfig::SWSCALE)
target_compile_definitions(timg PUBLIC WITH_TIMG_SWS_RESIZE)
else()
CHECK_INCLUDE_FILE_CXX(stb/stb_image_resize2.h HAVE_SYSTEM_STB_RESIZE2)
if(NOT HAVE_SYSTEM_STB_RESIZE2)
message("--> Using STB resize2 from third_party/")
target_include_directories(timg PRIVATE ${CMAKE_SOURCE_DIR}/third_party)
endif()
target_compile_definitions(timg PUBLIC WITH_TIMG_STB_RESIZE)
endif()

if(WITH_QOI_IMAGE)
include(CheckIncludeFileCXX)
CHECK_INCLUDE_FILE_CXX(qoi.h HAVE_QOI)
Expand All @@ -129,9 +136,6 @@ if(WITH_QOI_IMAGE)
target_include_directories(timg PRIVATE ${CMAKE_SOURCE_DIR}/third_party/qoi)
endif()
target_compile_definitions(timg PUBLIC WITH_TIMG_QOI)
target_link_libraries(timg
PkgConfig::AVUTIL
PkgConfig::SWSCALE)
endif()

# We always take the manpage from the checkout currently so that we don't
Expand Down
46 changes: 46 additions & 0 deletions src/image-scaler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,26 @@

#include "image-scaler.h"

#ifdef WITH_TIMG_SWS_RESIZE
extern "C" { // avutil is missing extern "C"
#include <libavutil/log.h>
#include <libavutil/pixfmt.h>
#include <libswscale/swscale.h>
}
#endif

#ifdef WITH_TIMG_STB_RESIZE
#define STB_IMAGE_RESIZE_IMPLEMENTATION
// Least amount of fuzziness on upscaling
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_BOX
#include "stb/stb_image_resize2.h"
#endif

// TODO: there is also zimg.

namespace timg {
namespace {
#if WITH_TIMG_SWS_RESIZE
static void dummy_log(void *, int, const char *, va_list) {}

class SWSImageScaler final : public ImageScaler {
Expand Down Expand Up @@ -53,13 +65,47 @@ class SWSImageScaler final : public ImageScaler {

SwsContext *const sws_context_;
};
#endif
#if WITH_TIMG_STB_RESIZE
class STBImageScaler final : public ImageScaler {
public:
static STBImageScaler *Create(int in_width, int in_height,
ColorFmt in_color_format, int out_width,
int out_height) {
return new STBImageScaler(in_color_format);
}

void Scale(Framebuffer &in, Framebuffer *out) final {
struct STBIR_RESIZE context {};
stbir_resize_init(&context, (uint8_t *)in.begin(), in.width(),
in.height(), 0, (uint8_t *)out->begin(), out->width(),
out->height(), 0, STBIR_RGBA, STBIR_TYPE_UINT8);
stbir_set_pixel_layouts(
&context, in_fmt_ == ColorFmt::kRGBA ? STBIR_RGBA : STBIR_BGRA,
STBIR_RGBA);
stbir_resize_extended(&context);
}

private:
explicit STBImageScaler(ColorFmt in_fmt) : in_fmt_(in_fmt) {}
const ColorFmt in_fmt_;
};
#endif
} // namespace

std::unique_ptr<ImageScaler> ImageScaler::Create(int in_width, int in_height,
ColorFmt in_color_format,
int out_width,
int out_height) {
#if WITH_TIMG_SWS_RESIZE
return std::unique_ptr<ImageScaler>(SWSImageScaler::Create(
in_width, in_height, in_color_format, out_width, out_height));
#elif WITH_TIMG_STB_RESIZE
return std::unique_ptr<ImageScaler>(STBImageScaler::Create(
in_width, in_height, in_color_format, out_width, out_height));
#else
#error "Configure issue: no image scaler available"
return nullptr;
#endif
}
} // namespace timg
41 changes: 10 additions & 31 deletions src/stb-image-source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,12 @@
#include "buffered-write-sequencer.h"
#include "display-options.h"
#include "framebuffer.h"
#include "image-scaler.h"
#include "image-source.h"
#include "renderer.h"
#include "stb/stb_image.h"
#include "timg-time.h"

#define STB_IMAGE_RESIZE_IMPLEMENTATION
// Least amount of fuzziness on upscaling
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_BOX

// There is an old and a new version of stb resize. Prefer newer if available
// (tested for in CMake), and provide adapter functions to use either.
#if STB_RESIZE_VERSION2
#include "stb/stb_image_resize2.h"
inline void stb_resize_image(const unsigned char *input_pixels, int input_w,
int input_h, unsigned char *output_pixels,
int output_w, int output_h) {
static constexpr stbir_pixel_layout kFramebufferFormat = STBIR_RGBA;
stbir_resize_uint8_linear(input_pixels, input_w, input_h, 0, //
output_pixels, output_w, output_h, 0,
kFramebufferFormat);
}

#else
#include "stb/stb_image_resize.h"
inline void stb_resize_image(const unsigned char *input_pixels, int input_w,
int input_h, unsigned char *output_pixels,
int output_w, int output_h) {
static constexpr int kFramebufferFormat = 4; // RGBA.
stbir_resize_uint8(input_pixels, input_w, input_h, 0, //
output_pixels, output_w, output_h, 0, //
kFramebufferFormat);
}
#endif

// TODO: preprocessed frame and SendFrames() are similar to
// image-display.cc. Maybe things can be consolidated.

Expand All @@ -71,8 +43,15 @@ class STBImageSource::PreprocessedFrame {
int target_w, int target_h, const Duration &delay,
const DisplayOptions &opt)
: delay_(delay), framebuffer_(target_w, target_h) {
stb_resize_image(image_data, source_w, source_h,
(uint8_t *)framebuffer_.begin(), target_w, target_h);
const size_t len = source_w * source_h * 4;
Framebuffer source_img(source_w, source_h); // TODO: avoid copy.
std::copy(image_data, image_data + len, (uint8_t *)source_img.begin());
auto scaler = ImageScaler::Create(source_w, source_h,
ImageScaler::ColorFmt::kRGBA,
target_w, target_h);
if (scaler) {
scaler->Scale(source_img, &framebuffer_);
}
framebuffer_.AlphaComposeBackground(
opt.bgcolor_getter, opt.bg_pattern_color,
opt.pattern_size * opt.cell_x_px,
Expand Down
19 changes: 12 additions & 7 deletions src/timg-print-version.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@
#include <jconfig.h>
#endif
#include <libdeflate.h>

#ifdef WITH_TIMG_SWS_RESIZE
#include <libswscale/swscale.h> // NOLINT used for version.
#endif

#include "timg-version.h" // generated.
#ifndef TIMG_VERSION
Expand Down Expand Up @@ -95,20 +98,22 @@ int PrintComponentVersions(FILE *stream) {
#endif
#ifdef WITH_TIMG_STB
fprintf(stream,
"STB image loading; STB resize v"
#ifdef STB_RESIZE_VERSION2
"2"
#else
"1"
#endif
"STB image loading"

#ifdef WITH_TIMG_GRPAPHICSMAGICK
// If we have graphics magic, that will take images first,
// so STB will only really be called as fallback.
" (fallback)"
#endif
"\n");
#endif
fprintf(stream, "swscale %s\n", AV_STRINGIFY(LIBSWSCALE_VERSION));

#ifdef WITH_TIMG_SWS_RESIZE
fprintf(stream, "Resize: swscale %s\n", AV_STRINGIFY(LIBSWSCALE_VERSION));
#else
fprintf(stream, "Resize: STB resize\n");
#endif

#ifdef WITH_TIMG_VIDEO
fprintf(stream, "Video decoding %s\n", timg::VideoSource::VersionInfo());
#endif
Expand Down

0 comments on commit 6497c23

Please sign in to comment.