dl
dl_free_type.h
浏览该文件的文档.
1
11#pragma once
12
13#ifndef DL_DISABLE_RENDER
14#include <vector>
15#include <string>
16#include <unordered_map>
17#include <cassert>
18
19#include <ft2build.h>
20#include FT_FREETYPE_H
21#include FT_STROKER_H
22
23#include "io/dl_log.h"
24#include "memory/dl_code_cvt.h"
25#include "dl_font.h"
26#include "base/dl_color.h"
27#include "io/dl_file.h"
28
29namespace dl
30{
32 constexpr size_t NUM_MAX_FONT = 16;
35{
36public:
37 // 某字体某大小的属性
38 struct Property
39 {
40 float _ascent; // 基线上方
41 float _descent;// 基线下方
42 float _linegap;// 行空白
44 float GetLinespace() const
45 {
46 return _ascent - _descent + _linegap;
47 }
48 };
49
50 // 表示水平的一段连续数据
51 struct Span
52 {
53 int _x;
54 int _y;
55 int _w;
56 int _coverage;// 为uint8_t透明度
57
58 Span(){}
59 Span(int x, int y, int w, int coverage):
60 _x(x), _y(y), _w(w), _coverage(coverage)
61 {}
62 };
63 // 渲染器回调,写入Span
64 static void RasterCallback(int y, int count, const FT_Span* spans, void* user)
65 {
66 std::vector<Span>* sptr = (std::vector<Span>*)user;
67 for (int i = 0; i < count; ++i)
68 sptr->push_back(Span(spans[i].x, y, spans[i].len, spans[i].coverage));
69 }
70 // 设置光栅参数,且渲染描边
71 void RenderSpans(FT_Library& library, FT_Outline* outline, std::vector<Span>* spans)
72 {
73 FT_Raster_Params params;
74 memset(&params, 0, sizeof(params));
75 params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
76 params.gray_spans = RasterCallback;
77 params.user = spans;
78
79 FT_Outline_Render(library, outline, &params);
80 }
81 struct CharRect
82 {
83 float _xMin;
84 float _xMax;
85 float _yMin;
86 float _yMax;
87
89 CharRect(float left, float top, float right, float bottom):
90 _xMin(left), _xMax(right), _yMin(top), _yMax(bottom)
91 {}
92
93 void Include(int x, int y)
94 {
95 _xMin = (std::min)(_xMin, float(x));
96 _yMin = (std::min)(_yMin, float(y));
97 _xMax = (std::max)(_xMax, float(x));
98 _yMax = (std::max)(_yMax, float(y));
99 }
100
101 float Width() { return _xMax - _xMin + 1; }
102 float Height() { return _yMax - _yMin + 1; }
103 };
104
106 {
107 if (FT_Init_FreeType(&_library))
108 {
109 log_err0("FreeType初始化失败!");
110 _library = nullptr;
111 }
112 _vecBuffer.resize(NUM_MAX_FONT);
113 }
114
115 size_t LoadFace(std::string_view path_name)
116 {
117 if (_vecFace.size() >= NUM_MAX_FONT)
118 {
119 log_err0("字体数加载超过上限!你可以修改 NUM_MAX_FONT值来支持更多。");
120 return -1;
121 }
122 Buffer& buf =_vecBuffer[_vecFace.size()];
123 buf = File::GetBuffer(path_name);
124 if (buf.empty())
125 return -1;
126 FT_Face face;
127 if (FT_New_Memory_Face(_library, (FT_Byte*)buf.data(), (FT_Long)buf.size(),
128 0, &face))
129 {
130 log_err("字体文件加载失败: {}", path_name);
131 return -1;
132 }
133 assert(FT_IS_SCALABLE(face));
134
135 //打印一些属性
136 log_msg("成功加载一个字体:{},{}", _vecFace.size(), path_name);
137 log_("名称:{}", face->family_name);// 不是utf8
138 log_("字形数:{}", face->num_glyphs);
139 //debug(format("包围盒:({}, {}),({}, {})",
140 // face->bbox.xMin, face->bbox.xMax,
141 // face->bbox.yMin, face->bbox.yMax));
142 _vecFace.push_back(face);
143 _vecProperty.push_back({});
144 return _vecFace.size() - 1;
145 }
146
148 {
149 //错误输出
150 auto fn_debug = [&](std::string_view str)
151 {
152 log_err("{}:{},{},{},{}",
153 str, info._font, std::to_string(info._ch), info._size, info._outline);
154 };
155
156 if (info._font >= _vecFace.size())
157 {
158 fn_debug("字体id越界");
159 return nullptr;
160 }
161
162 const char32_t& ch = info._ch;
163 const size_t& size = info._size;
164 const size_t& outline = info._outline;
165
166 FT_Face ft_face = _vecFace[info._font];
167 if (FT_Select_Charmap(ft_face, FT_ENCODING_UNICODE))
168 {
169 fn_debug("设置编码失败");
170 return nullptr;
171 }
172
173 if (FT_Set_Char_Size(ft_face, FT_F26Dot6(size << 6), FT_F26Dot6(size << 6), 72, 72))
174 {
175 fn_debug("设置字体大小失败");
176 return nullptr;
177 }
178
179 FT_UInt gindex = FT_Get_Char_Index(ft_face, ch);
180 if (FT_Load_Glyph(ft_face, gindex, FT_LOAD_NO_BITMAP))
181 {
182 fn_debug("字形加载失败");
183 return nullptr;
184 }
185 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
186 {
187 fn_debug("不支持描边");
188 return nullptr;
189 }
190 //渲染到 spans
191 std::vector<Span> spans;
192 RenderSpans(_library, &ft_face->glyph->outline, &spans);
193
194 //接下来渲染到 spans_outline
195 std::vector<Span> spans_outline;
196
197 //设置画笔
198 FT_Stroker stroker;
199 FT_Stroker_New(_library, &stroker);
200 FT_Stroker_Set(stroker,
201 (int)(outline * 64),
202 FT_STROKER_LINECAP_ROUND,
203 FT_STROKER_LINEJOIN_ROUND,
204 0);
205
206 FT_Glyph glyph;
207 if (FT_Get_Glyph(ft_face->glyph, &glyph))
208 {
209 fn_debug("获取字形失败");
210 return nullptr;
211 }
212
213 FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
214 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
215 {
216 //绘制outline到 outline_spans
217 FT_Outline* o =
218 &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
219 RenderSpans(_library, o, &spans_outline);
220 }
221
222 //清理后面无需用到的资源
223 FT_Stroker_Done(stroker);
224 FT_Done_Glyph(glyph);
225
226 if (spans.empty())
227 {
228 fn_debug("spans为空(或许打印了控制字符)");
229 return nullptr;
230 }
231 //计算二者包围盒(描边更大)
232 CharRect rect(
233 float(spans.front()._x),
234 float(spans.front()._y),
235 float(spans.front()._x),
236 float(spans.front()._y));
237 for (Span& s : spans)
238 {
239 rect.Include(s._x, s._y);
240 rect.Include(s._x + s._w - 1, s._y);
241 }
242 for (Span& s : spans_outline)
243 {
244 rect.Include(s._x, s._y);
245 rect.Include(s._x + s._w - 1, s._y);
246 }
247
248 //获得必要的属性
249 unsigned img_w = (unsigned)rect.Width();
250 unsigned img_h = (unsigned)rect.Height();
251
252
253 //分配图像内存,以0颜色
254 Image* img_outline = Img::Create({ img_w ,img_h }, ColorDef::NONE);
255 Image* img = Img::Create({ img_w ,img_h }, ColorDef::NONE);
256
257 //这里取得image buffer指针来赋值
258 uint32_t* p_lock = img_outline->GetData();
259
260 //复制到img_outline
261 for (Span& s : spans_outline)
262 {
263 for (int w = 0; w < s._w; ++w)
264 {
265 size_t y = (size_t)(img_h - 1 - (s._y - rect._yMin));
266 size_t index = (size_t)(y * img_w + s._x - rect._xMin + w);
267 p_lock[index] = uint32_t(s._coverage) << 24 | 0x00ffffff;
268 }
269 }
270 //复制到img
271 p_lock = img->GetData();
272 for (Span& s : spans)
273 {
274 for (int w = 0; w < s._w; ++w)
275 {
276 size_t y = (size_t)(img_h - 1 - (s._y - rect._yMin));
277 size_t index = (size_t)(y * img_w + s._x - rect._xMin + w);
278 p_lock[index] = uint32_t(s._coverage) << 24 | 0x00ffffff;
279 }
280 }
281
282 float bearingX = float(ft_face->glyph->metrics.horiBearingX >> 6);
283 float bearingY = float(ft_face->glyph->metrics.horiBearingY >> 6);
284 float advance = float(ft_face->glyph->advance.x >> 6);
285
286 CharImage* ret = new CharImage;
287
288 ret->_advance = advance;
289 ret->_bearingX = bearingX;
290 ret->_bearingY = bearingY;
291 ret->_image = img;
292 ret->_imageOutline = img_outline;
293
294 Property& prop = _vecProperty[info._font][info._size];
295 prop._ascent = float(ft_face->size->metrics.ascender >> 6);
296 prop._descent = float(ft_face->size->metrics.descender >> 6);
297 prop._linegap = 0;
298 //prop._linegap = float(ft_face->size->metrics.y_ppem >> 6);
299
300 return ret;
301 }
302
303
304 size_t GetFontSize()
305 {
306 return _vecFace.size();
307 }
308
309 const Property& GetProperty(size_t font, unsigned size)
310 {
311 std::unordered_map<int, Property>& vec = _vecProperty[font];
312 auto iter = vec.find(size);
313 if (iter == vec.end())
314 {
315 log_err0("不应该出现的情况!");
316 return _vecProperty[font][size];
317 }
318 return iter->second;
319 }
320
322 {
323 for (auto& iter : _vecFace)
324 FT_Done_Face(iter);
325 FT_Done_FreeType(_library);
326 }
327private:
328 FT_Library _library;
329 std::vector<Buffer> _vecBuffer;
330 std::vector<FT_Face> _vecFace;
331 std::vector<std::unordered_map<int, Property>> _vecProperty;
332};
333
334extern FreeType* g_freetype;
335
336}
337#endif
size_t size() const
std::byte * data()
const Property & GetProperty(size_t font, unsigned size)
static void RasterCallback(int y, int count, const FT_Span *spans, void *user)
CharImage * GetChar(const CharInfo &info)
void RenderSpans(FT_Library &library, FT_Outline *outline, std::vector< Span > *spans)
size_t LoadFace(std::string_view path_name)
加载字体文件,返回编号,-1为失败
编码转换
文件系统
字体解析结构
日志系统
#define log_msg(...)
#define log_(...)
#define log_err(...)
constexpr Color NONE
Buffer GetBuffer(std::string_view path_name)
返回文件内存
Image * Create(const Size &size, const Color &col)
创建图像
void log_err0(std::string_view str, DL_SOURCE_LOCATION)
constexpr size_t NUM_MAX_FONT
最大加载字体数
FreeType * g_freetype
Vector2< uint32_t, unsigned > Image
字符图像数据
Image * _imageOutline
float _bearingY
左侧离 对齐点的距离
float _advance
顶部到 基线的距离
字符信息
std::size_t _font
unsigned _outline
unsigned _size
void Include(int x, int y)
CharRect(float left, float top, float right, float bottom)
float GetLinespace() const
返回标准行间距
Span(int x, int y, int w, int coverage)