1
0
mirror of https://github.com/pdf2htmlEX/pdf2htmlEX.git synced 2024-12-22 04:50:09 +00:00

scale type 3 fonts

This commit is contained in:
Lu Wang 2013-09-19 22:02:12 +08:00
parent 4dad850ff7
commit 8812bb52fb
8 changed files with 171 additions and 33 deletions

View File

@ -41,7 +41,8 @@ public:
// Does this device use beginType3Char/endType3Char? Otherwise, // Does this device use beginType3Char/endType3Char? Otherwise,
// text in Type 3 fonts will be drawn with drawChar/drawString. // text in Type 3 fonts will be drawn with drawChar/drawString.
virtual GBool interpretType3Chars() { return !param.process_type3; } // debug
// virtual GBool interpretType3Chars() { return !param.process_type3; }
#if POPPLER_OLDER_THAN_0_23_0 #if POPPLER_OLDER_THAN_0_23_0
virtual void startPage(int pageNum, GfxState *state); virtual void startPage(int pageNum, GfxState *state);

View File

@ -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);

View File

@ -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,11 +182,13 @@ 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);
@ -190,13 +196,36 @@ string HTMLRenderer::dump_type3_font (GfxFont * font, long long fn_id)
auto used_map = preprocessor.get_code_map(hash_ref(font->getID())); auto used_map = preprocessor.get_code_map(hash_ref(font->getID()));
double * font_bbox = font->getFontBBox(); double * font_bbox = font->getFontBBox();
double glyph_width = font_bbox[2] - font_bbox[0]; // TODO: font matrix may not exists
double glyph_height = font_bbox[3] - font_bbox[1]; double * font_matrix = font->getFontMatrix();
// glyph_width /= 10; //calculate transformations
// glyph_height /= 10; double transformed_bbox[4];
memcpy(transformed_bbox, font_bbox, 4 * sizeof(double));
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];
//debug
std::cerr << "transformed bbox:";
for(int i = 0; i < 4; ++i)
std::cerr << ' ' << transformed_bbox[i];
std::cerr << std::endl;
// we want the glyphs is rendered in a box of size around 100 x 100
// for rectangles, the longer edge should be 100
info.type3_font_size_scale = std::max(transformed_bbox_width, transformed_bbox_height);
// dumpy each glyph into svg and combine them const double GLYPH_DUMP_SIZE = 100.0;
double scale = GLYPH_DUMP_SIZE / info.type3_font_size_scale;
// determine the position of the origin of the glyph
double ox, oy;
ox = oy = 0;
tm_transform(font_matrix, ox, oy);
ox -= transformed_bbox[0];
oy -= transformed_bbox[1];
// dump each glyph into svg and combine them
ffw_new_font(); ffw_new_font();
for(int code = 0; code < 256; ++code) for(int code = 0; code < 256; ++code)
{ {
@ -204,36 +233,86 @@ string HTMLRenderer::dump_type3_font (GfxFont * font, long long fn_id)
cairo_glyph_t glyph; cairo_glyph_t glyph;
glyph.index = cur_font->getGlyph(code, nullptr, 0); glyph.index = cur_font->getGlyph(code, nullptr, 0);
glyph.x = 0; glyph.x = ox;
glyph.y = glyph_height; glyph.y = transformed_bbox_width * scale - oy;
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 //debug
//cairo_matrix_t matrix; std::cerr << "debug " << code << std::endl;
std::cerr << "pdf width " << ((Gfx8BitFont*)font)->getWidth(code) << std::endl;
/* /*
double * font_matrix = font->getFontMatrix(); cairo_set_font_size(cr, scale);
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);
// cairo_set_source_rgb(cr, 0., 0., 0.);
cairo_set_font_face(cr, cur_font->getFontFace()); cairo_set_font_face(cr, cur_font->getFontFace());
cairo_show_glyphs(cr, &glyph, 1); cairo_show_glyphs(cr, &glyph, 1);
*/
// manually draw the char to get the metrics
// adapted from _render_type3_glyph of poppler
{
cairo_matrix_t m1, m2;
cairo_matrix_init_translate(&m1, glyph.x, glyph.y);
cairo_transform(cr, &m1);
cairo_matrix_init_scale(&m1, scale, scale);
cairo_transform(cr, &m1);
cairo_matrix_init(&m1, font_matrix[0], font_matrix[1], font_matrix[2], font_matrix[3], font_matrix[4], font_matrix[5]);
cairo_matrix_init_scale(&m2, 1, -1);
cairo_matrix_multiply(&m1, &m1, &m2);
cairo_transform(cr, &m1);
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;
gfx->display(char_procs->getVal(glyph.index, &char_proc_obj));
double wx, wy;
output_dev->getType3GlyphWidth(&wx, &wy);
cairo_matrix_transform_distance(&m1, &wx, &wy);
std::cerr << "wx " << wx << " wy " << wy << std::endl;
if(output_dev->hasType3GlyphBBox())
{
double *bbox = output_dev->getType3GlyphBBox();
cairo_matrix_transform_point (&m1, &bbox[0], &bbox[1]);
cairo_matrix_transform_point (&m1, &bbox[2], &bbox[3]);
std::cerr << "*bbox";
for(int i = 0; i < 4; ++i)
std::cerr << ' ' << bbox[i];
std::cerr << std::endl;
}
char_proc_obj.free();
delete gfx;
delete output_dev;
}
// cairo_set_source_rgb(cr, 0., 0., 0.);
{ {
auto status = cairo_status(cr); auto status = cairo_status(cr);
cairo_destroy(cr); cairo_destroy(cr);
@ -568,6 +647,9 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
cur_width = font_cid->getWidth(buf, 2) ; cur_width = font_cid->getWidth(buf, 2) ;
} }
if(info.is_type3)
cur_width /= info.type3_font_size_scale;
if(u == ' ') if(u == ' ')
{ {
/* /*
@ -611,6 +693,9 @@ 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);
} }
if(info.is_type3)
info.space_width /= info.type3_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;
@ -802,7 +887,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 != "")
{ {

View File

@ -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,12 @@ 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(cur_text_state.font_info->is_type3 && param.process_type3)
{
new_draw_font_size *= cur_text_state.font_info->type3_font_size_scale;
}
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

View File

@ -17,6 +17,18 @@ 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 type3_font_size_scale
*/
double type3_font_size_scale;
}; };
struct HTMLTextState struct HTMLTextState

View File

@ -300,7 +300,7 @@ void check_param()
} }
//test //test
//param.process_type3 = 1; param.process_type3 = 1;
} }
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@ -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

View File

@ -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__