comparison Framework/Fonts/FontRenderer.cpp @ 576:529c9617654b

FontRenderer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 19 Apr 2019 15:11:16 +0200
parents
children 9a474e90e832
comparison
equal deleted inserted replaced
575:919226caca82 576:529c9617654b
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "FontRenderer.h"
23
24 #include "../Toolbox/DynamicBitmap.h"
25
26 #include <Core/OrthancException.h>
27
28
29 #include <ft2build.h>
30 #include FT_FREETYPE_H
31 #include FT_GLYPH_H
32
33
34 // https://stackoverflow.com/questions/31161284/how-can-i-get-the-corresponding-error-string-from-an-ft-error-code
35 static std::string GetErrorMessage(FT_Error err)
36 {
37 #undef __FTERRORS_H__
38 #define FT_ERRORDEF( e, v, s ) case e: return s;
39 #define FT_ERROR_START_LIST switch (err) {
40 #define FT_ERROR_END_LIST }
41 #include FT_ERRORS_H
42 return "(Unknown error)";
43 }
44
45
46 static void CheckError(FT_Error err)
47 {
48 if (err != 0)
49 {
50 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
51 "Error in FreeType: " + GetErrorMessage(err));
52 }
53 }
54
55
56 namespace OrthancStone
57 {
58 class FontRenderer::PImpl : public boost::noncopyable
59 {
60 private:
61 std::string fontContent_;
62 FT_Library library_;
63 FT_Face face_;
64
65 void Clear()
66 {
67 if (face_ != NULL)
68 {
69 FT_Done_Face(face_);
70 face_ = NULL;
71 }
72
73 fontContent_.clear();
74 }
75
76 public:
77 PImpl() :
78 library_(NULL),
79 face_(NULL)
80 {
81 CheckError(FT_Init_FreeType(&library_));
82 }
83
84
85 ~PImpl()
86 {
87 Clear();
88 FT_Done_FreeType(library_);
89 }
90
91
92 void LoadFont(const std::string& fontContent,
93 unsigned int fontSize)
94 {
95 Clear();
96
97 // It is necessary to make a private copy of the font, as
98 // Freetype makes the assumption that the buffer containing the
99 // font is never deleted
100 fontContent_.assign(fontContent);
101
102 const FT_Byte* data = reinterpret_cast<const FT_Byte*>(fontContent_.c_str());
103
104 CheckError(FT_New_Memory_Face(library_, data, fontContent_.size(), 0, &face_));
105 CheckError(FT_Set_Char_Size(face_, // handle to face object
106 0, // char_width in 1/64th of points
107 fontSize * 64, // char_height in 1/64th of points
108 72, // horizontal device resolution
109 72)); // vertical device resolution
110
111 CheckError(FT_Select_Charmap(face_, FT_ENCODING_UNICODE));
112 }
113
114
115 Glyph* Render(uint32_t unicode)
116 {
117 if (face_ == NULL)
118 {
119 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls,
120 "First call LoadFont()");
121 }
122 else if (FT_Load_Char(face_, unicode, FT_LOAD_RENDER) != 0)
123 {
124 // This character is not available
125 return NULL;
126 }
127 else
128 {
129 if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP)
130 {
131 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
132 //CheckError(FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1));
133 }
134
135 Orthanc::ImageAccessor bitmap;
136 bitmap.AssignReadOnly(Orthanc::PixelFormat_Grayscale8,
137 face_->glyph->bitmap.width,
138 face_->glyph->bitmap.rows,
139 face_->glyph->bitmap.pitch,
140 face_->glyph->bitmap.buffer);
141
142 std::auto_ptr<Glyph> glyph(
143 new Glyph(bitmap.GetWidth(),
144 bitmap.GetHeight(),
145 face_->glyph->bitmap_left,
146 -face_->glyph->bitmap_top, // Positive for an upwards vertical distance
147 face_->glyph->advance.x >> 6,
148 face_->glyph->metrics.vertAdvance >> 6));
149
150 glyph->SetPayload(new DynamicBitmap(bitmap));
151
152 return glyph.release();
153 }
154 }
155 };
156
157
158
159 FontRenderer::FontRenderer() :
160 pimpl_(new PImpl)
161 {
162 }
163
164
165 void FontRenderer::LoadFont(const std::string& fontContent,
166 unsigned int fontSize)
167 {
168 pimpl_->LoadFont(fontContent, fontSize);
169 }
170
171
172 void FontRenderer::LoadFont(Orthanc::EmbeddedResources::FileResourceId resource,
173 unsigned int fontSize)
174 {
175 std::string content;
176 Orthanc::EmbeddedResources::GetFileResource(content, resource);
177 LoadFont(content, fontSize);
178 }
179
180
181 Glyph* FontRenderer::Render(uint32_t unicode)
182 {
183 return pimpl_->Render(unicode);
184 }
185 }