]> git.localhorst.tv Git - ffmpeg-test.git/commitdiff
pango text rendering
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 29 Sep 2024 14:26:30 +0000 (16:26 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 29 Sep 2024 14:26:30 +0000 (16:26 +0200)
Makefile
src/app/Renderer.h
src/cairo/Context.h
src/main.cpp
src/pango/Font.h [new file with mode: 0644]
src/pango/Layout.h [new file with mode: 0644]

index d2d0188035b9c6969ca1e37742eb8d4c429907a5..cc390cb84e0f6cb2279b0ae552c6c1a527864913 100644 (file)
--- 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 $@
index d32587fe2d0e4cdb4ec52ae0bb44a82a6b84e288..bb81c79df77f6d65cf0f239d4ee7e65500799191 100644 (file)
@@ -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;
 
 };
 
index 0eaa600affd3ed8e71850233f871cdd0a704c6cd..6824820faacf20b54b968605b191037a30d0d0ea 100644 (file)
@@ -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;
index 33833f3bec89760a1f927a621d2227a2530934a8..36f0cac6c2561107f93e749a70707f10e0fc317c 100644 (file)
@@ -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<app::Renderer *>(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 (file)
index 0000000..54d2573
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef TEST_PANGO_FONT_H_
+#define TEST_PANGO_FONT_H_
+
+#include <pango/pango.h>
+#include <stdexcept>
+
+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 (file)
index 0000000..3e52df9
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef TEST_PANGO_LAYOUT_H_
+#define TEST_PANGO_LAYOUT_H_
+
+#include <cairo.h>
+#include <glib-object.h>
+#include <pango/pangocairo.h>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#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>(pango::Layout &a, pango::Layout &b) {
+       a.Swap(b);
+}
+
+}
+
+#endif