From 623719abe209e547799bc3944d4ba12f1c169435 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Sun, 29 Sep 2024 16:26:30 +0200 Subject: [PATCH] pango text rendering --- Makefile | 2 +- src/app/Renderer.h | 25 +++++++------- src/cairo/Context.h | 5 +++ src/main.cpp | 6 +++- src/pango/Font.h | 40 +++++++++++++++++++++++ src/pango/Layout.h | 80 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 src/pango/Font.h create mode 100644 src/pango/Layout.h diff --git a/Makefile b/Makefile index d2d0188..cc390cb 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CPP_SRCS = $(shell find src -name \*.cpp) CPP_DEPS = $(shell find src -name \*.h) -LIBS = cairo freetype2 jsoncpp libavformat libavcodec libavutil libswresample libswscale libuv libwebsockets +LIBS = cairo freetype2 jsoncpp libavformat libavcodec libavutil libswresample libswscale libuv libwebsockets pangocairo main: $(CPP_SRCS) $(CPP_DEPS) clang++ -g $(shell pkg-config --cflags --libs $(LIBS)) $(CPP_SRCS) -o $@ diff --git a/src/app/Renderer.h b/src/app/Renderer.h index d32587f..bb81c79 100644 --- a/src/app/Renderer.h +++ b/src/app/Renderer.h @@ -6,11 +6,9 @@ extern "C" { #include "cairo.h" } -#include "../freetype/Face.h" -#include "../freetype/Library.h" #include "../cairo/Context.h" -#include "../cairo/Face.h" #include "../cairo/Surface.h" +#include "../pango/Layout.h" namespace app { @@ -18,14 +16,16 @@ class Renderer { public: Renderer(uint8_t *plane, int linesize, int width, int height) - : ft() - , face(ft.NewFace("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 0)) - , font(face) + : font("DejaVu Sans 32px") , surface(plane, linesize, CAIRO_FORMAT_ARGB32, width, height) , ctx(surface.CreateContext()) , width(width) , height(height) - , text("Hello") { + , text() + , text_layout(ctx.CreateLayout()) { + text_layout.SetFont(font); + text_layout.SetWidth(width / 2); + SetText("Hello, I am a long text that should wrap eventually when it gets long enough to cross the halfway point of the total width available (not including the offset which is added afterwards)."); } ~Renderer() { } @@ -39,23 +39,21 @@ public: ctx.Paint(); ctx.MoveTo(50, 50); - ctx.SetFontFace(font); - ctx.SetFontSize(16); ctx.SetSourceRGB(1, 1, 1); - ctx.ShowText(text.c_str()); + text_layout.Render(); surface.Flush(); } void SetText(const std::string &t) { text = t; + text_layout.SetText(text); + text_layout.Update(); } private: - freetype::Library ft; - freetype::Face face; - cairo::Face font; + pango::Font font; cairo::Surface surface; cairo::Context ctx; @@ -63,6 +61,7 @@ private: int height; std::string text; + pango::Layout text_layout; }; diff --git a/src/cairo/Context.h b/src/cairo/Context.h index 0eaa600..6824820 100644 --- a/src/cairo/Context.h +++ b/src/cairo/Context.h @@ -7,6 +7,7 @@ #include "Error.h" #include "Face.h" +#include "../pango/Layout.h" namespace cairo { @@ -31,6 +32,10 @@ public: Context &operator =(const Context &) = delete; public: + pango::Layout CreateLayout() { + return pango::Layout(ctx); + } + void DebugPrint() { cairo_status_t status = cairo_status(ctx); std::cout << "cairo status: " << cairo_status_to_string(status) << std::endl; diff --git a/src/main.cpp b/src/main.cpp index 33833f3..36f0cac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,8 +37,11 @@ void ws_handler(void *user, const Json::Value &json) { Json::Value data; Json::Reader json_reader; json_reader.parse(data_string, data); + const std::string text = data["model"]["text"].asString(); app::Renderer *renderer = static_cast(user); - renderer->SetText(data["model"]["text"].asString()); + if (text.length() > 0) { + renderer->SetText(text); + } } } @@ -48,6 +51,7 @@ int main(int argc, char**argv) { const int WIDTH = 1280; const int HEIGHT = 720; const int FPS = 60; + //const char *URL = "rtmp://localhost/horstiebot"; const char *URL = "rtmp://localhost/localhorsttv"; uv::Loop loop; diff --git a/src/pango/Font.h b/src/pango/Font.h new file mode 100644 index 0000000..54d2573 --- /dev/null +++ b/src/pango/Font.h @@ -0,0 +1,40 @@ +#ifndef TEST_PANGO_FONT_H_ +#define TEST_PANGO_FONT_H_ + +#include +#include + +namespace pango { + +class Font { + +public: + explicit Font(const char *name): fd(pango_font_description_from_string(name)) { + if (!fd) { + throw std::runtime_error("failed to create font description"); + } + } + ~Font() { + pango_font_description_free(fd); + } + + Font(const Font &) = delete; + Font &operator =(const Font &) = delete; + +public: + void Apply(PangoLayout *l) const { + pango_layout_set_font_description(l, fd); + } + + void SetSize(int size) { + pango_font_description_set_size(fd, size); + } + +private: + PangoFontDescription *fd; + +}; + +} + +#endif diff --git a/src/pango/Layout.h b/src/pango/Layout.h new file mode 100644 index 0000000..3e52df9 --- /dev/null +++ b/src/pango/Layout.h @@ -0,0 +1,80 @@ +#ifndef TEST_PANGO_LAYOUT_H_ +#define TEST_PANGO_LAYOUT_H_ + +#include +#include +#include +#include +#include +#include + +#include "Font.h" + +namespace pango { + +class Layout { + +public: + explicit Layout(cairo_t *c): c(c), l(pango_cairo_create_layout(c)) { + if (!l) { + throw std::runtime_error("failed to create layout"); + } + cairo_reference(c); + } + ~Layout() { + cairo_destroy(c); + g_object_unref(l); + } + Layout(const Layout &other): c(other.c), l(other.l) { + cairo_reference(c); + g_object_ref(l); + } + Layout &operator =(const Layout &other) { + Layout temp(other); + Swap(temp); + return *this; + } + void Swap(Layout &other) { + std::swap(c, other.c); + std::swap(l, other.l); + } + +public: + void Render() { + pango_cairo_show_layout(c, l); + } + + void SetFont(const Font &font) { + font.Apply(l); + } + + void SetText(const std::string &text) { + pango_layout_set_text(l, text.c_str(), text.length()); + } + + void SetWidth(int w) { + pango_layout_set_width(l, w * 1024); + } + + void Update() { + pango_cairo_update_layout(c, l); + } + +private: + cairo_t *c; + PangoLayout *l; + +}; + +} + +namespace std { + +template<> +inline void swap(pango::Layout &a, pango::Layout &b) { + a.Swap(b); +} + +} + +#endif -- 2.39.2