1
0
mirror of https://github.com/pdf2htmlEX/pdf2htmlEX.git synced 2024-12-22 13:00:08 +00:00

color managers

This commit is contained in:
Lu Wang 2013-02-05 21:56:19 +08:00
parent 225aa23dca
commit 31861e7acb
10 changed files with 235 additions and 207 deletions

View File

@ -125,22 +125,7 @@ span {
}
.a {
}
/* transparent color - Firefox, IE, etc. */
.ct { /*fill*/
color: white;
}
.Ct { /*stroke*/
text-shadow: none;
}
/* transparent color - WebKit */
@media screen and (-webkit-min-device-pixel-ratio:0) {
.ct { /*fill*/
color: transparent;
}
.Ct { /*stroke*/
-webkit-text-stroke: 0px transparent;
}
}
.Cd { /* css drawing */
position:absolute;
transform-origin:0% 100%;

View File

@ -160,9 +160,6 @@ protected:
void install_base_font(GfxFont * font, GfxFontLoc * font_loc, FontInfo & info);
void install_external_font (GfxFont * font, FontInfo & info);
long long install_fill_color(const GfxRGB * rgb);
long long install_stroke_color(const GfxRGB * rgb);
////////////////////////////////////////////////////
// export css styles
////////////////////////////////////////////////////
@ -174,9 +171,6 @@ protected:
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_fill_color(long long color_id, const GfxRGB * rgb);
void export_stroke_color(long long color_id, const GfxRGB * rgb);
// depending on single-html, to embed the content or add a link to it
// "type": specify the file type, usually it's the suffix, in which case this parameter could be ""
// "copy": indicates whether to copy the file into dest_dir, if not embedded
@ -258,9 +252,7 @@ protected:
NLS_DIV // has to open a new <div>
} new_line_state;
// The order is according to the appearance in check_state_change
// any state changed
bool all_changed;
// current position
double cur_tx, cur_ty; // real text position, in text coords
@ -271,40 +263,36 @@ protected:
// as we'll calculate the position of the origin separately
double cur_text_tm[6]; // unscaled
bool text_pos_changed;
bool font_changed;
bool all_changed;
bool ctm_changed;
bool text_mat_changed;
bool hori_scale_changed;
bool letter_space_changed;
bool word_space_changed;
bool rise_changed;
bool font_changed;
bool text_pos_changed;
bool text_mat_changed;
bool fill_color_changed;
bool hori_scale_changed;
bool word_space_changed;
bool letter_space_changed;
bool stroke_color_changed;
// font & size
const FontInfo * cur_font_info;
// fill color
long long cur_fill_color_id;
GfxRGB cur_fill_color;
bool cur_has_fill;
bool fill_color_changed;
// stroke color
long long cur_stroke_color_id;
GfxRGB cur_stroke_color;
bool cur_has_stroke;
bool stroke_color_changed;
// 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;
StrokeColorManager stroke_color_manager;
LetterSpaceManager letter_space_manager;
WhitespaceManager whitespace_manager;
WordSpaceManager word_space_manager;
FillColorManager fill_color_manager;
FontSizeManager font_size_manager;
HeightManager height_manager;
RiseManager rise_manager;
LeftManager left_manager;
////////////////////////////////////////////////
// optimize for web
// we try to render the final font size directly
@ -341,7 +329,6 @@ protected:
////////////////////////////////////////////////////
std::unordered_map<long long, FontInfo> font_name_map;
std::unordered_map<GfxRGB, long long, GfxRGB_hash, GfxRGB_equal> fill_color_map, stroke_color_map;
const Param * param;

View File

@ -193,8 +193,8 @@ void HTMLRenderer::TextLineBuffer::set_state (State & state)
{
state.ids[State::FONT_ID] = renderer->cur_font_info->id;
state.ids[State::FONT_SIZE_ID] = renderer->font_size_manager.get_id();
state.ids[State::FILL_COLOR_ID] = renderer->cur_fill_color_id;
state.ids[State::STROKE_COLOR_ID] = renderer->cur_stroke_color_id;
state.ids[State::FILL_COLOR_ID] = renderer->fill_color_manager.get_id();
state.ids[State::STROKE_COLOR_ID] = renderer->stroke_color_manager.get_id();
state.ids[State::LETTER_SPACE_ID] = renderer->letter_space_manager.get_id();
state.ids[State::WORD_SPACE_ID] = renderer->word_space_manager.get_id();
state.ids[State::RISE_ID] = renderer->rise_manager.get_id();
@ -224,16 +224,11 @@ void HTMLRenderer::TextLineBuffer::State::begin (ostream & out, const State * pr
}
// out should have hex set
out << css_class_names[i];
if (ids[i] == -1)
{
// transparent
// TODO about "t"
out << css_class_names[i] << "t";
}
out << CSS::INVALID_ID;
else
{
out << css_class_names[i] << ids[i];
}
out << ids[i];
}
if(first)

