Add ft library (a freetype wrapper)

This commit is contained in:
David Capello 2016-03-10 11:21:03 -03:00
parent 64111bf991
commit d33a2adb64
6 changed files with 192 additions and 89 deletions

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -18,116 +18,39 @@
#include "doc/color.h" #include "doc/color.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/primitives.h" #include "doc/primitives.h"
#include "ft/face.h"
#include "ft/lib.h"
#include <stdexcept> #include <stdexcept>
#include "freetype/ftglyph.h"
#include "ft2build.h"
#include FT_FREETYPE_H
namespace app { namespace app {
template<typename Iterator, typename Func>
static void for_each_glyph(FT_Face face, bool antialias,
Iterator first, Iterator end,
Func callback)
{
bool use_kerning = (FT_HAS_KERNING(face) ? true: false);
// Calculate size
FT_UInt prev_glyph = 0;
int x = 0;
for (; first != end; ++first) {
FT_UInt glyph_index = FT_Get_Char_Index(face, *first);
if (use_kerning && prev_glyph && glyph_index) {
FT_Vector kerning;
FT_Get_Kerning(face, prev_glyph, glyph_index,
FT_KERNING_DEFAULT, &kerning);
x += kerning.x >> 6;
}
FT_Error err = FT_Load_Glyph(
face, glyph_index,
FT_LOAD_RENDER |
FT_LOAD_NO_BITMAP |
(antialias ? FT_LOAD_TARGET_NORMAL:
FT_LOAD_TARGET_MONO));
if (!err) {
callback(x, face->glyph);
x += face->glyph->advance.x >> 6;
}
prev_glyph = glyph_index;
}
}
class ScopedFTLib {
public:
ScopedFTLib(FT_Library& ft) : m_ft(ft) {
FT_Init_FreeType(&m_ft);
}
~ScopedFTLib() {
FT_Done_FreeType(m_ft);
}
private:
FT_Library& m_ft;
};
class ScopedFTFace {
public:
ScopedFTFace(FT_Face& face) : m_face(face) {
}
~ScopedFTFace() {
FT_Done_Face(m_face);
}
private:
FT_Face& m_face;
};
doc::Image* render_text(const std::string& fontfile, int fontsize, doc::Image* render_text(const std::string& fontfile, int fontsize,
const std::string& text, const std::string& text,
doc::color_t color, doc::color_t color,
bool antialias) bool antialias)
{ {
base::UniquePtr<doc::Image> image(nullptr); base::UniquePtr<doc::Image> image(nullptr);
FT_Library ft; ft::Lib ft;
ScopedFTLib init_and_done_ft(ft);
FT_Open_Args args;
memset(&args, 0, sizeof(args));
args.flags = FT_OPEN_PATHNAME;
args.pathname = (FT_String*)fontfile.c_str();
FT_Face face;
FT_Error err = FT_Open_Face(ft, &args, 0, &face);
if (!err) {
ScopedFTFace done_face(face);
ft::Face face(ft.open(fontfile));
if (face) {
// Set font size // Set font size
FT_Set_Pixel_Sizes(face, fontsize, fontsize); face.setSize(fontsize);
face.setAntialias(antialias);
// Calculate text size // Calculate text size
base::utf8_const_iterator begin(text.begin()), end(text.end()); base::utf8_const_iterator begin(text.begin()), end(text.end());
gfx::Rect bounds(0, 0, 0, 0); gfx::Rect bounds = face.calcTextBounds(begin, end);
for_each_glyph(
face, antialias, begin, end,
[&bounds](int x, FT_GlyphSlot glyph) {
bounds |= gfx::Rect(x + glyph->bitmap_left,
-glyph->bitmap_top,
(int)glyph->bitmap.width,
(int)glyph->bitmap.rows);
});
// Render the image and copy it to the clipboard // Render the image and copy it to the clipboard
if (!bounds.isEmpty()) { if (!bounds.isEmpty()) {
image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h)); image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h));
doc::clear_image(image, 0); doc::clear_image(image, 0);
for_each_glyph( face.forEachGlyph(
face, antialias, begin, end, begin, end,
[&bounds, &image, color, antialias](int x, FT_GlyphSlot glyph) { [&bounds, &image, color, antialias](FT_GlyphSlot glyph, int x) {
int t, yimg = - bounds.y - glyph->bitmap_top; int t, yimg = - bounds.y - glyph->bitmap_top;
for (int v=0; v<(int)glyph->bitmap.rows; ++v, ++yimg) { for (int v=0; v<(int)glyph->bitmap.rows; ++v, ++yimg) {

20
src/ft/LICENSE.txt Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2016 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

4
src/ft/README.md Normal file
View File

@ -0,0 +1,4 @@
# Aseprite FreeType Wrapper
*Copyright (C) 2016 David Capello*
> Distributed under [MIT license](LICENSE.txt)

96
src/ft/face.h Normal file
View File

@ -0,0 +1,96 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_FACE_H_INCLUDED
#define FT_FACE_H_INCLUDED
#pragma once
#include "ft/freetype_headers.h"
namespace ft {
class Face {
public:
Face(FT_Face face = nullptr) : m_face(face) {
}
~Face() {
if (m_face)
FT_Done_Face(m_face);
}
operator FT_Face() {
return m_face;
}
bool antialias() const {
return m_antialias;
}
void setAntialias(bool antialias) {
m_antialias = antialias;
}
void setSize(int size) {
FT_Set_Pixel_Sizes(m_face, size, size);
}
template<typename Iterator,
typename Callback>
void forEachGlyph(Iterator first, Iterator end, Callback callback) {
bool use_kerning = (FT_HAS_KERNING(m_face) ? true: false);
FT_UInt prev_glyph = 0;
int x = 0;
for (; first != end; ++first) {
FT_UInt glyph_index = FT_Get_Char_Index(m_face, *first);
if (use_kerning && prev_glyph && glyph_index) {
FT_Vector kerning;
FT_Get_Kerning(m_face, prev_glyph, glyph_index,
FT_KERNING_DEFAULT, &kerning);
x += kerning.x >> 6;
}
FT_Error err = FT_Load_Glyph(
m_face, glyph_index,
FT_LOAD_RENDER |
FT_LOAD_NO_BITMAP |
(m_antialias ? FT_LOAD_TARGET_NORMAL:
FT_LOAD_TARGET_MONO));
if (!err) {
callback(m_face->glyph, x);
x += m_face->glyph->advance.x >> 6;
}
prev_glyph = glyph_index;
}
}
template<typename Iterator>
gfx::Rect calcTextBounds(Iterator first, Iterator end) {
gfx::Rect bounds(0, 0, 0, 0);
forEachGlyph(first, end,
[&bounds](FT_GlyphSlot glyph, int x) {
bounds |= gfx::Rect(x + glyph->bitmap_left,
-glyph->bitmap_top,
(int)glyph->bitmap.width,
(int)glyph->bitmap.rows);
});
return bounds;
}
private:
FT_Face m_face;
bool m_antialias;
};
} // namespace ft
#endif

14
src/ft/freetype_headers.h Normal file
View File

@ -0,0 +1,14 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_FREETYPE_HEADERS_H_INCLUDED
#define FT_FREETYPE_HEADERS_H_INCLUDED
#pragma once
#include "ft2build.h"
#include FT_FREETYPE_H
#endif

46
src/ft/lib.h Normal file
View File

@ -0,0 +1,46 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_LIB_H_INCLUDED
#define FT_LIB_H_INCLUDED
#pragma once
#include "ft/freetype_headers.h"
namespace ft {
class Lib {
public:
Lib() : m_ft(nullptr) {
FT_Init_FreeType(&m_ft);
}
~Lib() {
FT_Done_FreeType(m_ft);
}
operator FT_Library() {
return m_ft;
}
FT_Face open(const std::string& filename) {
FT_Open_Args args;
memset(&args, 0, sizeof(args));
args.flags = FT_OPEN_PATHNAME;
args.pathname = (FT_String*)filename.c_str();
FT_Face face = nullptr;
FT_Error err = FT_Open_Face(m_ft, &args, 0, &face);
return face;
}
private:
FT_Library m_ft;
};
} // namespace ft
#endif