<ClInclude Include="producer\text\utils\string_metrics.h" />\r
<ClInclude Include="producer\text\utils\texture_atlas.h" />\r
<ClInclude Include="producer\text\utils\texture_font.h" />\r
+ <ClInclude Include="producer\text\utils\text_info.h" />\r
<ClInclude Include="producer\variable.h" />\r
<ClInclude Include="video_channel.h" />\r
<ClInclude Include="consumer\output.h" />\r
</ClInclude>\r
<ClInclude Include="producer\scene\expression_parser.h">\r
<Filter>source\producer\scene</Filter>\r
+ <ClInclude Include="producer\text\utils\text_info.h">\r
+ <Filter>source\producer\text\utils</Filter>\r
</ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
register_producer_factory(&create_text_producer);
}
- std::wstring find_font_file(const std::wstring& font_name)
+ text_info& find_font_file(text_info& info)
{
+ auto& font_name = info.font;
auto it = std::find_if(fonts.begin(), fonts.end(), font_comparer(font_name));
- return (it != fonts.end()) ? (*it).second : L"";
+ info.font_file = (it != fonts.end()) ? (*it).second : L"";
+ return info;
}
}
text::texture_font font_;
public:
- explicit impl(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height, bool standalone)
+ explicit impl(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone)
: frame_factory_(frame_factory)
, constraints_(parent_width, parent_height)
, x_(x), y_(y), parent_width_(parent_width), parent_height_(parent_height)
, standalone_(standalone)
, atlas_(512,512,4)
- , font_(atlas_, text::find_font_file(text_info.font), text_info.size, !standalone)
+ , font_(atlas_, text::find_font_file(text_info), !standalone)
{
//TODO: examine str to determine which unicode_blocks to load
font_.load_glyphs(text::Basic_Latin, text_info.color);
}
};
-text_producer::text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height, bool standalone)
+text_producer::text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone)
: impl_(new impl(frame_factory, x, y, str, text_info, parent_width, parent_height, standalone))
{}
const binding<int>& text_producer::current_bearing_y() const { return impl_->current_bearing_y(); }
const binding<int>& text_producer::current_protrude_under_y() const { return impl_->current_protrude_under_y(); }
-spl::shared_ptr<text_producer> text_producer::create(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height, bool standalone)
+spl::shared_ptr<text_producer> text_producer::create(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone)
{
return spl::make_shared<text_producer>(frame_factory, x, y, str, text_info, parent_width, parent_height, standalone);
}
#include "utils/color.h"
#include "utils/string_metrics.h"
+#include "utils/text_info.h"
namespace caspar { namespace core {
namespace text
{
void init();
-
- struct text_info
- {
- std::wstring font;
- float size;
- color<float> color;
- };
}
class text_producer : public frame_producer_base
{
public:
- text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height, bool standalone);
- static spl::shared_ptr<text_producer> create(const spl::shared_ptr<class frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height, bool standalone = false);
+ text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone);
+ static spl::shared_ptr<text_producer> create(const spl::shared_ptr<class frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone = false);
draw_frame receive_impl() override;
boost::unique_future<std::wstring> call(const std::vector<std::wstring>& param) override;
--- /dev/null
+#pragma once
+
+#include <string>
+#include "color.h"
+
+namespace caspar { namespace core { namespace text {
+
+ struct text_info
+ {
+ std::wstring font;
+ std::wstring font_file;
+
+ float size;
+ color<float> color;
+ int baseline_shift;
+ int tracking;
+ };
+
+}}}
\ No newline at end of file
FT_Face face_;
texture_atlas atlas_;
float size_;
+ float tracking_;
bool normalize_;
std::map<int, glyph_info> glyphs_;
public:
- impl::impl(texture_atlas& atlas, const std::wstring& filename, float size, bool normalize_coordinates) : lib_(nullptr), face_(nullptr), atlas_(atlas), size_(size), normalize_(normalize_coordinates)
+ impl::impl(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : lib_(nullptr), face_(nullptr), atlas_(atlas), size_(info.size), tracking_(info.size*info.tracking/1000.0f), normalize_(normalize_coordinates)
{
try
{
err = FT_Init_FreeType(&lib_);
if(err) throw freetype_exception("Failed to initialize freetype");
- err = FT_New_Face(lib_, u8(filename).c_str(), 0, &face_);
+ err = FT_New_Face(lib_, u8(info.font_file).c_str(), 0, &face_);
if(err) throw freetype_exception("Failed to load font");
- err = FT_Set_Char_Size(face_, (FT_F26Dot6)(size*64), 0, 72, 72);
+ err = FT_Set_Char_Size(face_, static_cast<FT_F26Dot6>(size_*64), 0, 72, 72);
if(err) throw freetype_exception("Failed to set font size");
}
catch(std::exception& ex)
maxHeight = maxBearingY + maxProtrudeUnderY;
pos_x += face_->glyph->advance.x / 64.0f;
+ pos_x += tracking_;
previous = glyph_index;
}
else
}
};
-texture_font::texture_font(texture_atlas& atlas, const std::wstring& filename, float size, bool normalize_coordinates) : impl_(new impl(atlas, filename, size, normalize_coordinates)) {}
+texture_font::texture_font(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : impl_(new impl(atlas, info, normalize_coordinates)) {}
void texture_font::load_glyphs(unicode_block range, const color<float>& col) { impl_->load_glyphs(range, col); }
std::vector<float> texture_font::create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics) { return impl_->create_vertex_stream(str, x, y, parent_width, parent_height, metrics); }
string_metrics texture_font::measure_string(const std::wstring& str) { return impl_->measure_string(str); }
#include <common/memory.h>
#include "string_metrics.h"
+#include "text_info.h"
namespace caspar { namespace core { namespace text {
const texture_font& operator=(const texture_font&);
public:
- texture_font(texture_atlas&, const std::wstring& filename, float size, bool normalize_coordinates);
+ texture_font(texture_atlas&, const text_info&, bool normalize_coordinates);
void load_glyphs(unicode_block block, const color<float>& col);
std::vector<float> create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics);
string_metrics measure_string(const std::wstring& str);
#include "layer.h"
#include "doc.h"
#include "descriptor.h"
+#include <common/log.h>
#include "util\pdf_reader.h"
#include <algorithm>
{
friend class layer;
- impl() : blend_mode_(InvalidBlendMode), link_group_id_(0), opacity_(255), baseClipping_(false), flags_(0), protection_flags_(0), masks_count_(0)
+ impl() : blend_mode_(InvalidBlendMode), link_group_id_(0), opacity_(255), sheet_color_(0), baseClipping_(false), flags_(0), protection_flags_(0), masks_count_(0), text_scale_(1.0f)
{}
private:
blend_mode blend_mode_;
int link_group_id_;
unsigned char opacity_;
+ unsigned short sheet_color_;
bool baseClipping_;
unsigned char flags_;
int protection_flags_;
std::wstring name_;
char masks_count_;
+ float text_scale_;
rect<long> vector_mask_;
layer::layer_mask_info mask_;
case 'shmd': //metadata
read_metadata(stream, doc);
break;
+
+ case 'lclr':
+ sheet_color_ = stream.read_short();
+ break;
case 'lyvr': //layer version
break;
break;
}
}
- catch(PSDFileFormatException&)
+ catch(PSDFileFormatException& ex)
{
//ignore failed chunks silently
+ CASPAR_LOG(warning) << ex.what();
}
stream.set_position(end_of_chunk);
descriptor solid_descriptor;
if(!solid_descriptor.populate(stream))
- throw PSDFileFormatException();
+ throw PSDFileFormatException("Failed to read solid color data");
else
{
solid_color_.red = static_cast<unsigned char>(solid_descriptor.items().get(L"Clr .Rd ", 0.0) + 0.5);
double yy = stream.read_double();
double tx = stream.read_double();
double ty = stream.read_double();
+ if(xx != yy || (xy != 0 && yx != 0))
+ throw PSDFileFormatException("Rotation and non-uniform scaling of dynamic textfields is not supported yet");
+
+ text_scale_ = static_cast<float>(xx);
if(stream.read_short() != 50) //"text version" should be 50
- throw PSDFileFormatException();
+ throw PSDFileFormatException("invalid text version");
if(stream.read_long() != 16) //"descriptor version" should be 16
- throw PSDFileFormatException();
+ throw PSDFileFormatException("Invalid descriptor version while reading text-data");
descriptor text_descriptor;
if(!text_descriptor.populate(stream))
- throw PSDFileFormatException();
+ throw PSDFileFormatException("Failed to read text-info");
else
{
auto text_info = text_descriptor.items().get_optional<std::wstring>(L"EngineData");
}
if(stream.read_short() != 1) //"warp version" should be 1
- throw PSDFileFormatException();
+ throw PSDFileFormatException("invalid warp version");
if(stream.read_long() != 16) //"descriptor version" should be 16
- throw PSDFileFormatException();
+ throw PSDFileFormatException("Invalid descriptor version while reading text warp-data");
descriptor warp_descriptor;
if(!warp_descriptor.populate(stream))
- throw PSDFileFormatException();
+ throw PSDFileFormatException("Failed to read text warp-data");
else
- stream.discard_bytes(4*8); //top, left, right, bottom
+ {
+ double w_top = stream.read_double();
+ double w_left = stream.read_double();
+ double w_right = stream.read_double();
+ double w_bottom = stream.read_double();
+ }
}
//TODO: implement
const std::wstring& layer::name() const { return impl_->name_; }
unsigned char layer::opacity() const { return impl_->opacity_; }
+unsigned short layer::sheet_color() const { return impl_->sheet_color_; }
bool layer::is_visible() { return (impl_->flags_ & 2) == 0; } //the (PSD file-format) documentation is is saying the opposite but what the heck
bool layer::is_position_protected() { return (impl_->protection_flags_& 4) == 4; }
-
+float layer::text_scale() const { return impl_->text_scale_; }
bool layer::is_text() const { return !impl_->text_layer_info_.empty(); }
const boost::property_tree::wptree& layer::text_data() const { return impl_->text_layer_info_; }
const std::wstring& name() const;
unsigned char opacity() const;
+ unsigned short sheet_color() const;
bool is_visible();
bool is_position_protected();
+ float text_scale() const;
bool is_text() const;
const boost::property_tree::wptree& text_data() const;
class PSDFileFormatException : public std::exception
{
public:
+ PSDFileFormatException() : std::exception()
+ {}
+ explicit PSDFileFormatException(const char* msg) : std::exception(msg)
+ {}
+
virtual ~PSDFileFormatException()
{}
virtual const char *what() const
core::text::text_info result;
int font_index = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.Font", 0);
result.size = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.FontSize", 30.0f);
+ //result.leading = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.Leading", 0);
+ result.tracking = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.Tracking", 0);
+ result.baseline_shift = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.BaselineShift", 0);
+ //result.kerning = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.Kerning", 0);
int child_index = 0;
auto color_node = ptree.get_child(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.FillColor.Values");
{
if((*it)->is_visible())
{
- if((*it)->is_text())
+ if((*it)->is_text() && (*it)->sheet_color() == 4)
{
std::wstring str = (*it)->text_data().get(L"EngineDict.Editor.Text", L"");
core::text::text_info text_info(std::move(get_text_info((*it)->text_data())));
+ text_info.size *= (*it)->text_scale();
+
auto text_producer = core::text_producer::create(frame_factory, 0, 0, str, text_info, doc.width(), doc.height());
core::text::string_metrics metrics = text_producer->measure_string(str);
if(layer->is_text())
{
trace << L" <text value='" << (*it)->text_data().get(L"EngineDict.Editor.Text", L"") << L"' />" << std::endl;
- //boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);
- //boost::property_tree::write_xml(trace, (*it)->text_data(), w);
+ boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);
+ boost::property_tree::write_xml(trace, (*it)->text_data(), w);
}
if(layer->has_timeline())
{