View File

@ -130,29 +130,4 @@ void HTMLRenderer::export_local_font(const FontInfo & info, GfxFont * font, cons
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;
}
void HTMLRenderer::export_stroke_color (long long color_id, const GfxRGB * rgb)
{
// TODO: take the stroke width from the graphics state,
// currently using 0.015em as a good default
// Firefox, IE, etc.
f_css.fs << ".C" << color_id << "{"
<< "text-shadow: "
<< "-0.015em 0 " << *rgb << ","
<< "0 0.015em " << *rgb << ","
<< "0.015em 0 " << *rgb << ","
<< "0 -0.015em " << *rgb << ";"
<< "}" << endl;
// WebKit
f_css.fs << "@media screen and (-webkit-min-device-pixel-ratio:0) {";
f_css.fs << ".C" << color_id << "{-webkit-text-stroke: 0.015em " << *rgb << ";text-shadow: none;}";
f_css.fs << "}" << endl;
}
}
} //namespace pdf2hmlEX

View File

@ -341,14 +341,16 @@ void HTMLRenderer::pre_process(PDFDoc * doc)
void HTMLRenderer::post_process()
{
// dump css
font_size_manager .dump_css(f_css.fs);
letter_space_manager .dump_css(f_css.fs);
word_space_manager .dump_css(f_css.fs);
rise_manager .dump_css(f_css.fs);
whitespace_manager .dump_css(f_css.fs);
height_manager .dump_css(f_css.fs);
left_manager .dump_css(f_css.fs);
transform_matrix_manager.dump_css(f_css.fs);
letter_space_manager .dump_css(f_css.fs);
stroke_color_manager .dump_css(f_css.fs);
word_space_manager .dump_css(f_css.fs);
whitespace_manager .dump_css(f_css.fs);
fill_color_manager .dump_css(f_css.fs);
font_size_manager .dump_css(f_css.fs);
height_manager .dump_css(f_css.fs);
rise_manager .dump_css(f_css.fs);
left_manager .dump_css(f_css.fs);
// close files
f_outline.fs.close();

View File

@ -212,40 +212,4 @@ void HTMLRenderer::install_external_font(GfxFont * font, FontInfo & info)
export_local_font(info, font, fontname, "");
}
long long HTMLRenderer::install_fill_color(const GfxRGB * rgb)
{
// transparent
if (rgb == nullptr) {
return -1;
}
const GfxRGB & c = *rgb;
auto iter = fill_color_map.find(c);
if(iter != fill_color_map.end())
return iter->second;
long long new_color_id = fill_color_map.size();
fill_color_map.insert(make_pair(c, new_color_id));
export_fill_color(new_color_id, rgb);
return new_color_id;
}
long long HTMLRenderer::install_stroke_color(const GfxRGB * rgb)
{
// transparent
if (rgb == nullptr) {
return -1;
}
const GfxRGB & c = *rgb;
auto iter = stroke_color_map.find(c);
if(iter != stroke_color_map.end())
return iter->second;
long long new_color_id = stroke_color_map.size();
stroke_color_map.insert(make_pair(c, new_color_id));
export_stroke_color(new_color_id, rgb);
return new_color_id;
}
} // namespace pdf2htmlEX

View File

