Files
effector/src/effects/text.hpp
T
SiandClaude Opus 5 1d0343b90a Add a text effect
Writes a line or several over its input in a chosen family, weight, size
and colour, optionally on a box filled with a colour or with a picture
from disk. Like the blur and the overlay it needs no sources of its own,
so it can lead a chain; given sources it fills the canvas from a randomly
chosen one first.

Two param types rather than effect-specific branches in the front-ends:
Text, free-form text the user types, and Color, a colour written
"#rrggbb". Both travel as strings, so the interface gets an entry and a
colour button, the command line gets a flag (a colour that does not parse
is refused there rather than drawn as black), and a project keeps them
across a round trip.

The glyphs come from Pango, which draws through Cairo without a display,
so the core stays headless — but they are the one thing here that is not
byte-identical across machines: a machine without the chosen family
renders the substitute its fontconfig picks. Everything the effect is
handed, the rng included, is used exactly as every other effect uses it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 20:31:24 +02:00

50 lines
1.8 KiB
C++

#pragma once
#include <cstdint>
#include <mutex>
#include <string>
#include <vector>
#include "core/effect.hpp"
namespace effector {
// Writes a line (or several) over its input: a title, a caption, a watermark.
// The family and the weight are chosen freely, and the text can sit on a box
// filled with a colour or with a picture from disk. Like the blur and the
// overlay it needs no source images of its own, so it can lead a chain; given
// sources it fills the canvas from a randomly chosen one first.
//
// The glyphs come from Pango, so the exact pixels depend on the fonts the
// machine has installed: a seed reproduces everything this effect draws, but a
// machine without the chosen family renders the substitute its fontconfig
// picks.
class TextEffect : public Effect {
public:
std::string name() const override { return "text"; }
std::string title() const override { return "Text"; }
std::string description() const override {
return "Writes text over its input in a chosen family, weight and size, optionally on a "
"box filled with a colour or with a picture.";
}
const std::vector<ParamSpec>& params() const override;
bool needsSources() const override { return false; }
Image render(const std::vector<Image>& sources, int width, int height, Rng& rng,
const ParamValues& values) const override;
private:
// The box picture is re-read on every param change otherwise, and a render
// is a keystroke away in the interface. Renders can overlap, so it is
// guarded.
void loadBoxImage(const std::string& path, Image& image,
std::vector<std::uint8_t>& alpha) const;
mutable std::mutex cacheMutex_;
mutable std::string cachedPath_;
mutable Image cached_;
mutable std::vector<std::uint8_t> cachedAlpha_;
};
} // namespace effector