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_base_font(GfxFont * font, GfxFontLoc * font_loc, FontInfo & info);
|
||||||
void install_external_font (GfxFont * font, 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_fill_color(const GfxRGB * rgb);
|
||||||
long long install_stroke_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_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_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_fill_color(long long color_id, const GfxRGB * rgb);
|
||||||
void export_stroke_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,
|
// cur_font_size is as in GfxState,
|
||||||
// font_size_manager saves the final font size used in HTML
|
// font_size_manager saves the final font size used in HTML
|
||||||
double cur_font_size;
|
double cur_font_size;
|
||||||
FontSizeManager font_size_manager;
|
|
||||||
|
|
||||||
// transform matrix
|
// transform matrix
|
||||||
long long cur_ttm_id;
|
long long cur_ttm_id;
|
||||||
@ -292,11 +289,7 @@ class HTMLRenderer : public OutputDev
|
|||||||
|
|
||||||
// letter spacing
|
// letter spacing
|
||||||
bool letter_space_changed;
|
bool letter_space_changed;
|
||||||
LetterSpaceManager letter_space_manager;
|
|
||||||
|
|
||||||
// word spacing
|
|
||||||
bool word_space_changed;
|
bool word_space_changed;
|
||||||
WordSpaceManager word_space_manager;
|
|
||||||
|
|
||||||
// fill color
|
// fill color
|
||||||
long long cur_fill_color_id;
|
long long cur_fill_color_id;
|
||||||
@ -309,22 +302,24 @@ class HTMLRenderer : public OutputDev
|
|||||||
GfxRGB cur_stroke_color;
|
GfxRGB cur_stroke_color;
|
||||||
bool cur_has_stroke;
|
bool cur_has_stroke;
|
||||||
bool stroke_color_changed;
|
bool stroke_color_changed;
|
||||||
|
|
||||||
// rise
|
|
||||||
bool rise_changed;
|
bool rise_changed;
|
||||||
RiseManager rise_manager;
|
|
||||||
|
|
||||||
WhitespaceManager whitespace_manager;
|
// managers store values actually used in HTML (i.e. scaled)
|
||||||
HeightManager height_manager;
|
FontSizeManager font_size_manager;
|
||||||
LeftManager left_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
|
// optimize for web
|
||||||
// we try to render the final font size directly
|
// we try to render the final font size directly
|
||||||
// to reduce the effect of ctm as much as possible
|
// 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
|
// so everything redenered should be multiplied by draw_text_scale
|
||||||
double draw_text_tm[6];
|
|
||||||
double draw_text_scale;
|
double draw_text_scale;
|
||||||
|
|
||||||
// the position of next char, in text coords
|
// 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::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;
|
std::unordered_map<GfxRGB, long long, GfxRGB_hash, GfxRGB_equal> fill_color_map, stroke_color_map;
|
||||||
|
|
||||||
const Param * param;
|
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)
|
if(line_color)
|
||||||
{
|
{
|
||||||
|
@ -130,39 +130,6 @@ void HTMLRenderer::export_local_font(const FontInfo & info, GfxFont * font, cons
|
|||||||
f_css.fs << "}" << endl;
|
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)
|
void HTMLRenderer::export_fill_color (long long color_id, const GfxRGB * rgb)
|
||||||
{
|
{
|
||||||
f_css.fs << ".c" << color_id << "{color:" << *rgb << ";}" << endl;
|
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, "");
|
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)
|
long long HTMLRenderer::install_fill_color(const GfxRGB * rgb)
|
||||||
{
|
{
|
||||||
// transparent
|
// transparent
|
||||||
|
@ -193,7 +193,7 @@ void HTMLRenderer::processLink(AnnotLink * al)
|
|||||||
|
|
||||||
if(!dest_str.empty())
|
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())
|
if(!dest_detail_str.empty())
|
||||||
f_pages.fs << " data-dest-detail='" << dest_detail_str << "'";
|
f_pages.fs << " data-dest-detail='" << dest_detail_str << "'";
|
||||||
@ -201,8 +201,9 @@ void HTMLRenderer::processLink(AnnotLink * al)
|
|||||||
f_pages.fs << ">";
|
f_pages.fs << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transform_matrix_manager.install(default_ctm);
|
||||||
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
||||||
<< install_transform_matrix(default_ctm)
|
<< transform_matrix_manager.get_id()
|
||||||
<< "\" style=\"";
|
<< "\" style=\"";
|
||||||
|
|
||||||
double x,y,w,h;
|
double x,y,w,h;
|
||||||
|
@ -102,11 +102,10 @@ void HTMLRenderer::reset_state()
|
|||||||
font_size_manager.reset();
|
font_size_manager.reset();
|
||||||
|
|
||||||
memcpy(cur_text_tm, ID_MATRIX, sizeof(cur_text_tm));
|
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();
|
transform_matrix_manager.reset();
|
||||||
word_space_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.r = cur_fill_color.g = cur_fill_color.b = 0;
|
||||||
cur_fill_color_id = install_fill_color(&cur_fill_color);
|
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);
|
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);
|
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
|
// usually called at the beginning of a page
|
||||||
void reset(void) {
|
void reset(void) {
|
||||||
value = imp->default_value();
|
_install(imp->default_value());
|
||||||
_install(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -79,9 +78,8 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
actual_value = new_value;
|
|
||||||
id = value_map.size();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +92,88 @@ protected:
|
|||||||
std::map<double, long long> value_map;
|
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>
|
class FontSizeManager : public StateManager<double, FontSizeManager>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -154,6 +234,39 @@ public:
|
|||||||
void dump_value(std::ostream & out, double value) { out << "left:" << round(value) << "px;"; }
|
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
|
} // namespace pdf2htmlEX
|
||||||
|
|
||||||
#endif //STATEMANAGER_H__
|
#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
|
} // namespace pdf2htmlEX
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user