@ -99,27 +99,19 @@ void HTMLRenderer::reset_state()
cur_font_info = install_font(nullptr);
cur_font_size = 0.0;
font_size_manager.reset();
memcpy(cur_text_tm, ID_MATRIX, sizeof(cur_text_tm));
transform_matrix_manager.reset();
letter_space_manager .reset();
stroke_color_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);
cur_has_fill = true;
cur_stroke_color.r = cur_stroke_color.g = cur_stroke_color.b = 0;
cur_stroke_color_id = install_stroke_color(&cur_stroke_color);
cur_has_stroke = false;
rise_manager .reset();
whitespace_manager .reset();
fill_color_manager .reset();
font_size_manager .reset();
height_manager .reset();
transform_matrix_manager.reset();
// no need to reset whitespace or left
rise_manager .reset();
left_manager .reset();
cur_tx = cur_ty = 0;
draw_tx = draw_ty = 0;
@ -351,59 +343,51 @@ void HTMLRenderer::check_state_change(GfxState * state)
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
}
// color
if(all_changed || fill_color_changed || stroke_color_changed)
// fill color
if(all_changed || fill_color_changed)
{
// * PDF Spec. Table 106 Text rendering modes
static const char FILL[8] = { true, false, true, false, true, false, true, false };
int idx = state->getRender();
assert((idx >= 0) && (idx < 8));
bool changed = true;
if(FILL[idx])
{
GfxRGB new_color;
state->getFillRGB(&new_color);
changed = fill_color_manager.install(new_color);
}
else
{
changed = fill_color_manager.install_transparent();
}
if(changed)
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
}
// stroke color
if(all_changed || stroke_color_changed)
{
// * PDF Spec. Table 106 Text rendering modes
static const char STROKE[8] = { false, true, true, false, false, true, true, false };
int idx = state->getRender();
assert((idx >= 0) && (idx < 8));
bool is_filled = FILL[idx];
bool is_stroked = STROKE[idx];
// fill
if(is_filled)
{
GfxRGB new_color;
state->getFillRGB(&new_color);
if(!cur_has_fill
|| (!GfxRGB_equal()(new_color, cur_fill_color))
)
{
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
cur_fill_color = new_color;
cur_fill_color_id = install_fill_color(&new_color);
}
}
else
{
cur_fill_color_id = install_fill_color(nullptr);
}
cur_has_fill = is_filled;
bool changed = true;
// stroke
if(is_stroked)
if(STROKE[idx])
{
GfxRGB new_color;
state->getStrokeRGB(&new_color);
if(!cur_has_stroke
|| (!GfxRGB_equal()(new_color, cur_stroke_color))
)
{
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
cur_stroke_color = new_color;
cur_stroke_color_id = install_stroke_color(&new_color);
}
changed = stroke_color_manager.install(new_color);
}
else
{
cur_stroke_color_id = install_stroke_color(nullptr);
changed = stroke_color_manager.install_transparent();
}
cur_has_stroke = is_stroked;
if(changed)
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
}
// rise

View File

