mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-04 13:59:46 +00:00
Add ft library (a freetype wrapper)
This commit is contained in:
parent
64111bf991
commit
d33a2adb64
@ -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
20
src/ft/LICENSE.txt
Normal 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
4
src/ft/README.md
Normal 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
96
src/ft/face.h
Normal 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
14
src/ft/freetype_headers.h
Normal 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
46
src/ft/lib.h
Normal 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
|
Loading…
Reference in New Issue
Block a user