Mercurial > hg > orthanc-stone
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Fonts/FontRenderer.cpp Fri Apr 19 15:11:16 2019 +0200 @@ -0,0 +1,185 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "FontRenderer.h" + +#include "../Toolbox/DynamicBitmap.h" + +#include <Core/OrthancException.h> + + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_GLYPH_H + + +// https://stackoverflow.com/questions/31161284/how-can-i-get-the-corresponding-error-string-from-an-ft-error-code +static std::string GetErrorMessage(FT_Error err) +{ +#undef __FTERRORS_H__ +#define FT_ERRORDEF( e, v, s ) case e: return s; +#define FT_ERROR_START_LIST switch (err) { +#define FT_ERROR_END_LIST } +#include FT_ERRORS_H + return "(Unknown error)"; +} + + +static void CheckError(FT_Error err) +{ + if (err != 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, + "Error in FreeType: " + GetErrorMessage(err)); + } +} + + +namespace OrthancStone +{ + class FontRenderer::PImpl : public boost::noncopyable + { + private: + std::string fontContent_; + FT_Library library_; + FT_Face face_; + + void Clear() + { + if (face_ != NULL) + { + FT_Done_Face(face_); + face_ = NULL; + } + + fontContent_.clear(); + } + + public: + PImpl() : + library_(NULL), + face_(NULL) + { + CheckError(FT_Init_FreeType(&library_)); + } + + + ~PImpl() + { + Clear(); + FT_Done_FreeType(library_); + } + + + void LoadFont(const std::string& fontContent, + unsigned int fontSize) + { + Clear(); + + // It is necessary to make a private copy of the font, as + // Freetype makes the assumption that the buffer containing the + // font is never deleted + fontContent_.assign(fontContent); + + const FT_Byte* data = reinterpret_cast<const FT_Byte*>(fontContent_.c_str()); + + CheckError(FT_New_Memory_Face(library_, data, fontContent_.size(), 0, &face_)); + CheckError(FT_Set_Char_Size(face_, // handle to face object + 0, // char_width in 1/64th of points + fontSize * 64, // char_height in 1/64th of points + 72, // horizontal device resolution + 72)); // vertical device resolution + + CheckError(FT_Select_Charmap(face_, FT_ENCODING_UNICODE)); + } + + + Glyph* Render(uint32_t unicode) + { + if (face_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, + "First call LoadFont()"); + } + else if (FT_Load_Char(face_, unicode, FT_LOAD_RENDER) != 0) + { + // This character is not available + return NULL; + } + else + { + if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + //CheckError(FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1)); + } + + Orthanc::ImageAccessor bitmap; + bitmap.AssignReadOnly(Orthanc::PixelFormat_Grayscale8, + face_->glyph->bitmap.width, + face_->glyph->bitmap.rows, + face_->glyph->bitmap.pitch, + face_->glyph->bitmap.buffer); + + std::auto_ptr<Glyph> glyph( + new Glyph(bitmap.GetWidth(), + bitmap.GetHeight(), + face_->glyph->bitmap_left, + -face_->glyph->bitmap_top, // Positive for an upwards vertical distance + face_->glyph->advance.x >> 6, + face_->glyph->metrics.vertAdvance >> 6)); + + glyph->SetPayload(new DynamicBitmap(bitmap)); + + return glyph.release(); + } + } + }; + + + + FontRenderer::FontRenderer() : + pimpl_(new PImpl) + { + } + + + void FontRenderer::LoadFont(const std::string& fontContent, + unsigned int fontSize) + { + pimpl_->LoadFont(fontContent, fontSize); + } + + + void FontRenderer::LoadFont(Orthanc::EmbeddedResources::FileResourceId resource, + unsigned int fontSize) + { + std::string content; + Orthanc::EmbeddedResources::GetFileResource(content, resource); + LoadFont(content, fontSize); + } + + + Glyph* FontRenderer::Render(uint32_t unicode) + { + return pimpl_->Render(unicode); + } +}