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>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user