From 42452d45b0a75a70b94286b50ce0173626cbf803 Mon Sep 17 00:00:00 2001 From: John Hewson Date: Thu, 31 Jan 2013 22:21:57 +0000 Subject: [PATCH] stroked text --- share/base.css | 16 +++++++ src/HTMLRenderer/HTMLRenderer.h | 18 +++++--- src/HTMLRenderer/TextLineBuffer.cc | 17 +++++-- src/HTMLRenderer/TextLineBuffer.h | 3 +- src/HTMLRenderer/export.cc | 24 +++++++++- src/HTMLRenderer/general.cc | 8 +++- src/HTMLRenderer/install.cc | 35 +++++++++++--- src/HTMLRenderer/state.cc | 74 +++++++++++++++++++++++------- 8 files changed, 157 insertions(+), 38 deletions(-) diff --git a/share/base.css b/share/base.css index d56463c..d96d98b 100644 --- a/share/base.css +++ b/share/base.css @@ -125,6 +125,22 @@ 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%; diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index f94e013..b3cb978 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -53,7 +53,8 @@ * s - font Size * l - Letter spacing * w - Word spacing - * c - Color + * c - Fill Color + * C - Stroke Color * _ - white space * r - Rise * h - Height @@ -235,7 +236,8 @@ class HTMLRenderer : public OutputDev long long install_transform_matrix(const double * tm); long long install_letter_space(double letter_space); long long install_word_space(double word_space); - long long install_color(const GfxRGB * rgb); + long long install_fill_color(const GfxRGB * rgb); + long long install_stroke_color(const GfxRGB * rgb); long long install_whitespace(double ws_width, double & actual_width); long long install_rise(double rise); long long install_height(double height); @@ -256,7 +258,8 @@ class HTMLRenderer : public OutputDev void export_transform_matrix(long long tm_id, const double * tm); void export_letter_space(long long ls_id, double letter_space); void export_word_space(long long ws_id, double word_space); - void export_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_whitespace(long long ws_id, double ws_width); void export_rise(long long rise_id, double rise); void export_height(long long height_id, double height); @@ -376,9 +379,10 @@ class HTMLRenderer : public OutputDev bool word_space_changed; // text color - long long cur_color_id; - GfxRGB cur_color; - bool color_changed; + long long cur_fill_color_id, cur_stroke_color_id; + GfxRGB cur_fill_color, cur_stroke_color; + bool cur_has_fill, cur_has_stroke; + bool fill_color_changed, stroke_color_changed; // rise long long cur_rise_id; @@ -426,7 +430,7 @@ class HTMLRenderer : public OutputDev std::map transform_matrix_map; std::map letter_space_map; std::map word_space_map; - std::unordered_map color_map; + std::unordered_map fill_color_map, stroke_color_map; std::map whitespace_map; std::map rise_map; std::map height_map; diff --git a/src/HTMLRenderer/TextLineBuffer.cc b/src/HTMLRenderer/TextLineBuffer.cc index 7fefea5..e85f088 100644 --- a/src/HTMLRenderer/TextLineBuffer.cc +++ b/src/HTMLRenderer/TextLineBuffer.cc @@ -187,7 +187,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->cur_fs_id; - state.ids[State::COLOR_ID] = renderer->cur_color_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::LETTER_SPACE_ID] = renderer->cur_ls_id; state.ids[State::WORD_SPACE_ID] = renderer->cur_ws_id; state.ids[State::RISE_ID] = renderer->cur_rise_id; @@ -216,8 +217,16 @@ void HTMLRenderer::TextLineBuffer::State::begin (ostream & out, const State * pr out << ' '; } - // out should has set hex - out << format_str[i] << ids[i]; + // out should have hex set + if (ids[i] == -1) + { + // transparent + out << format_str[i] << "t"; + } + else + { + out << format_str[i] << ids[i]; + } } if(first) @@ -262,5 +271,5 @@ int HTMLRenderer::TextLineBuffer::State::diff(const State & s) const return d; } -const char * HTMLRenderer::TextLineBuffer::State::format_str = "fsclwr"; +const char * HTMLRenderer::TextLineBuffer::State::format_str = "fscClwr"; } //namespace pdf2htmlEX diff --git a/src/HTMLRenderer/TextLineBuffer.h b/src/HTMLRenderer/TextLineBuffer.h index 5919a3f..0f3809e 100644 --- a/src/HTMLRenderer/TextLineBuffer.h +++ b/src/HTMLRenderer/TextLineBuffer.h @@ -33,7 +33,8 @@ public: enum { FONT_ID, FONT_SIZE_ID, - COLOR_ID, + FILL_COLOR_ID, + STROKE_COLOR_ID, LETTER_SPACE_ID, WORD_SPACE_ID, RISE_ID, diff --git a/src/HTMLRenderer/export.cc b/src/HTMLRenderer/export.cc index c9e1516..9771ef7 100644 --- a/src/HTMLRenderer/export.cc +++ b/src/HTMLRenderer/export.cc @@ -171,9 +171,29 @@ void HTMLRenderer::export_word_space (long long ws_id, double word_space) f_css.fs << ".w" << ws_id << "{word-spacing:" << round(word_space) << "px;}" << endl; } -void HTMLRenderer::export_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; +} + +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 << "}"; } void HTMLRenderer::export_whitespace (long long ws_id, double ws_width) diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index a3bfae2..51e629c 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -197,8 +197,12 @@ void HTMLRenderer::startPage(int pageNum, GfxState *state, XRef * xref) cur_ls_id = install_letter_space(cur_letter_space); cur_ws_id = install_word_space(cur_word_space); - cur_color.r = cur_color.g = cur_color.b = 0; - cur_color_id = install_color(&cur_color); + cur_fill_color.r = cur_fill_color.g = cur_fill_color.b = 0; + cur_stroke_color.r = cur_stroke_color.g = cur_stroke_color.b = 0; + cur_fill_color_id = install_fill_color(&cur_fill_color); + cur_stroke_color_id = install_stroke_color(&cur_stroke_color); + cur_has_stroke = false; + cur_has_fill = true; cur_rise = 0; cur_rise_id = install_rise(cur_rise); diff --git a/src/HTMLRenderer/install.cc b/src/HTMLRenderer/install.cc index 1ec80ca..0af5fda 100644 --- a/src/HTMLRenderer/install.cc +++ b/src/HTMLRenderer/install.cc @@ -264,16 +264,39 @@ long long HTMLRenderer::install_word_space(double word_space) return new_ws_id; } -long long HTMLRenderer::install_color(const GfxRGB * rgb) +long long HTMLRenderer::install_fill_color(const GfxRGB * rgb) { + // transparent + if (rgb == nullptr) { + return -1; + } + const GfxRGB & c = *rgb; - auto iter = color_map.find(c); - if(iter != color_map.end()) + auto iter = fill_color_map.find(c); + if(iter != fill_color_map.end()) return iter->second; - long long new_color_id = color_map.size(); - color_map.insert(make_pair(c, new_color_id)); - export_color(new_color_id, rgb); + 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; } diff --git a/src/HTMLRenderer/state.cc b/src/HTMLRenderer/state.cc index 1ceb017..f2ae9da 100644 --- a/src/HTMLRenderer/state.cc +++ b/src/HTMLRenderer/state.cc @@ -74,23 +74,24 @@ void HTMLRenderer::updateRender(GfxState * state) { // currently Render is traced for color only // might need something like render_changed later - color_changed = true; + fill_color_changed = true; + stroke_color_changed = true; } void HTMLRenderer::updateFillColorSpace(GfxState * state) { - color_changed = true; + fill_color_changed = true; } void HTMLRenderer::updateStrokeColorSpace(GfxState * state) { - color_changed = true; + stroke_color_changed = true; } void HTMLRenderer::updateFillColor(GfxState * state) { - color_changed = true; + fill_color_changed = true; } void HTMLRenderer::updateStrokeColor(GfxState * state) { - color_changed = true; + stroke_color_changed = true; } void HTMLRenderer::check_state_change(GfxState * state) { @@ -305,25 +306,65 @@ void HTMLRenderer::check_state_change(GfxState * state) } // color - if(all_changed || color_changed) + if(all_changed || fill_color_changed || stroke_color_changed) { - GfxRGB new_color; /* * Render modes 0 2 4 6 fill text (stroke or not) * Render modes 1 5 stroke only * Render modes 3 7 hidden (but ok, we won't even draw text) */ - if(state->getRender() % 2 == 0) - state->getFillRGB(&new_color); - else - state->getStrokeRGB(&new_color); - - if(!((new_color.r == cur_color.r) && (new_color.g == cur_color.g) && (new_color.b == cur_color.b))) + + // PDF Spec. Table 106 – Text rendering modes + bool is_filled, is_stroked; + switch (state->getRender()) { + case 0: is_filled = true; is_stroked = false; break; + case 1: is_filled = false; is_stroked = true; break; + case 2: is_filled = true; is_stroked = true; break; + case 3: is_filled = false; is_stroked = false; break; + case 4: is_filled = true; is_stroked = false; break; + case 5: is_filled = false; is_stroked = true; break; + case 6: is_filled = true; is_stroked = true; break; + case 7: is_filled = false; is_stroked = false; break; + } + + GfxRGB new_color; + + // fill + state->getFillRGB(&new_color); + + if(cur_has_fill != is_filled || + !((new_color.r == cur_fill_color.r) && + (new_color.g == cur_fill_color.g) && + (new_color.b == cur_fill_color.b))) { new_line_state = max(new_line_state, NLS_SPAN); - cur_color = new_color; - cur_color_id = install_color(&new_color); + cur_fill_color = new_color; + cur_fill_color_id = install_fill_color(&new_color); } + + if (!is_filled) { + cur_fill_color_id = install_fill_color(nullptr); + } + + // stroke + state->getStrokeRGB(&new_color); + + if(cur_has_stroke != is_stroked || + !((new_color.r == cur_stroke_color.r) && + (new_color.g == cur_stroke_color.g) && + (new_color.b == cur_stroke_color.b))) + { + new_line_state = max(new_line_state, NLS_SPAN); + cur_stroke_color = new_color; + cur_stroke_color_id = install_stroke_color(&new_color); + } + + if (!is_stroked) { + cur_stroke_color_id = install_stroke_color(nullptr); + } + + cur_has_fill = is_filled; + cur_has_stroke = is_stroked; } // rise @@ -357,7 +398,8 @@ void HTMLRenderer::reset_state_change() letter_space_changed = false; word_space_changed = false; - color_changed = false; + fill_color_changed = false; + stroke_color_changed = false; } void HTMLRenderer::prepare_text_line(GfxState * state) {