@ -15,6 +15,17 @@
namespace pdf2htmlEX {
namespace CSS {
// usually the class name is XXX_CN or XXX_CN<hex id>
// sometimes we need a special one, e.g. transparent color, where the id is -1
const char * const INVALID_ID = "_";
// work around strings
// TODOsince we have this string, should this file be named as general "css.h" ?
const char * const WEBKIT_ONLY = "@media screen and (-webkit-min-device-pixel-ratio:0)";
// TODO: better names, remove collission (i.e LINE_CN vs LETTER_SPACE_CN)
const char * const LINE_CN = "l";
const char * const TRANSFORM_MATRIX_CN = "t";

View File

@ -11,6 +11,7 @@
#include <iostream>
#include <map>
#include <unordered_map>
#include "util/math.h"
#include "util/CSSClassNames.h"
@ -117,7 +118,6 @@ public:
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)
@ -136,13 +136,12 @@ protected:
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);
value_map.insert(std::make_pair(value, id));
return true;
}
@ -150,7 +149,6 @@ protected:
long long id;
Matrix value;
const Matrix * actual_value;
class Matrix_less
{
@ -171,6 +169,104 @@ protected:
std::map<Matrix, long long, Matrix_less> value_map;
};
template <class Imp>
class StateManager<GfxRGB, Imp>
{
public:
StateManager()
: imp(static_cast<Imp*>(this))
{ }
void reset(void) {
is_transparent = true;
id = -1;
}
bool install(const GfxRGB & new_value) {
if((!is_transparent) && gfxrgb_equal_obj(new_value, value))
return false;
_install(new_value);
return true;
}
bool install_transparent (void) {
if(is_transparent)
return false;
_install_transparent();
return true;
}
long long get_id (void) const { return id; }
const GfxRGB & get_value (void) const { return value; }
bool get_is_transparent (void) const { return is_transparent; }
void dump_css(std::ostream & out) {
out << "." << imp->get_css_class_name() << CSS::INVALID_ID << "{";
imp->dump_transparent(out);
out << "}" << std::endl;
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:
bool _install(const GfxRGB & new_value) {
is_transparent = false;
value = new_value;
auto iter = value_map.find(new_value);
if(iter != value_map.end())
{
id = iter->second;
return false;
}
id = value_map.size();
value_map.insert(std::make_pair(value, id));
return true;
}
bool _install_transparent(void) {
is_transparent = true;
id = -1;
return false;
}
Imp * imp;
long long id;
GfxRGB value;
bool is_transparent;
class GfxRGB_hash
{
public:
size_t operator () (const GfxRGB & rgb) const
{
return ( (((size_t)colToByte(rgb.r)) << 16)
| (((size_t)colToByte(rgb.g)) << 8)
| ((size_t)colToByte(rgb.b))
);
}
};
class GfxRGB_equal
{
public:
bool operator ()(const GfxRGB & rgb1, const GfxRGB & rgb2) const
{
return ((rgb1.r == rgb2.r) && (rgb1.g == rgb2.g) && (rgb1.b == rgb2.b));
}
};
GfxRGB_equal gfxrgb_equal_obj;
std::unordered_map<GfxRGB, long long, GfxRGB_hash, GfxRGB_equal> value_map;
};
/////////////////////////////////////
// Specific state managers
@ -267,6 +363,57 @@ public:
}
};
class FillColorManager : public StateManager<GfxRGB, FillColorManager>
{
public:
static const char * get_css_class_name (void) { return CSS::FILL_COLOR_CN; }
/* override base's method, as we need some workaround in CSS */
void dump_css(std::ostream & out) {
// normal CSS
out << "." << get_css_class_name() << CSS::INVALID_ID << "{color:white;}" << std::endl;
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
{
out << "." << get_css_class_name() << iter->second
<< "{color:" << iter->first << ";}" << std::endl;
}
// webkit
out << CSS::WEBKIT_ONLY << "{" << std::endl;
out << "." << get_css_class_name() << CSS::INVALID_ID << "{color:transparent;}" << std::endl;
out << "}" << std::endl;
}
};
class StrokeColorManager : public StateManager<GfxRGB, StrokeColorManager>
{
public:
static const char * get_css_class_name (void) { return CSS::STROKE_COLOR_CN; }
/* override base's method, as we need some workaround in CSS */
void dump_css(std::ostream & out) {
// normal CSS
out << "." << get_css_class_name() << CSS::INVALID_ID << "{text-shadow:none;}" << std::endl;
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
{
// TODO: take the stroke width from the graphics state,
// currently using 0.015em as a good default
out << "." << get_css_class_name() << iter->second << "{text-shadow:"
<< "-0.015em 0 " << iter->first << ","
<< "0 0.015em " << iter->first << ","
<< "0.015em 0 " << iter->first << ","
<< "0 -0.015em " << iter->first << ";"
<< "}" << std::endl;
}
// webkit
out << CSS::WEBKIT_ONLY << "{" << std::endl;
out << "." << get_css_class_name() << CSS::INVALID_ID << "{-webkit-text-stroke:0px transparent;}" << std::endl;
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
{
out << "." << get_css_class_name() << iter->second
<< "{-webkit-text-stroke:0.015em " << iter->first << ";text-shadow:none;}" << std::endl;
}
out << "}" << std::endl;
}
};
} // namespace pdf2htmlEX
#endif //STATEMANAGER_H__

View File

@ -34,28 +34,6 @@ void css_fix_rectangle_border_width(double x1, double y1, double x2, double y2,
std::ostream & operator << (std::ostream & out, const GfxRGB & rgb);
class GfxRGB_hash
{
public:
size_t operator () (const GfxRGB & rgb) const
{
return ( (((size_t)colToByte(rgb.r)) << 16)
| (((size_t)colToByte(rgb.g)) << 8)
| ((size_t)colToByte(rgb.b))
);
}
};
class GfxRGB_equal
{
public:
bool operator ()(const GfxRGB & rgb1, const GfxRGB & rgb2) const
{
return ((rgb1.r == rgb2.r) && (rgb1.g == rgb2.g) && (rgb1.b == rgb2.b));
}
};
} // namespace pdf2htmlEX
#endif //UTIL_H__