mirror of
https://github.com/pdf2htmlEX/pdf2htmlEX.git
synced 2024-12-22 13:00:08 +00:00
Merge branch 'type3'
This commit is contained in:
commit
ea4c6f4f90
@ -3,6 +3,7 @@ Developing v0.10
|
|||||||
* Background image optimization
|
* Background image optimization
|
||||||
* Support output background image in JPEG (--bg-format jpg)
|
* Support output background image in JPEG (--bg-format jpg)
|
||||||
* [Experimental] Support output background image in SVG (--bg-format svg)
|
* [Experimental] Support output background image in SVG (--bg-format svg)
|
||||||
|
* [Experimental] Support Type 3 fonts
|
||||||
* New options
|
* New options
|
||||||
--bg-format
|
--bg-format
|
||||||
--font-format (same as --font-sufix, but without the leading dot)
|
--font-format (same as --font-sufix, but without the leading dot)
|
||||||
|
@ -184,6 +184,13 @@ Clear the fstype bits in TTF/OTF fonts.
|
|||||||
|
|
||||||
Turn this on if Internet Explorer complains about 'Permission must be Installable' AND you have permission to do so.
|
Turn this on if Internet Explorer complains about 'Permission must be Installable' AND you have permission to do so.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B --process-type3 <0|1> (Default: 0)
|
||||||
|
If turned on, pdf2htmlEX will try to convert Type 3 fonts such that text can be rendered natively in HTML.
|
||||||
|
Otherwise all text with Type 3 fonts will be rendered as image.
|
||||||
|
|
||||||
|
This feature is highly experimental.
|
||||||
|
|
||||||
.SS Text
|
.SS Text
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
@ -166,8 +166,8 @@ protected:
|
|||||||
* local font: to be substituted with a local (client side) font
|
* local font: to be substituted with a local (client side) font
|
||||||
*/
|
*/
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
std::string dump_embedded_font(GfxFont * font, long long fn_id);
|
std::string dump_embedded_font(GfxFont * font, FontInfo & info);
|
||||||
std::string dump_type3_font(GfxFont * font, long long fn_id);
|
std::string dump_type3_font(GfxFont * font, FontInfo & info);
|
||||||
void embed_font(const std::string & filepath, GfxFont * font, FontInfo & info, bool get_metric_only = false);
|
void embed_font(const std::string & filepath, GfxFont * font, FontInfo & info, bool get_metric_only = false);
|
||||||
const FontInfo * install_font(GfxFont * font);
|
const FontInfo * install_font(GfxFont * font);
|
||||||
void install_embedded_font(GfxFont * font, FontInfo & info);
|
void install_embedded_font(GfxFont * font, FontInfo & info);
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
#include <cairo-ft.h>
|
#include <cairo-ft.h>
|
||||||
#include <cairo-svg.h>
|
#include <cairo-svg.h>
|
||||||
#include "BackgroundRenderer/CairoOutputDev/CairoFontEngine.h"
|
#include "BackgroundRenderer/CairoOutputDev/CairoFontEngine.h"
|
||||||
|
#include "BackgroundRenderer/CairoOutputDev/CairoOutputDev.h"
|
||||||
|
#include <Gfx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace pdf2htmlEX {
|
namespace pdf2htmlEX {
|
||||||
@ -45,16 +47,18 @@ using std::unordered_set;
|
|||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
string HTMLRenderer::dump_embedded_font (GfxFont * font, long long fn_id)
|
string HTMLRenderer::dump_embedded_font (GfxFont * font, FontInfo & info)
|
||||||
{
|
{
|
||||||
if(font->getType() == fontType3)
|
if(info.is_type3)
|
||||||
return dump_type3_font(font, fn_id);
|
return dump_type3_font(font, info);
|
||||||
|
|
||||||
Object obj, obj1, obj2;
|
Object obj, obj1, obj2;
|
||||||
Object font_obj, font_obj2, fontdesc_obj;
|
Object font_obj, font_obj2, fontdesc_obj;
|
||||||
string suffix;
|
string suffix;
|
||||||
string filepath;
|
string filepath;
|
||||||
|
|
||||||
|
long long fn_id = info.id;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// inspired by mupdf
|
// inspired by mupdf
|
||||||
@ -178,62 +182,164 @@ string HTMLRenderer::dump_embedded_font (GfxFont * font, long long fn_id)
|
|||||||
return filepath;
|
return filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
string HTMLRenderer::dump_type3_font (GfxFont * font, long long fn_id)
|
string HTMLRenderer::dump_type3_font (GfxFont * font, FontInfo & info)
|
||||||
{
|
{
|
||||||
assert(font->getFontType() == fontType3);
|
assert(info.is_type3);
|
||||||
|
|
||||||
#if ENABLE_SVG
|
#if ENABLE_SVG
|
||||||
|
long long fn_id = info.id;
|
||||||
|
|
||||||
FT_Library ft_lib;
|
FT_Library ft_lib;
|
||||||
FT_Init_FreeType(&ft_lib);
|
FT_Init_FreeType(&ft_lib);
|
||||||
CairoFontEngine font_engine(ft_lib);
|
CairoFontEngine font_engine(ft_lib);
|
||||||
auto * cur_font = font_engine.getFont(font, cur_doc, true, xref);
|
auto * cur_font = font_engine.getFont(font, cur_doc, true, xref);
|
||||||
auto used_map = preprocessor.get_code_map(hash_ref(font->getID()));
|
auto used_map = preprocessor.get_code_map(hash_ref(font->getID()));
|
||||||
|
|
||||||
|
//calculate transformed metrics
|
||||||
double * font_bbox = font->getFontBBox();
|
double * font_bbox = font->getFontBBox();
|
||||||
double glyph_width = font_bbox[2] - font_bbox[0];
|
double * font_matrix = font->getFontMatrix();
|
||||||
double glyph_height = font_bbox[3] - font_bbox[1];
|
double transformed_bbox[4];
|
||||||
|
memcpy(transformed_bbox, font_bbox, 4 * sizeof(double));
|
||||||
|
/*
|
||||||
|
// add the origin to the bbox
|
||||||
|
if(transformed_bbox[0] > 0) transformed_bbox[0] = 0;
|
||||||
|
if(transformed_bbox[1] > 0) transformed_bbox[1] = 0;
|
||||||
|
if(transformed_bbox[2] < 0) transformed_bbox[2] = 0;
|
||||||
|
if(transformed_bbox[3] < 0) transformed_bbox[3] = 0;
|
||||||
|
*/
|
||||||
|
tm_transform_bbox(font_matrix, transformed_bbox);
|
||||||
|
double transformed_bbox_width = transformed_bbox[2] - transformed_bbox[0];
|
||||||
|
double transformed_bbox_height = transformed_bbox[3] - transformed_bbox[1];
|
||||||
|
info.font_size_scale = std::max(transformed_bbox_width, transformed_bbox_height);
|
||||||
|
|
||||||
// glyph_width /= 10;
|
// we want the glyphs is rendered in a box of size around GLYPH_DUMP_EM_SIZE x GLYPH_DUMP_EM_SIZE
|
||||||
// glyph_height /= 10;
|
// for rectangles, the longer edge should be GLYPH_DUMP_EM_SIZE
|
||||||
|
const double GLYPH_DUMP_EM_SIZE = 100.0;
|
||||||
|
double scale = GLYPH_DUMP_EM_SIZE / info.font_size_scale;
|
||||||
|
|
||||||
// dumpy each glyph into svg and combine them
|
// we choose ttf as it does not use char names
|
||||||
|
// or actually we don't use char names for ttf (see embed_font)
|
||||||
ffw_new_font();
|
ffw_new_font();
|
||||||
|
// dump each glyph into svg and combine them
|
||||||
for(int code = 0; code < 256; ++code)
|
for(int code = 0; code < 256; ++code)
|
||||||
{
|
{
|
||||||
if(!used_map[code]) continue;
|
if(!used_map[code]) continue;
|
||||||
|
|
||||||
cairo_glyph_t glyph;
|
|
||||||
glyph.index = cur_font->getGlyph(code, nullptr, 0);
|
|
||||||
glyph.x = 0;
|
|
||||||
glyph.y = glyph_height;
|
|
||||||
|
|
||||||
cairo_surface_t * surface = nullptr;
|
cairo_surface_t * surface = nullptr;
|
||||||
|
|
||||||
string glyph_filename = (char*)str_fmt("%s/f%llx-%x.svg", param.tmp_dir.c_str(), fn_id, code);
|
string glyph_filename = (char*)str_fmt("%s/f%llx-%x.svg", param.tmp_dir.c_str(), fn_id, code);
|
||||||
tmp_files.add(glyph_filename);
|
tmp_files.add(glyph_filename);
|
||||||
surface = cairo_svg_surface_create(glyph_filename.c_str(), glyph_height, glyph_width);
|
|
||||||
|
surface = cairo_svg_surface_create(glyph_filename.c_str(), transformed_bbox_width * scale, transformed_bbox_height * scale);
|
||||||
|
|
||||||
cairo_svg_surface_restrict_to_version(surface, CAIRO_SVG_VERSION_1_2);
|
cairo_svg_surface_restrict_to_version(surface, CAIRO_SVG_VERSION_1_2);
|
||||||
cairo_surface_set_fallback_resolution(surface, param.h_dpi, param.v_dpi);
|
cairo_surface_set_fallback_resolution(surface, param.h_dpi, param.v_dpi);
|
||||||
cairo_t * cr = cairo_create(surface);
|
cairo_t * cr = cairo_create(surface);
|
||||||
|
|
||||||
// zoom the image to prevent CairoOutputDev from rounding/increasing thin borders
|
// track the positio of the origin
|
||||||
//cairo_matrix_t matrix;
|
double ox, oy;
|
||||||
/*
|
ox = oy = 0.0;
|
||||||
double * font_matrix = font->getFontMatrix();
|
|
||||||
cairo_matrix_init(&matrix, font_matrix[0], font_matrix[1], font_matrix[2], font_matrix[3], font_matrix[4], font_matrix[5]);
|
|
||||||
cairo_set_font_matrix(cr, &matrix);
|
|
||||||
cairo_matrix_init_identity(&matrix);
|
|
||||||
// cairo_matrix_scale(&matrix, 10, 10);
|
|
||||||
cairo_transform(cr, &matrix);
|
|
||||||
*/
|
|
||||||
|
|
||||||
cairo_set_font_size(cr, 1000);
|
auto glyph_width = ((Gfx8BitFont*)font)->getWidth(code);
|
||||||
|
|
||||||
// cairo_set_source_rgb(cr, 0., 0., 0.);
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
// pain the glyph
|
||||||
cairo_set_font_face(cr, cur_font->getFontFace());
|
cairo_set_font_face(cr, cur_font->getFontFace());
|
||||||
|
|
||||||
|
cairo_matrix_t m1, m2, m3;
|
||||||
|
// set up m1
|
||||||
|
// m1 shift the bottom-left corner of the glyph bbox to the origin
|
||||||
|
// also set font size to scale
|
||||||
|
cairo_matrix_init_translate(&m1, -transformed_bbox[0], transformed_bbox[1]);
|
||||||
|
cairo_matrix_init_scale(&m2, scale, scale);
|
||||||
|
cairo_matrix_multiply(&m1, &m1, &m2);
|
||||||
|
cairo_set_font_matrix(cr, &m1);
|
||||||
|
|
||||||
|
cairo_glyph_t glyph;
|
||||||
|
glyph.index = cur_font->getGlyph(code, nullptr, 0);
|
||||||
|
glyph.x = 0;
|
||||||
|
glyph.y = GLYPH_DUMP_EM_SIZE;
|
||||||
cairo_show_glyphs(cr, &glyph, 1);
|
cairo_show_glyphs(cr, &glyph, 1);
|
||||||
|
|
||||||
|
|
||||||
|
// apply the type 3 font's font matrix before m1
|
||||||
|
// such that we got the mapping from type 3 font space to user space, then we will be able to calculate mapped position for ox,oy and glyph_width
|
||||||
|
cairo_matrix_init(&m2, font_matrix[0], font_matrix[1], font_matrix[2], font_matrix[3], font_matrix[4], font_matrix[5]);
|
||||||
|
cairo_matrix_init_scale(&m3, 1, -1);
|
||||||
|
cairo_matrix_multiply(&m2, &m2, &m3);
|
||||||
|
cairo_matrix_multiply(&m2, &m2, &m1);
|
||||||
|
|
||||||
|
cairo_matrix_transform_point(&m2, &ox, &oy);
|
||||||
|
double dummy = 0;
|
||||||
|
cairo_matrix_transform_distance(&m2, &glyph_width, &dummy);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
// manually draw the char to get the metrics
|
||||||
|
// adapted from _render_type3_glyph of poppler
|
||||||
|
cairo_matrix_t ctm, m, m1;
|
||||||
|
cairo_matrix_init_identity(&ctm);
|
||||||
|
|
||||||
|
// apply font-matrix
|
||||||
|
cairo_matrix_init(&m, font_matrix[0], font_matrix[1], font_matrix[2], font_matrix[3], font_matrix[4], font_matrix[5]);
|
||||||
|
cairo_matrix_multiply(&ctm, &ctm, &m);
|
||||||
|
|
||||||
|
// shift origin
|
||||||
|
cairo_matrix_init_translate(&m1, -transformed_bbox[0], -transformed_bbox[1]);
|
||||||
|
cairo_matrix_multiply(&ctm, &ctm, &m1);
|
||||||
|
|
||||||
|
// make it upside down since the difference between the glyph coordination and cairo coordination
|
||||||
|
cairo_matrix_init_scale(&m1, 1, -1);
|
||||||
|
cairo_matrix_multiply(&ctm, &ctm, &m1);
|
||||||
|
// save m*m1 to m1 for later use
|
||||||
|
cairo_matrix_multiply(&m1, &m, &m1);
|
||||||
|
|
||||||
|
// shift up to the bounding box
|
||||||
|
cairo_matrix_init_translate(&m, 0.0, transformed_bbox_height);
|
||||||
|
cairo_matrix_multiply(&ctm, &ctm, &m);
|
||||||
|
|
||||||
|
// scale up
|
||||||
|
cairo_matrix_init_scale(&m, scale, scale);
|
||||||
|
cairo_matrix_multiply(&ctm, &ctm, &m);
|
||||||
|
|
||||||
|
// set ctm
|
||||||
|
cairo_set_matrix(cr, &ctm);
|
||||||
|
|
||||||
|
// calculate the position of origin
|
||||||
|
cairo_matrix_transform_point(&ctm, &ox, &oy);
|
||||||
|
oy -= transformed_bbox_height * scale;
|
||||||
|
// calculate glyph width
|
||||||
|
double dummy = 0;
|
||||||
|
cairo_matrix_transform_distance(&ctm, &glyph_width, &dummy);
|
||||||
|
|
||||||
|
// draw the glyph
|
||||||
|
auto output_dev = new CairoOutputDev();
|
||||||
|
output_dev->setCairo(cr);
|
||||||
|
output_dev->setPrinting(true);
|
||||||
|
|
||||||
|
PDFRectangle box;
|
||||||
|
box.x1 = font_bbox[0];
|
||||||
|
box.y1 = font_bbox[1];
|
||||||
|
box.x2 = font_bbox[2];
|
||||||
|
box.y2 = font_bbox[3];
|
||||||
|
auto gfx = new Gfx(cur_doc, output_dev,
|
||||||
|
((Gfx8BitFont*)font)->getResources(),
|
||||||
|
&box, nullptr);
|
||||||
|
output_dev->startDoc(cur_doc, &font_engine);
|
||||||
|
output_dev->startPage(1, gfx->getState(), gfx->getXRef());
|
||||||
|
output_dev->setInType3Char(gTrue);
|
||||||
|
auto char_procs = ((Gfx8BitFont*)font)->getCharProcs();
|
||||||
|
Object char_proc_obj;
|
||||||
|
auto glyph_index = cur_font->getGlyph(code, nullptr, 0);
|
||||||
|
gfx->display(char_procs->getVal(glyph_index, &char_proc_obj));
|
||||||
|
|
||||||
|
char_proc_obj.free();
|
||||||
|
delete gfx;
|
||||||
|
delete output_dev;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
auto status = cairo_status(cr);
|
auto status = cairo_status(cr);
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
@ -249,11 +355,9 @@ string HTMLRenderer::dump_type3_font (GfxFont * font, long long fn_id)
|
|||||||
throw string("Error in cairo: ") + cairo_status_to_string(status);
|
throw string("Error in cairo: ") + cairo_status_to_string(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ffw_import_svg_glyph(code, glyph_filename.c_str());
|
ffw_import_svg_glyph(code, glyph_filename.c_str(), ox / GLYPH_DUMP_EM_SIZE, -oy / GLYPH_DUMP_EM_SIZE, glyph_width / GLYPH_DUMP_EM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we choose ttf as it does not use char names
|
|
||||||
// or actually we don't use char names for ttf (see embed_font)
|
|
||||||
string font_filename = (char*)str_fmt("%s/f%llx.ttf", param.tmp_dir.c_str(), fn_id);
|
string font_filename = (char*)str_fmt("%s/f%llx.ttf", param.tmp_dir.c_str(), fn_id);
|
||||||
tmp_files.add(font_filename);
|
tmp_files.add(font_filename);
|
||||||
ffw_save(font_filename.c_str());
|
ffw_save(font_filename.c_str());
|
||||||
@ -321,7 +425,8 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
|||||||
|
|
||||||
if(get_metric_only)
|
if(get_metric_only)
|
||||||
{
|
{
|
||||||
ffw_metric(&info.ascent, &info.descent);
|
ffw_fix_metric();
|
||||||
|
ffw_get_metric(&info.ascent, &info.descent);
|
||||||
ffw_close();
|
ffw_close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -568,6 +673,8 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
|||||||
cur_width = font_cid->getWidth(buf, 2) ;
|
cur_width = font_cid->getWidth(buf, 2) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur_width /= info.font_size_scale;
|
||||||
|
|
||||||
if(u == ' ')
|
if(u == ' ')
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -611,6 +718,8 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
|||||||
char buf[2] = {0, ' '};
|
char buf[2] = {0, ' '};
|
||||||
info.space_width = font_cid->getWidth(buf, 2);
|
info.space_width = font_cid->getWidth(buf, 2);
|
||||||
}
|
}
|
||||||
|
info.space_width /= info.font_size_scale;
|
||||||
|
|
||||||
/* See comments above */
|
/* See comments above */
|
||||||
if(equal(info.space_width,0))
|
if(equal(info.space_width,0))
|
||||||
info.space_width = 0.001;
|
info.space_width = 0.001;
|
||||||
@ -692,7 +801,8 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
|||||||
tmp_files.add(fn);
|
tmp_files.add(fn);
|
||||||
|
|
||||||
ffw_load_font(cur_tmp_fn.c_str());
|
ffw_load_font(cur_tmp_fn.c_str());
|
||||||
ffw_metric(&info.ascent, &info.descent);
|
ffw_fix_metric();
|
||||||
|
ffw_get_metric(&info.ascent, &info.descent);
|
||||||
if(param.override_fstype)
|
if(param.override_fstype)
|
||||||
ffw_override_fstype();
|
ffw_override_fstype();
|
||||||
ffw_save(fn.c_str());
|
ffw_save(fn.c_str());
|
||||||
@ -718,6 +828,7 @@ const FontInfo * HTMLRenderer::install_font(GfxFont * font)
|
|||||||
FontInfo & new_font_info = cur_info_iter->second;
|
FontInfo & new_font_info = cur_info_iter->second;
|
||||||
new_font_info.id = new_fn_id;
|
new_font_info.id = new_fn_id;
|
||||||
new_font_info.use_tounicode = true;
|
new_font_info.use_tounicode = true;
|
||||||
|
new_font_info.font_size_scale = 1.0;
|
||||||
|
|
||||||
if(font == nullptr)
|
if(font == nullptr)
|
||||||
{
|
{
|
||||||
@ -802,7 +913,7 @@ const FontInfo * HTMLRenderer::install_font(GfxFont * font)
|
|||||||
|
|
||||||
void HTMLRenderer::install_embedded_font(GfxFont * font, FontInfo & info)
|
void HTMLRenderer::install_embedded_font(GfxFont * font, FontInfo & info)
|
||||||
{
|
{
|
||||||
auto path = dump_embedded_font(font, info.id);
|
auto path = dump_embedded_font(font, info);
|
||||||
|
|
||||||
if(path != "")
|
if(path != "")
|
||||||
{
|
{
|
||||||
|
@ -206,7 +206,6 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
|||||||
{
|
{
|
||||||
// The width of the type 3 font text, if shown, is likely to be wrong
|
// The width of the type 3 font text, if shown, is likely to be wrong
|
||||||
// So we will create separate (absolute positioned) blocks for them, such that it won't affect other text
|
// So we will create separate (absolute positioned) blocks for them, such that it won't affect other text
|
||||||
// TODO: consider the font matrix and estimate the metrics
|
|
||||||
if((new_font_info->is_type3 || cur_text_state.font_info->is_type3) && (!param.process_type3))
|
if((new_font_info->is_type3 || cur_text_state.font_info->is_type3) && (!param.process_type3))
|
||||||
{
|
{
|
||||||
set_line_state(new_line_state, NLS_NEWLINE);
|
set_line_state(new_line_state, NLS_NEWLINE);
|
||||||
@ -218,6 +217,12 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
|||||||
cur_text_state.font_info = new_font_info;
|
cur_text_state.font_info = new_font_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For Type 3 fonts, we need to take type3_font_size_scale into consideration
|
||||||
|
*/
|
||||||
|
if((new_font_info->is_type3 || cur_text_state.font_info->is_type3) && param.process_type3)
|
||||||
|
need_rescale_font = true;
|
||||||
|
|
||||||
double new_font_size = state->getFontSize();
|
double new_font_size = state->getFontSize();
|
||||||
if(!equal(cur_font_size, new_font_size))
|
if(!equal(cur_font_size, new_font_size))
|
||||||
{
|
{
|
||||||
@ -268,6 +273,7 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
|||||||
double new_draw_text_scale = 1.0/text_scale_factor2 * hypot(new_draw_text_tm[2], new_draw_text_tm[3]);
|
double new_draw_text_scale = 1.0/text_scale_factor2 * hypot(new_draw_text_tm[2], new_draw_text_tm[3]);
|
||||||
|
|
||||||
double new_draw_font_size = cur_font_size;
|
double new_draw_font_size = cur_font_size;
|
||||||
|
|
||||||
if(is_positive(new_draw_text_scale))
|
if(is_positive(new_draw_text_scale))
|
||||||
{
|
{
|
||||||
// scale both font size and matrix
|
// scale both font size and matrix
|
||||||
|
@ -17,6 +17,20 @@ struct FontInfo
|
|||||||
double space_width;
|
double space_width;
|
||||||
double ascent, descent;
|
double ascent, descent;
|
||||||
bool is_type3;
|
bool is_type3;
|
||||||
|
/*
|
||||||
|
* As Type 3 fonts have a font matrix
|
||||||
|
* a glyph of 1pt can be very large or very small
|
||||||
|
* however it might not be true for other font formats such as ttf
|
||||||
|
*
|
||||||
|
* Therefore when we save a Type 3 font into ttf,
|
||||||
|
* we have to scale the font to about 1,
|
||||||
|
* then apply the scaling when using the font
|
||||||
|
*
|
||||||
|
* The scaling factor is stored as font_size_scale
|
||||||
|
*
|
||||||
|
* The value is 1 for other fonts
|
||||||
|
*/
|
||||||
|
double font_size_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HTMLTextState
|
struct HTMLTextState
|
||||||
|
@ -60,7 +60,10 @@ void HTMLTextLine::append_state(const HTMLTextState & text_state)
|
|||||||
states.back().hash_umask = 0;
|
states.back().hash_umask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
(HTMLTextState&)(states.back()) = text_state;
|
HTMLTextState & last_state = states.back();
|
||||||
|
last_state = text_state;
|
||||||
|
//apply font scale
|
||||||
|
last_state.font_size *= last_state.font_info->font_size_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLTextLine::dump_text(ostream & out)
|
void HTMLTextLine::dump_text(ostream & out)
|
||||||
@ -251,7 +254,8 @@ void HTMLTextLine::prepare(void)
|
|||||||
// note that vertical_align cannot be calculated here
|
// note that vertical_align cannot be calculated here
|
||||||
for(auto iter = states.begin(); iter != states.end(); ++iter)
|
for(auto iter = states.begin(); iter != states.end(); ++iter)
|
||||||
{
|
{
|
||||||
iter->ids[State::FONT_ID] = iter->font_info->id;
|
auto font_info = iter->font_info;
|
||||||
|
iter->ids[State::FONT_ID] = font_info->id;
|
||||||
iter->ids[State::FONT_SIZE_ID] = all_manager.font_size.install(iter->font_size);
|
iter->ids[State::FONT_SIZE_ID] = all_manager.font_size.install(iter->font_size);
|
||||||
iter->ids[State::FILL_COLOR_ID] = all_manager.fill_color.install(iter->fill_color);
|
iter->ids[State::FILL_COLOR_ID] = all_manager.fill_color.install(iter->fill_color);
|
||||||
iter->ids[State::STROKE_COLOR_ID] = all_manager.stroke_color.install(iter->stroke_color);
|
iter->ids[State::STROKE_COLOR_ID] = all_manager.stroke_color.install(iter->stroke_color);
|
||||||
@ -260,10 +264,10 @@ void HTMLTextLine::prepare(void)
|
|||||||
iter->hash();
|
iter->hash();
|
||||||
|
|
||||||
accum_vertical_align += iter->vertical_align;
|
accum_vertical_align += iter->vertical_align;
|
||||||
double cur_ascent = accum_vertical_align + iter->font_info->ascent * iter->font_size;
|
double cur_ascent = accum_vertical_align + font_info->ascent * iter->font_size;
|
||||||
if(cur_ascent > ascent)
|
if(cur_ascent > ascent)
|
||||||
ascent = cur_ascent;
|
ascent = cur_ascent;
|
||||||
double cur_descent = accum_vertical_align + iter->font_info->descent * iter->font_size;
|
double cur_descent = accum_vertical_align + font_info->descent * iter->font_size;
|
||||||
if(cur_descent < descent)
|
if(cur_descent < descent)
|
||||||
descent = cur_descent;
|
descent = cur_descent;
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ void parse_options (int argc, char **argv)
|
|||||||
.add("stretch-narrow-glyph", ¶m.stretch_narrow_glyph, 0, "stretch narrow glyphs instead of padding them")
|
.add("stretch-narrow-glyph", ¶m.stretch_narrow_glyph, 0, "stretch narrow glyphs instead of padding them")
|
||||||
.add("squeeze-wide-glyph", ¶m.squeeze_wide_glyph, 1, "shrink wide glyphs instead of truncating them")
|
.add("squeeze-wide-glyph", ¶m.squeeze_wide_glyph, 1, "shrink wide glyphs instead of truncating them")
|
||||||
.add("override-fstype", ¶m.override_fstype, 0, "clear the fstype bits in TTF/OTF fonts")
|
.add("override-fstype", ¶m.override_fstype, 0, "clear the fstype bits in TTF/OTF fonts")
|
||||||
|
.add("process-type3", ¶m.process_type3, 0, "convert Type 3 fonts for web (experimental)")
|
||||||
|
|
||||||
// text
|
// text
|
||||||
.add("heps", ¶m.h_eps, 1.0, "horizontal threshold for merging text, in pixels")
|
.add("heps", ¶m.h_eps, 1.0, "horizontal threshold for merging text, in pixels")
|
||||||
@ -299,8 +300,13 @@ void check_param()
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test
|
#if not ENABLE_SVG
|
||||||
//param.process_type3 = 1;
|
if(param.process_type3)
|
||||||
|
{
|
||||||
|
cerr << "process-type3 is enabled, however SVG support is not built in this version of pdf2htmlEX." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -302,29 +302,20 @@ int ffw_get_em_size(void)
|
|||||||
return cur_fv->sf->ascent + cur_fv->sf->descent;
|
return cur_fv->sf->ascent + cur_fv->sf->descent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffw_metric(double * ascent, double * descent)
|
void ffw_fix_metric()
|
||||||
|
{
|
||||||
|
double ascent, descent;
|
||||||
|
ffw_get_metric(&ascent, &descent);
|
||||||
|
ffw_set_metric(ascent, descent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ffw_get_metric(double * ascent, double * descent)
|
||||||
{
|
{
|
||||||
SplineFont * sf = cur_fv->sf;
|
SplineFont * sf = cur_fv->sf;
|
||||||
struct pfminfo * info = &sf->pfminfo;
|
|
||||||
|
|
||||||
SFDefaultOS2Info(info, sf, sf->fontname);
|
|
||||||
info->pfmset = 1;
|
|
||||||
sf->changed = 1;
|
|
||||||
|
|
||||||
DBounds bb;
|
DBounds bb;
|
||||||
SplineFontFindBounds(sf, &bb);
|
SplineFontFindBounds(sf, &bb);
|
||||||
|
|
||||||
/*
|
|
||||||
printf("bb %lf %lf\n", bb.maxy, bb.miny);
|
|
||||||
printf("_ %d %d\n", sf->ascent, sf->descent);
|
|
||||||
printf("win %d %d\n", info->os2_winascent, info->os2_windescent);
|
|
||||||
printf("%d %d\n", info->winascent_add, info->windescent_add);
|
|
||||||
printf("typo %d %d\n", info->os2_typoascent, info->os2_typodescent);
|
|
||||||
printf("%d %d\n", info->typoascent_add, info->typodescent_add);
|
|
||||||
printf("hhead %d %d\n", info->hhead_ascent, info->hhead_descent);
|
|
||||||
printf("%d %d\n", info->hheadascent_add, info->hheaddescent_add);
|
|
||||||
*/
|
|
||||||
|
|
||||||
int em = sf->ascent + sf->descent;
|
int em = sf->ascent + sf->descent;
|
||||||
|
|
||||||
if (em > 0)
|
if (em > 0)
|
||||||
@ -336,9 +327,20 @@ void ffw_metric(double * ascent, double * descent)
|
|||||||
{
|
{
|
||||||
*ascent = *descent = 0;
|
*ascent = *descent = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int a = floor(bb.maxy + 0.5);
|
void ffw_set_metric(double ascent, double descent)
|
||||||
int d = floor(bb.miny + 0.5);
|
{
|
||||||
|
SplineFont * sf = cur_fv->sf;
|
||||||
|
struct pfminfo * info = &sf->pfminfo;
|
||||||
|
|
||||||
|
SFDefaultOS2Info(info, sf, sf->fontname);
|
||||||
|
info->pfmset = 1;
|
||||||
|
sf->changed = 1;
|
||||||
|
|
||||||
|
int em = sf->ascent + sf->descent;
|
||||||
|
int a = floor(ascent * em + 0.5);
|
||||||
|
int d = floor(descent * em + 0.5);
|
||||||
|
|
||||||
if(a < 0) a = 0;
|
if(a < 0) a = 0;
|
||||||
if(d > 0) d = 0;
|
if(d > 0) d = 0;
|
||||||
@ -354,7 +356,6 @@ void ffw_metric(double * ascent, double * descent)
|
|||||||
* But have to unify them, for different browsers on different platforms
|
* But have to unify them, for different browsers on different platforms
|
||||||
* Things may become easier when there are CSS rules for baseline-based positioning.
|
* Things may become easier when there are CSS rules for baseline-based positioning.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
info->os2_winascent = a;
|
info->os2_winascent = a;
|
||||||
info->os2_typoascent = a;
|
info->os2_typoascent = a;
|
||||||
info->hhead_ascent = a;
|
info->hhead_ascent = a;
|
||||||
@ -424,19 +425,34 @@ void ffw_set_widths(int * width_list, int mapping_len,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffw_import_svg_glyph(int code, const char * filename)
|
void ffw_import_svg_glyph(int code, const char * filename, double ox, double oy, double width)
|
||||||
{
|
{
|
||||||
int enc = SFFindSlot(cur_fv->sf, cur_fv->map, code, "");
|
int enc = SFFindSlot(cur_fv->sf, cur_fv->map, code, "");
|
||||||
if(enc == -1)
|
if(enc == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SFMakeChar(cur_fv->sf, cur_fv->map, enc);
|
SplineChar * sc = SFMakeChar(cur_fv->sf, cur_fv->map, enc);
|
||||||
|
|
||||||
memset(cur_fv->selected, 0, cur_fv->map->enccount);
|
memset(cur_fv->selected, 0, cur_fv->map->enccount);
|
||||||
cur_fv->selected[enc] = 1;
|
cur_fv->selected[enc] = 1;
|
||||||
int ok = FVImportImages(cur_fv, (char*)filename, fv_svg, 0, -1);
|
int ok = FVImportImages(cur_fv, (char*)filename, fv_svg, 0, -1);
|
||||||
if(!ok)
|
if(!ok)
|
||||||
err("Import SVG glyph failed");
|
err("Import SVG glyph failed");
|
||||||
|
|
||||||
|
// correct origin and width
|
||||||
|
{
|
||||||
|
int a = cur_fv->sf->ascent;
|
||||||
|
int d = cur_fv->sf->descent;
|
||||||
|
real transform[6];
|
||||||
|
transform[0] = 1.0;
|
||||||
|
transform[3] = 1.0;
|
||||||
|
transform[1] = transform[2] = 0.0;
|
||||||
|
transform[4] = -ox * (a+d);
|
||||||
|
transform[5] = -oy * (a+d) + d;
|
||||||
|
FVTrans(cur_fv, sc, transform, NULL, fvt_alllayers | fvt_dontmovewidth);
|
||||||
|
|
||||||
|
SCSynchronizeWidth(sc, floor(width * (a+d) + 0.5), sc->width, cur_fv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffw_auto_hint(void)
|
void ffw_auto_hint(void)
|
||||||
|
@ -48,15 +48,23 @@ void ffw_add_empty_char(int32_t unicode, int width);
|
|||||||
////////////////////////
|
////////////////////////
|
||||||
// metrics
|
// metrics
|
||||||
int ffw_get_em_size(void);
|
int ffw_get_em_size(void);
|
||||||
// fix metrics and get them
|
// manipulate ascent and descent
|
||||||
void ffw_metric(double * ascent, double * descent);
|
// asscent is between 0 and 1
|
||||||
|
// descent is between -1 and 0
|
||||||
|
void ffw_fix_metric();
|
||||||
|
// get ascent/descent based on the shape
|
||||||
|
void ffw_get_metric(double * ascent, double * descent);
|
||||||
|
// set corresponding fields
|
||||||
|
void ffw_set_metric(double ascent, double descent);
|
||||||
|
|
||||||
void ffw_set_widths(int * width_list, int mapping_len,
|
void ffw_set_widths(int * width_list, int mapping_len,
|
||||||
int stretch_narrow, int squeeze_wide);
|
int stretch_narrow, int squeeze_wide);
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
// others
|
// others
|
||||||
void ffw_import_svg_glyph(int code, const char * filename);
|
// (ox,oy) is the position of the true origin, fractions related to em_size
|
||||||
|
// also true for glyph_width
|
||||||
|
void ffw_import_svg_glyph(int code, const char * filename, double ox, double oy, double glyph_width);
|
||||||
void ffw_auto_hint(void);
|
void ffw_auto_hint(void);
|
||||||
void ffw_override_fstype(void);
|
void ffw_override_fstype(void);
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
namespace pdf2htmlEX {
|
namespace pdf2htmlEX {
|
||||||
@ -28,5 +30,31 @@ void tm_multiply(double * tm_left, const double * tm_right)
|
|||||||
tm_left[5] += old[1] * tm_right[4] + old[3] * tm_right[5];
|
tm_left[5] += old[1] * tm_right[4] + old[3] * tm_right[5];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tm_transform_bbox(const double * tm, double * bbox)
|
||||||
|
{
|
||||||
|
double & x1 = bbox[0];
|
||||||
|
double & y1 = bbox[1];
|
||||||
|
double & x2 = bbox[2];
|
||||||
|
double & y2 = bbox[3];
|
||||||
|
double _[4][2];
|
||||||
|
_[0][0] = _[1][0] = x1;
|
||||||
|
_[0][1] = _[2][1] = y1;
|
||||||
|
_[2][0] = _[3][0] = x2;
|
||||||
|
_[1][1] = _[3][1] = y2;
|
||||||
|
|
||||||
|
x1 = y1 = std::numeric_limits<double>::max();
|
||||||
|
x2 = y2 = std::numeric_limits<double>::min();
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
auto & x = _[i][0];
|
||||||
|
auto & y = _[i][1];
|
||||||
|
tm_transform(tm, x, y);
|
||||||
|
if(x < x1) x1 = x;
|
||||||
|
if(x > x2) x2 = x;
|
||||||
|
if(y < y1) y1 = y;
|
||||||
|
if(y > y2) y2 = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace pdf2htmlEX
|
} //namespace pdf2htmlEX
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ static inline double hypot(double x, double y) { return std::sqrt(x*x+y*y); }
|
|||||||
|
|
||||||
void tm_transform(const double * tm, double & x, double & y, bool is_delta = false);
|
void tm_transform(const double * tm, double & x, double & y, bool is_delta = false);
|
||||||
void tm_multiply(double * tm_left, const double * tm_right);
|
void tm_multiply(double * tm_left, const double * tm_right);
|
||||||
|
void tm_transform_bbox(const double * tm, double * bbox);
|
||||||
|
|
||||||
} //namespace pdf2htmlEX
|
} //namespace pdf2htmlEX
|
||||||
#endif //MATH_H__
|
#endif //MATH_H__
|
||||||
|
Loading…
Reference in New Issue
Block a user