comparison Framework/Fonts/GlyphTextureAlphabet.cpp @ 577:b098a3aaf694

alphabet of glyphs
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 19 Apr 2019 15:42:57 +0200
parents
children 9a474e90e832
comparison
equal deleted inserted replaced
576:529c9617654b 577:b098a3aaf694
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 "GlyphTextureAlphabet.h"
23
24 #include "TextBoundingBox.h"
25 #include "../Toolbox/DynamicBitmap.h"
26
27 #include <Core/Images/Image.h>
28 #include <Core/Images/ImageProcessing.h>
29 #include <Core/OrthancException.h>
30
31 #include <boost/math/special_functions/round.hpp>
32
33
34 namespace OrthancStone
35 {
36 class GlyphTextureAlphabet::GlyphSizeVisitor : public GlyphAlphabet::IGlyphVisitor
37 {
38 private:
39 unsigned int maxWidth_;
40 unsigned int maxHeight_;
41
42 public:
43 GlyphSizeVisitor() :
44 maxWidth_(0),
45 maxHeight_(0)
46 {
47 }
48
49 virtual void Visit(uint32_t unicode,
50 const Glyph& glyph)
51 {
52 maxWidth_ = std::max(maxWidth_, glyph.GetWidth());
53 maxHeight_ = std::max(maxHeight_, glyph.GetHeight());
54 }
55
56 unsigned int GetMaxWidth() const
57 {
58 return maxWidth_;
59 }
60
61 unsigned int GetMaxHeight() const
62 {
63 return maxHeight_;
64 }
65 };
66
67
68 class GlyphTextureAlphabet::TextureGenerator : public GlyphAlphabet::IGlyphVisitor
69 {
70 private:
71 std::auto_ptr<Orthanc::ImageAccessor> texture_;
72
73 unsigned int countColumns_;
74 unsigned int countRows_;
75 GlyphAlphabet& targetAlphabet_;
76 unsigned int glyphMaxWidth_;
77 unsigned int glyphMaxHeight_;
78 unsigned int column_;
79 unsigned int row_;
80
81 public:
82 TextureGenerator(GlyphAlphabet& targetAlphabet,
83 unsigned int countGlyphs,
84 unsigned int glyphMaxWidth,
85 unsigned int glyphMaxHeight) :
86 targetAlphabet_(targetAlphabet),
87 glyphMaxWidth_(glyphMaxWidth),
88 glyphMaxHeight_(glyphMaxHeight),
89 column_(0),
90 row_(0)
91 {
92 int c = boost::math::iround<int>(sqrt(static_cast<float>(countGlyphs)));
93
94 if (c <= 0)
95 {
96 countColumns_ = 1;
97 }
98 else
99 {
100 countColumns_ = static_cast<unsigned int>(c);
101 }
102
103 countRows_ = countGlyphs / countColumns_;
104 if (countGlyphs % countColumns_ != 0)
105 {
106 countRows_++;
107 }
108
109 texture_.reset(new Orthanc::Image(Orthanc::PixelFormat_RGBA32,
110 countColumns_ * glyphMaxWidth_,
111 countRows_ * glyphMaxHeight_,
112 true /* force minimal pitch */));
113
114 Orthanc::ImageProcessing::Set(*texture_, 0, 0, 0, 0);
115 }
116
117
118 virtual void Visit(uint32_t unicode,
119 const Glyph& glyph)
120 {
121 if (!glyph.HasPayload())
122 {
123 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
124 }
125
126 if (column_ >= countColumns_ ||
127 row_ >= countRows_)
128 {
129 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
130 }
131
132 unsigned int x = column_ * glyphMaxWidth_;
133 unsigned int y = row_ * glyphMaxHeight_;
134
135 const Orthanc::ImageAccessor& source = dynamic_cast<const DynamicBitmap&>(glyph.GetPayload()).GetBitmap();
136
137 if (source.GetFormat() != Orthanc::PixelFormat_Grayscale8)
138 {
139 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
140 }
141
142 targetAlphabet_.Register(unicode, glyph, new TextureLocation(x, y));
143
144 Orthanc::ImageAccessor target;
145 texture_->GetRegion(target, x, y, source.GetWidth(), source.GetHeight());
146
147 //Orthanc::ImageProcessing::Copy(target, bitmap->GetBitmap());
148
149 for (unsigned int y = 0; y < source.GetHeight(); y++)
150 {
151 const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
152 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
153
154 for (unsigned int x = 0; x < source.GetWidth(); x++)
155 {
156 // Premultiplied alpha
157 q[0] = 0;
158 q[1] = 0;
159 q[2] = 0;
160 q[3] = *p;
161
162 p++;
163 q += 4;
164 }
165 }
166
167 column_++;
168 if (column_ == countColumns_)
169 {
170 column_ = 0;
171 row_++;
172 }
173 }
174
175
176 Orthanc::ImageAccessor* ReleaseTexture()
177 {
178 return texture_.release();
179 }
180 };
181
182
183 class GlyphTextureAlphabet::RenderTextVisitor : public GlyphAlphabet::ITextVisitor
184 {
185 private:
186 Orthanc::ImageAccessor& target_;
187 const Orthanc::ImageAccessor& texture_;
188 int offsetX_;
189 int offsetY_;
190
191 public:
192 RenderTextVisitor(Orthanc::ImageAccessor& target,
193 const GlyphTextureAlphabet& that,
194 int offsetX,
195 int offsetY) :
196 target_(target),
197 texture_(that.GetTexture()),
198 offsetX_(offsetX),
199 offsetY_(offsetY)
200 {
201 }
202
203 virtual void Visit(uint32_t unicode,
204 int x,
205 int y,
206 unsigned int width,
207 unsigned int height,
208 const Orthanc::IDynamicObject* payload)
209 {
210 int left = x + offsetX_;
211 int top = y + offsetY_;
212
213 assert(payload != NULL);
214 const TextureLocation& location = *dynamic_cast<const TextureLocation*>(payload);
215
216 assert(left >= 0 &&
217 top >= 0 &&
218 static_cast<unsigned int>(left) + width <= target_.GetWidth() &&
219 static_cast<unsigned int>(top) + height <= target_.GetHeight());
220
221 {
222 Orthanc::ImageAccessor to;
223 target_.GetRegion(to, left, top, width, height);
224
225 Orthanc::ImageAccessor from;
226 texture_.GetRegion(from, location.GetX(), location.GetY(), width, height);
227
228 Orthanc::ImageProcessing::Copy(to, from);
229 }
230 }
231 };
232
233
234 GlyphTextureAlphabet::GlyphTextureAlphabet(const GlyphBitmapAlphabet& sourceAlphabet) :
235 textureWidth_(0),
236 textureHeight_(0)
237 {
238 GlyphSizeVisitor size;
239 sourceAlphabet.GetAlphabet().Apply(size);
240
241 TextureGenerator generator(alphabet_,
242 sourceAlphabet.GetAlphabet().GetSize(),
243 size.GetMaxWidth(),
244 size.GetMaxHeight());
245 sourceAlphabet.GetAlphabet().Apply(generator);
246
247 texture_.reset(generator.ReleaseTexture());
248 textureWidth_ = texture_->GetWidth();
249 textureHeight_ = texture_->GetHeight();
250 }
251
252
253 const Orthanc::ImageAccessor& GlyphTextureAlphabet::GetTexture() const
254 {
255 if (texture_.get() == NULL)
256 {
257 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
258 }
259 else
260 {
261 return *texture_;
262 }
263 }
264
265
266 Orthanc::ImageAccessor* GlyphTextureAlphabet::ReleaseTexture()
267 {
268 if (texture_.get() == NULL)
269 {
270 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
271 }
272 else
273 {
274 return texture_.release();
275 }
276 }
277
278
279 Orthanc::ImageAccessor* GlyphTextureAlphabet::RenderText(const std::string& utf8)
280 {
281 TextBoundingBox box(alphabet_, utf8);
282
283 std::auto_ptr<Orthanc::ImageAccessor> bitmap(
284 new Orthanc::Image(Orthanc::PixelFormat_RGBA32,
285 box.GetWidth(), box.GetHeight(),
286 true /* force minimal pitch */));
287
288 Orthanc::ImageProcessing::Set(*bitmap, 0, 0, 0, 0);
289
290 RenderTextVisitor visitor(*bitmap, *this, -box.GetLeft(), -box.GetTop());
291 alphabet_.Apply(visitor, utf8);
292
293 return bitmap.release();
294 }
295 }