freepdfeditor/spike/B_reconstruction/GlyphRun.h

86 lines
3.5 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors
//
// GlyphRun.h — the reconstruction pipeline's input model. Mirrors the L3
// GlyphRun from §3.2 of the plan: a sequence of glyphs sharing font, size,
// color and CTM, each glyph carrying its Unicode mapping and confidence.
//
// The reconstruction spike (§4.1) takes a vector of these and produces
// paragraphs. In production these come from the content-stream interpreter;
// in the spike they come from a synthetic generator so the pipeline can be
// scored against ground truth without the full L3 stack.
#ifndef FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H
#define FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H
#include <cstdint>
#include <string>
#include <vector>
namespace freepdfeditor::spike::b {
struct Point { float x; float y; };
// A single glyph as the reconstruction pipeline sees it. `unicode` and
// `confidence` are produced by the glyph→Unicode step (§4.1 step 1); the
// geometry is in device space (post-CTM) so line detection works in page
// coordinates.
struct Glyph {
std::uint32_t gid = 0; // glyph id in the font
std::uint32_t code = 0; // character code in the content stream
std::uint32_t unicode = 0; // resolved Unicode codepoint (0 if unknown)
float confidence = 0.0f; // [0,1] — see §4.1 step 1 priority ladder
Point origin {}; // pen position before this glyph (device space)
float advance = 0.0f; // horizontal advance (device space)
};
// A run of glyphs sharing typography: font, size, color, text matrix. This is
// the unit the content-stream interpreter emits; the reconstruction pipeline
// merges and re-splits runs as it builds lines and paragraphs.
struct GlyphRun {
std::uint64_t font_id = 0;
float size = 0.0f; // font size in points
float char_spacing = 0.0f;
float word_spacing = 0.0f;
float rise = 0.0f; // superscript/subscript
float rotation = 0.0f; // baseline direction in radians (0 = LTR horizontal)
// Glyphs in logical order along the baseline (advance is signed along the
// baseline direction; the pipeline handles RTL by negative advance).
std::vector<Glyph> glyphs;
};
// A detected line: glyphs whose baselines agree and which read in sequence.
struct Line {
std::vector<std::size_t> run_indices; // indices into the input run vector
float baseline_y = 0.0f; // in the run's text space (cluster along baseline dir)
float x_start = 0.0f;
float x_end = 0.0f;
float size = 0.0f; // dominant font size on this line
std::u32string text; // concatenated Unicode, in reading order
std::string marker; // list marker ("•", "1.", etc.) if detected
};
// A paragraph: consecutive lines with consistent leading and extent.
struct Paragraph {
std::vector<std::size_t> line_indices; // indices into the line vector
float top = 0.0f;
float bottom = 0.0f;
float left = 0.0f;
float right = 0.0f;
std::u32string text; // full paragraph text, lines joined
bool is_list_item = false;
};
// Ground-truth label for one paragraph, used by the scorer. Coordinates are in
// the same device space as the glyph origins.
struct GroundTruthParagraph {
float top = 0.0f;
float bottom = 0.0f;
float left = 0.0f;
float right = 0.0f;
std::u32string text;
};
} // namespace freepdfeditor::spike::b
#endif // FREEPDFEDITOR_SPIKE_B_GLYPHRUN_H