mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-26 18:21:44 +00:00
Add list of system fonts in PasteTextCommand dialog (on Windows)
This commit is contained in:
parent
74c2ce83dc
commit
9f8200ea3e
12
data/widgets/font_popup.xml
Normal file
12
data/widgets/font_popup.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<!-- ASEPRITE -->
|
||||
<!-- Copyright (C) 2015 by David Capello -->
|
||||
<gui>
|
||||
<vbox id="font_popup">
|
||||
<label text="Available Fonts:" />
|
||||
<view id="view" expansive="true" />
|
||||
<hbox>
|
||||
<boxfiller />
|
||||
<button id="load_font" text="Load" width="80" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
</gui>
|
@ -7,7 +7,7 @@
|
||||
<entry expansive="true" maxsize="256" id="user_text" magnet="true" cell_align="horizontal" />
|
||||
|
||||
<label text="Font:" />
|
||||
<button minwidth="60" id="font_face" text="Select Font" cell_align="horizontal" />
|
||||
<dropdownbutton minwidth="60" id="font_face" text="Select Font" cell_align="horizontal" />
|
||||
|
||||
<label text="Font Size:" />
|
||||
<entry id="font_size" maxsize="4" text="32" cell_align="horizontal" />
|
||||
|
@ -353,6 +353,7 @@ add_library(app-lib
|
||||
ui/editor/zooming_state.cpp
|
||||
ui/file_list.cpp
|
||||
ui/file_selector.cpp
|
||||
ui/font_popup.cpp
|
||||
ui/frame_tag_window.cpp
|
||||
ui/hex_color_entry.cpp
|
||||
ui/home_view.cpp
|
||||
@ -393,6 +394,7 @@ add_library(app-lib
|
||||
util/create_cel_copy.cpp
|
||||
util/expand_cel_canvas.cpp
|
||||
util/filetoks.cpp
|
||||
util/freetype_utils.cpp
|
||||
util/msk_file.cpp
|
||||
util/new_image_from_mask.cpp
|
||||
util/pic_file.cpp
|
||||
|
@ -11,22 +11,19 @@
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/console.h"
|
||||
#include "app/context.h"
|
||||
#include "app/file_selector.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/ui/drop_down_button.h"
|
||||
#include "app/ui/font_popup.h"
|
||||
#include "app/util/clipboard.h"
|
||||
#include "app/util/freetype_utils.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/path.h"
|
||||
#include "base/string.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/color.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
#include "freetype/ftglyph.h"
|
||||
#include "ft2build.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "paste_text.xml.h"
|
||||
|
||||
@ -34,37 +31,6 @@ namespace app {
|
||||
|
||||
static std::string last_text_used;
|
||||
|
||||
template<typename Iterator, typename Func>
|
||||
static void for_each_glyph(FT_Face face, 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);
|
||||
|
||||
if (!err) {
|
||||
callback(x, face->glyph);
|
||||
x += face->glyph->advance.x >> 6;
|
||||
}
|
||||
|
||||
prev_glyph = glyph_index;
|
||||
}
|
||||
}
|
||||
|
||||
class PasteTextCommand : public Command {
|
||||
public:
|
||||
PasteTextCommand();
|
||||
@ -97,7 +63,8 @@ public:
|
||||
updateFontFaceButton();
|
||||
|
||||
fontSize()->setTextf("%d", size);
|
||||
fontFace()->Click.connect(Bind<void>(&PasteTextWindow::onSelectFont, this));
|
||||
fontFace()->Click.connect(Bind<void>(&PasteTextWindow::onSelectFontFile, this));
|
||||
fontFace()->DropDownClick.connect(Bind<void>(&PasteTextWindow::onSelectSystemFont, this));
|
||||
fontColor()->setColor(color);
|
||||
}
|
||||
|
||||
@ -113,11 +80,12 @@ public:
|
||||
|
||||
private:
|
||||
void updateFontFaceButton() {
|
||||
fontFace()->setTextf("Select Font: %s",
|
||||
base::get_file_name(m_face).c_str());
|
||||
fontFace()->mainButton()
|
||||
->setTextf("Select Font: %s",
|
||||
base::get_file_title(m_face).c_str());
|
||||
}
|
||||
|
||||
void onSelectFont() {
|
||||
void onSelectFontFile() {
|
||||
std::string face = show_file_selector(
|
||||
"Select a TrueType Font",
|
||||
m_face,
|
||||
@ -126,13 +94,41 @@ private:
|
||||
nullptr);
|
||||
|
||||
if (!face.empty()) {
|
||||
m_face = face;
|
||||
ok()->setEnabled(true);
|
||||
updateFontFaceButton();
|
||||
setFontFace(face);
|
||||
}
|
||||
}
|
||||
|
||||
void setFontFace(const std::string& face) {
|
||||
m_face = face;
|
||||
ok()->setEnabled(true);
|
||||
updateFontFaceButton();
|
||||
}
|
||||
|
||||
void onSelectSystemFont() {
|
||||
if (!m_fontPopup) {
|
||||
try {
|
||||
m_fontPopup.reset(new FontPopup());
|
||||
m_fontPopup->Load.connect(&PasteTextWindow::setFontFace, this);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Console::showException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_fontPopup->isVisible()) {
|
||||
gfx::Rect bounds = fontFace()->getBounds();
|
||||
m_fontPopup->showPopup(
|
||||
gfx::Rect(bounds.x, bounds.y+bounds.h,
|
||||
ui::display_w()/2, ui::display_h()/2));
|
||||
}
|
||||
else {
|
||||
m_fontPopup->closeWindow(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_face;
|
||||
base::UniquePtr<FontPopup> m_fontPopup;
|
||||
};
|
||||
|
||||
void PasteTextCommand::onExecute(Context* ctx)
|
||||
@ -155,17 +151,7 @@ void PasteTextCommand::onExecute(Context* ctx)
|
||||
pref.textTool.fontFace(faceName);
|
||||
pref.textTool.fontSize(size);
|
||||
|
||||
FT_Library ft;
|
||||
FT_Init_FreeType(&ft);
|
||||
|
||||
FT_Open_Args args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.flags = FT_OPEN_PATHNAME;
|
||||
args.pathname = (FT_String*)faceName.c_str();
|
||||
|
||||
FT_Face face;
|
||||
FT_Error err = FT_Open_Face(ft, &args, 0, &face);
|
||||
if (!err) {
|
||||
try {
|
||||
std::string text = window.userText()->getText();
|
||||
app::Color appColor = window.fontColor()->getColor();
|
||||
doc::color_t color = doc::rgba(appColor.getRed(),
|
||||
@ -173,65 +159,17 @@ void PasteTextCommand::onExecute(Context* ctx)
|
||||
appColor.getBlue(),
|
||||
appColor.getAlpha());
|
||||
|
||||
// Set font size
|
||||
FT_Set_Pixel_Sizes(face, size, size);
|
||||
|
||||
// Calculate text size
|
||||
base::utf8_iterator begin(text.begin()), end(text.end());
|
||||
gfx::Rect bounds(0, 0, 0, 0);
|
||||
for_each_glyph(
|
||||
face, 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
|
||||
if (!bounds.isEmpty()) {
|
||||
doc::Image* image = doc::Image::create(IMAGE_RGB, bounds.w, bounds.h);
|
||||
doc::clear_image(image, 0);
|
||||
|
||||
for_each_glyph(
|
||||
face, begin, end,
|
||||
[&bounds, &image, color](int x, FT_GlyphSlot glyph) {
|
||||
int t, yimg = - bounds.y - glyph->bitmap_top;
|
||||
for (int v=0; v<(int)glyph->bitmap.rows; ++v, ++yimg) {
|
||||
const uint8_t* p = glyph->bitmap.buffer + v*glyph->bitmap.pitch;
|
||||
int ximg = x - bounds.x + glyph->bitmap_left;
|
||||
for (int u=0; u<(int)glyph->bitmap.width; ++u, ++p, ++ximg) {
|
||||
int alpha = *p;
|
||||
doc::put_pixel(
|
||||
image, ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image, ximg, yimg),
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
MUL_UN8(doc::rgba_geta(color), alpha, t)), 255));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
doc::Image* image = render_text(faceName, size, text, color);
|
||||
if (image) {
|
||||
clipboard::copy_image(image, nullptr, nullptr);
|
||||
clipboard::paste();
|
||||
}
|
||||
else {
|
||||
ui::Alert::show(PACKAGE
|
||||
"<<There is no text"
|
||||
"||&OK");
|
||||
}
|
||||
|
||||
FT_Done_Face(face);
|
||||
}
|
||||
else {
|
||||
catch (const std::exception& ex) {
|
||||
ui::Alert::show(PACKAGE
|
||||
"<<Error loading font face"
|
||||
"||&OK");
|
||||
"<<%s"
|
||||
"||&OK", ex.what());
|
||||
}
|
||||
|
||||
FT_Done_FreeType(ft);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createPasteTextCommand()
|
||||
|
192
src/app/ui/font_popup.cpp
Normal file
192
src/app/ui/font_popup.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// 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
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/font_popup.h"
|
||||
|
||||
#include "app/commands/cmd_set_palette.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/console.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/freetype_utils.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/string.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/conversion_she.h"
|
||||
#include "doc/image.h"
|
||||
#include "she/surface.h"
|
||||
#include "she/system.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/preferred_size_event.h"
|
||||
#include "ui/theme.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
#include "font_popup.xml.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
class FontItem : public ListItem {
|
||||
public:
|
||||
FontItem(std::string& fontsDir, const std::string& fn)
|
||||
: ListItem(fn)
|
||||
, m_fontsDir(fontsDir) {
|
||||
}
|
||||
|
||||
private:
|
||||
void onPaint(PaintEvent& ev) override {
|
||||
if (!m_image) {
|
||||
ListItem::onPaint(ev);
|
||||
}
|
||||
else {
|
||||
app::skin::SkinTheme* theme = app::skin::SkinTheme::instance();
|
||||
Graphics* g = ev.getGraphics();
|
||||
she::Surface* sur = she::instance()->createRgbaSurface(m_image->width(),
|
||||
m_image->height());
|
||||
|
||||
convert_image_to_surface(
|
||||
m_image.get(), nullptr, sur,
|
||||
0, 0, 0, 0, m_image->width(), m_image->height());
|
||||
|
||||
gfx::Color bg;
|
||||
if (isSelected())
|
||||
bg = theme->colors.listitemSelectedFace();
|
||||
else
|
||||
bg = theme->colors.listitemNormalFace();
|
||||
|
||||
g->fillRect(bg, getClientBounds());
|
||||
g->drawRgbaSurface(sur, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void onPreferredSize(PreferredSizeEvent& ev) override {
|
||||
if (m_image)
|
||||
ev.setPreferredSize(m_image->width(),
|
||||
m_image->height());
|
||||
else
|
||||
ListItem::onPreferredSize(ev);
|
||||
}
|
||||
|
||||
void onSelect() override {
|
||||
if (!getParent())
|
||||
return;
|
||||
|
||||
ASSERT(getParent());
|
||||
ASSERT(getParent()->type() == kListBoxWidget);
|
||||
|
||||
std::string filename = base::join_path(m_fontsDir, getText());
|
||||
app::skin::SkinTheme* theme = app::skin::SkinTheme::instance();
|
||||
gfx::Color color = theme->colors.text();
|
||||
|
||||
try {
|
||||
m_image.reset(
|
||||
render_text(
|
||||
filename, 16,
|
||||
getText(),
|
||||
doc::rgba(gfx::getr(color),
|
||||
gfx::getg(color),
|
||||
gfx::getb(color),
|
||||
gfx::geta(color))));
|
||||
|
||||
getParent()->layout();
|
||||
invalidate();
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Console::showException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string& m_fontsDir;
|
||||
base::UniquePtr<doc::Image> m_image;
|
||||
};
|
||||
|
||||
FontPopup::FontPopup()
|
||||
: PopupWindow("Fonts", kCloseOnClickInOtherWindow)
|
||||
, m_popup(new gen::FontPopup())
|
||||
{
|
||||
setAutoRemap(false);
|
||||
setBorder(gfx::Border(4*guiscale()));
|
||||
|
||||
addChild(m_popup);
|
||||
|
||||
m_popup->loadFont()->Click.connect(Bind<void>(&FontPopup::onLoadFont, this));
|
||||
m_listBox.Change.connect(Bind<void>(&FontPopup::onChangeFont, this));
|
||||
m_listBox.DoubleClickItem.connect(Bind<void>(&FontPopup::onLoadFont, this));
|
||||
|
||||
m_popup->view()->attachToView(&m_listBox);
|
||||
|
||||
#if _WIN32
|
||||
{
|
||||
std::vector<wchar_t> buf(MAX_PATH);
|
||||
HRESULT hr = SHGetFolderPath(NULL, CSIDL_FONTS, NULL,
|
||||
SHGFP_TYPE_DEFAULT, &buf[0]);
|
||||
if (hr == S_OK) {
|
||||
m_fontsDir = base::to_utf8(&buf[0]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_fontsDir.empty()) {
|
||||
auto& files = base::list_files(m_fontsDir);
|
||||
std::sort(files.begin(), files.end());
|
||||
for (auto& file : files) {
|
||||
if (base::string_to_lower(base::get_file_extension(file)) == "ttf")
|
||||
m_listBox.addChild(new FontItem(m_fontsDir, file));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_listBox.getChildren().empty())
|
||||
m_listBox.addChild(new ListItem("No system fonts were found"));
|
||||
}
|
||||
|
||||
void FontPopup::showPopup(const gfx::Rect& bounds)
|
||||
{
|
||||
m_popup->loadFont()->setEnabled(false);
|
||||
m_listBox.selectChild(NULL);
|
||||
|
||||
moveWindow(bounds);
|
||||
|
||||
// Setup the hot-region
|
||||
setHotRegion(gfx::Region(gfx::Rect(bounds).enlarge(32 * guiscale())));
|
||||
|
||||
openWindow();
|
||||
}
|
||||
|
||||
void FontPopup::onChangeFont()
|
||||
{
|
||||
m_popup->loadFont()->setEnabled(true);
|
||||
}
|
||||
|
||||
void FontPopup::onLoadFont()
|
||||
{
|
||||
Widget* child = m_listBox.getSelectedChild();
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
std::string filename = base::join_path(m_fontsDir,
|
||||
child->getText());
|
||||
if (base::is_file(filename))
|
||||
Load(filename); // Fire Load signal
|
||||
|
||||
closeWindow(nullptr);
|
||||
}
|
||||
|
||||
} // namespace app
|
50
src/app/ui/font_popup.h
Normal file
50
src/app/ui/font_popup.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// 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
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_UI_FONT_POPUP_H_INCLUDED
|
||||
#define APP_UI_FONT_POPUP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/listbox.h"
|
||||
#include "ui/popup_window.h"
|
||||
|
||||
namespace ui {
|
||||
class Button;
|
||||
class View;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
namespace gen {
|
||||
class FontPopup;
|
||||
}
|
||||
|
||||
class FontPopup : public ui::PopupWindow {
|
||||
public:
|
||||
FontPopup();
|
||||
|
||||
void showPopup(const gfx::Rect& bounds);
|
||||
|
||||
const std::string& fontsDir() const {
|
||||
return m_fontsDir;
|
||||
}
|
||||
|
||||
Signal1<void, const std::string&> Load;
|
||||
|
||||
protected:
|
||||
void onChangeFont();
|
||||
void onLoadFont();
|
||||
|
||||
private:
|
||||
gen::FontPopup* m_popup;
|
||||
ui::ListBox m_listBox;
|
||||
std::string m_fontsDir;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
152
src/app/util/freetype_utils.cpp
Normal file
152
src/app/util/freetype_utils.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// 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
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/util/freetype_utils.h"
|
||||
|
||||
#include "base/string.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
#include "freetype/ftglyph.h"
|
||||
#include "ft2build.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace app {
|
||||
|
||||
template<typename Iterator, typename Func>
|
||||
static void for_each_glyph(FT_Face face, 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);
|
||||
|
||||
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,
|
||||
const std::string& text,
|
||||
doc::color_t color)
|
||||
{
|
||||
base::UniquePtr<doc::Image> image(nullptr);
|
||||
FT_Library 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);
|
||||
|
||||
// Set font size
|
||||
FT_Set_Pixel_Sizes(face, fontsize, fontsize);
|
||||
|
||||
// Calculate text size
|
||||
base::utf8_const_iterator begin(text.begin()), end(text.end());
|
||||
gfx::Rect bounds(0, 0, 0, 0);
|
||||
for_each_glyph(
|
||||
face, 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
|
||||
if (!bounds.isEmpty()) {
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h));
|
||||
doc::clear_image(image, 0);
|
||||
|
||||
for_each_glyph(
|
||||
face, begin, end,
|
||||
[&bounds, &image, color](int x, FT_GlyphSlot glyph) {
|
||||
int t, yimg = - bounds.y - glyph->bitmap_top;
|
||||
for (int v=0; v<(int)glyph->bitmap.rows; ++v, ++yimg) {
|
||||
const uint8_t* p = glyph->bitmap.buffer + v*glyph->bitmap.pitch;
|
||||
int ximg = x - bounds.x + glyph->bitmap_left;
|
||||
for (int u=0; u<(int)glyph->bitmap.width; ++u, ++p, ++ximg) {
|
||||
int alpha = *p;
|
||||
doc::put_pixel(
|
||||
image, ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image, ximg, yimg),
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
MUL_UN8(doc::rgba_geta(color), alpha, t)), 255));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("There is no text");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Error loading font face");
|
||||
}
|
||||
|
||||
return (image ? image.release(): nullptr);
|
||||
}
|
||||
|
||||
} // namespace app
|
28
src/app/util/freetype_utils.h
Normal file
28
src/app/util/freetype_utils.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// 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
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_UTIL_FREETYPE_UTILS_H_INCLUDED
|
||||
#define APP_UTIL_FREETYPE_UTILS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/color.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
doc::Image* render_text(const std::string& fontfile, int fontsize,
|
||||
const std::string& text,
|
||||
doc::color_t color);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user