mirror of
https://github.com/pdf2htmlEX/pdf2htmlEX.git
synced 2024-12-22 04:50:09 +00:00
transform matrix manager
This commit is contained in:
parent
6c33d431c6
commit
8e24776124
@ -164,7 +164,6 @@ class HTMLRenderer : public OutputDev
|
||||
void install_base_font(GfxFont * font, GfxFontLoc * font_loc, FontInfo & info);
|
||||
void install_external_font (GfxFont * font, FontInfo & info);
|
||||
|
||||
long long install_transform_matrix(const double * tm);
|
||||
long long install_fill_color(const GfxRGB * rgb);
|
||||
long long install_stroke_color(const GfxRGB * rgb);
|
||||
|
||||
@ -179,7 +178,6 @@ class HTMLRenderer : public OutputDev
|
||||
void export_remote_default_font(long long fn_id);
|
||||
void export_local_font(const FontInfo & info, GfxFont * font, const std::string & original_font_name, const std::string & cssfont);
|
||||
|
||||
void export_transform_matrix(long long tm_id, const double * tm);
|
||||
void export_fill_color(long long color_id, const GfxRGB * rgb);
|
||||
void export_stroke_color(long long color_id, const GfxRGB * rgb);
|
||||
|
||||
@ -277,7 +275,6 @@ class HTMLRenderer : public OutputDev
|
||||
// cur_font_size is as in GfxState,
|
||||
// font_size_manager saves the final font size used in HTML
|
||||
double cur_font_size;
|
||||
FontSizeManager font_size_manager;
|
||||
|
||||
// transform matrix
|
||||
long long cur_ttm_id;
|
||||
@ -292,11 +289,7 @@ class HTMLRenderer : public OutputDev
|
||||
|
||||
// letter spacing
|
||||
bool letter_space_changed;
|
||||
LetterSpaceManager letter_space_manager;
|
||||
|
||||
// word spacing
|
||||
bool word_space_changed;
|
||||
WordSpaceManager word_space_manager;
|
||||
|
||||
// fill color
|
||||
long long cur_fill_color_id;
|
||||
@ -309,22 +302,24 @@ class HTMLRenderer : public OutputDev
|
||||
GfxRGB cur_stroke_color;
|
||||
bool cur_has_stroke;
|
||||
bool stroke_color_changed;
|
||||
|
||||
// rise
|
||||
bool rise_changed;
|
||||
RiseManager rise_manager;
|
||||
|
||||
WhitespaceManager whitespace_manager;
|
||||
HeightManager height_manager;
|
||||
LeftManager left_manager;
|
||||
// managers store values actually used in HTML (i.e. scaled)
|
||||
FontSizeManager font_size_manager;
|
||||
LetterSpaceManager letter_space_manager;
|
||||
WordSpaceManager word_space_manager;
|
||||
RiseManager rise_manager;
|
||||
WhitespaceManager whitespace_manager;
|
||||
HeightManager height_manager;
|
||||
LeftManager left_manager;
|
||||
TransformMatrixManager transform_matrix_manager;
|
||||
|
||||
// optimize for web
|
||||
// we try to render the final font size directly
|
||||
// to reduce the effect of ctm as much as possible
|
||||
|
||||
// draw_text_tm is cur_text_tm scaled by 1/draw_text_scale,
|
||||
// the actual tm used is `real tm in PDF` scaled by 1/draw_text_scale,
|
||||
// so everything redenered should be multiplied by draw_text_scale
|
||||
double draw_text_tm[6];
|
||||
double draw_text_scale;
|
||||
|
||||
// the position of next char, in text coords
|
||||
@ -354,7 +349,6 @@ class HTMLRenderer : public OutputDev
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<long long, FontInfo> font_name_map;
|
||||
std::map<Matrix, long long, Matrix_less> transform_matrix_map;
|
||||
std::unordered_map<GfxRGB, long long, GfxRGB_hash, GfxRGB_equal> fill_color_map, stroke_color_map;
|
||||
|
||||
const Param * param;
|
||||
|
@ -372,7 +372,10 @@ void HTMLRenderer::css_draw_rectangle(double x, double y, double w, double h, co
|
||||
}
|
||||
}
|
||||
|
||||
f_pages.fs << "<div class=\"Cd t" << install_transform_matrix(new_tm) << "\" style=\"";
|
||||
transform_matrix_manager.install(new_tm);
|
||||
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN
|
||||
<< ' ' << CSS::TRANSFORM_MATRIX_CN << transform_matrix_manager.get_id()
|
||||
<< "\" style=\"";
|
||||
|
||||
if(line_color)
|
||||
{
|
||||
|
@ -130,39 +130,6 @@ void HTMLRenderer::export_local_font(const FontInfo & info, GfxFont * font, cons
|
||||
f_css.fs << "}" << endl;
|
||||
}
|
||||
|
||||
|
||||
void HTMLRenderer::export_transform_matrix (long long tm_id, const double * tm)
|
||||
{
|
||||
f_css.fs << ".t" << tm_id << "{";
|
||||
|
||||
// always ignore tm[4] and tm[5] because
|
||||
// we have already shifted the origin
|
||||
|
||||
// TODO: recognize common matices
|
||||
if(tm_equal(tm, ID_MATRIX, 4))
|
||||
{
|
||||
auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"};
|
||||
for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter)
|
||||
f_css.fs << *iter << "transform:none;";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"};
|
||||
for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter)
|
||||
{
|
||||
// PDF use a different coordinate system from Web
|
||||
f_css.fs << *iter << "transform:matrix("
|
||||
<< round(tm[0]) << ','
|
||||
<< round(-tm[1]) << ','
|
||||
<< round(-tm[2]) << ','
|
||||
<< round(tm[3]) << ',';
|
||||
|
||||
f_css.fs << "0,0);";
|
||||
}
|
||||
}
|
||||
f_css.fs << "}" << endl;
|
||||
}
|
||||
|
||||
void HTMLRenderer::export_fill_color (long long color_id, const GfxRGB * rgb)
|
||||
{
|
||||
f_css.fs << ".c" << color_id << "{color:" << *rgb << ";}" << endl;
|
||||
|
@ -212,21 +212,6 @@ void HTMLRenderer::install_external_font(GfxFont * font, FontInfo & info)
|
||||
export_local_font(info, font, fontname, "");
|
||||
}
|
||||
|
||||
long long HTMLRenderer::install_transform_matrix(const double * tm)
|
||||
{
|
||||
Matrix m;
|
||||
memcpy(m.m, tm, sizeof(m.m));
|
||||
|
||||
auto iter = transform_matrix_map.lower_bound(m);
|
||||
if((iter != transform_matrix_map.end()) && (tm_equal(m.m, iter->first.m, 4)))
|
||||
return iter->second;
|
||||
|
||||
long long new_tm_id = transform_matrix_map.size();
|
||||
transform_matrix_map.insert(make_pair(m, new_tm_id));
|
||||
export_transform_matrix(new_tm_id, tm);
|
||||
return new_tm_id;
|
||||
}
|
||||
|
||||
long long HTMLRenderer::install_fill_color(const GfxRGB * rgb)
|
||||
{
|
||||
// transparent
|
||||
|
@ -193,7 +193,7 @@ void HTMLRenderer::processLink(AnnotLink * al)
|
||||
|
||||
if(!dest_str.empty())
|
||||
{
|
||||
f_pages.fs << "<a class=\"" << CSS::LINE_CN << "\" href=\"" << dest_str << "\"";
|
||||
f_pages.fs << "<a class=\"" << CSS::LINK_CN << "\" href=\"" << dest_str << "\"";
|
||||
|
||||
if(!dest_detail_str.empty())
|
||||
f_pages.fs << " data-dest-detail='" << dest_detail_str << "'";
|
||||
@ -201,8 +201,9 @@ void HTMLRenderer::processLink(AnnotLink * al)
|
||||
f_pages.fs << ">";
|
||||
}
|
||||
|
||||
transform_matrix_manager.install(default_ctm);
|
||||
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
||||
<< install_transform_matrix(default_ctm)
|
||||
<< transform_matrix_manager.get_id()
|
||||
<< "\" style=\"";
|
||||
|
||||
double x,y,w,h;
|
||||
|
@ -102,11 +102,10 @@ void HTMLRenderer::reset_state()
|
||||
font_size_manager.reset();
|
||||
|
||||
memcpy(cur_text_tm, ID_MATRIX, sizeof(cur_text_tm));
|
||||
memcpy(draw_text_tm, ID_MATRIX, sizeof(draw_text_tm));
|
||||
cur_ttm_id = install_transform_matrix(draw_text_tm);
|
||||
|
||||
letter_space_manager.reset();
|
||||
word_space_manager .reset();
|
||||
transform_matrix_manager.reset();
|
||||
letter_space_manager .reset();
|
||||
word_space_manager .reset();
|
||||
|
||||
cur_fill_color.r = cur_fill_color.g = cur_fill_color.b = 0;
|
||||
cur_fill_color_id = install_fill_color(&cur_fill_color);
|
||||
@ -269,11 +268,9 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||
{
|
||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||
}
|
||||
if(!(tm_equal(new_draw_text_tm, draw_text_tm, 4)))
|
||||
if(transform_matrix_manager.install(new_draw_text_tm))
|
||||
{
|
||||
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
||||
memcpy(draw_text_tm, new_draw_text_tm, sizeof(draw_text_tm));
|
||||
cur_ttm_id = install_transform_matrix(draw_text_tm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,7 @@ public:
|
||||
|
||||
// usually called at the beginning of a page
|
||||
void reset(void) {
|
||||
value = imp->default_value();
|
||||
_install(value);
|
||||
_install(imp->default_value());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -79,9 +78,8 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
actual_value = new_value;
|
||||
id = value_map.size();
|
||||
value_map.insert(std::make_pair(new_value, id));
|
||||
actual_value = value_map.insert(std::make_pair(new_value, id)).first->first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -94,6 +92,88 @@ protected:
|
||||
std::map<double, long long> value_map;
|
||||
};
|
||||
|
||||
// Be careful about the mixed usage of Matrix and const double *
|
||||
template <class Imp>
|
||||
class StateManager<Matrix, Imp>
|
||||
{
|
||||
public:
|
||||
StateManager()
|
||||
: imp(static_cast<Imp*>(this))
|
||||
{ }
|
||||
|
||||
void reset(void) {
|
||||
_install(imp->default_value());
|
||||
}
|
||||
|
||||
// return if changed
|
||||
bool install(const double * new_value) {
|
||||
// For a transform matrix m
|
||||
// m[4] & m[5] have been taken care of
|
||||
if(tm_equal(new_value, value.m, 4))
|
||||
return false;
|
||||
_install(new_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
long long get_id (void) const { return id; }
|
||||
const Matrix & get_value (void) const { return value; }
|
||||
const Matrix & get_actual_value (void) const { return *actual_value; }
|
||||
|
||||
void dump_css(std::ostream & out) {
|
||||
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
|
||||
{
|
||||
out << "." << imp->get_css_class_name() << iter->second << "{";
|
||||
imp->dump_value(out, iter->first);
|
||||
out << "}" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// return if a new entry has been created
|
||||
bool _install(const double * new_value) {
|
||||
memcpy(value.m, new_value, sizeof(value.m));
|
||||
|
||||
auto iter = value_map.lower_bound(value);
|
||||
if((iter != value_map.end()) && (tm_equal(value.m, iter->first.m, 4)))
|
||||
{
|
||||
actual_value = &(iter->first);
|
||||
id = iter->second;
|
||||
return false;
|
||||
}
|
||||
|
||||
id = value_map.size();
|
||||
actual_value = &(value_map.insert(std::make_pair(value, id)).first->first);
|
||||
return true;
|
||||
}
|
||||
|
||||
Imp * imp;
|
||||
|
||||
long long id;
|
||||
Matrix value;
|
||||
const Matrix * actual_value;
|
||||
|
||||
class Matrix_less
|
||||
{
|
||||
public:
|
||||
bool operator () (const Matrix & m1, const Matrix & m2) const
|
||||
{
|
||||
// Note that we only care about the first 4 elements
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
if(m1.m[i] < m2.m[i] - EPS)
|
||||
return true;
|
||||
if(m1.m[i] > m2.m[i] + EPS)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
std::map<Matrix, long long, Matrix_less> value_map;
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
// Specific state managers
|
||||
|
||||
class FontSizeManager : public StateManager<double, FontSizeManager>
|
||||
{
|
||||
public:
|
||||
@ -154,6 +234,39 @@ public:
|
||||
void dump_value(std::ostream & out, double value) { out << "left:" << round(value) << "px;"; }
|
||||
};
|
||||
|
||||
class TransformMatrixManager : public StateManager<Matrix, TransformMatrixManager>
|
||||
{
|
||||
public:
|
||||
static const char * get_css_class_name (void) { return CSS::TRANSFORM_MATRIX_CN; }
|
||||
const double * default_value(void) { return ID_MATRIX; }
|
||||
void dump_value(std::ostream & out, const Matrix & matrix) {
|
||||
// always ignore tm[4] and tm[5] because
|
||||
// we have already shifted the origin
|
||||
// TODO: recognize common matices
|
||||
const auto & m = matrix.m;
|
||||
if(tm_equal(m, ID_MATRIX, 4))
|
||||
{
|
||||
auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"};
|
||||
for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter)
|
||||
out << *iter << "transform:none;";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"};
|
||||
for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter)
|
||||
{
|
||||
// PDF use a different coordinate system from Web
|
||||
out << *iter << "transform:matrix("
|
||||
<< round(m[0]) << ','
|
||||
<< round(-m[1]) << ','
|
||||
<< round(-m[2]) << ','
|
||||
<< round(m[3]) << ',';
|
||||
out << "0,0);";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pdf2htmlEX
|
||||
|
||||
#endif //STATEMANAGER_H__
|
||||
|
@ -55,23 +55,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class Matrix_less
|
||||
{
|
||||
public:
|
||||
bool operator () (const Matrix & m1, const Matrix & m2) const
|
||||
{
|
||||
// Note that we only care about the first 4 elements
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
if(m1.m[i] < m2.m[i] - EPS)
|
||||
return true;
|
||||
if(m1.m[i] > m2.m[i] + EPS)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace pdf2htmlEX
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user