From 85a7c43f831202240202eed3ba9e97fa84a4dc17 Mon Sep 17 00:00:00 2001 From: Duan Yao Date: Sat, 7 Jun 2014 02:01:10 +0800 Subject: [PATCH] Add svg-nodes-limit option to avoid overly complicated svg background. --- .../CairoBackgroundRenderer.cc | 57 +++++++++++++++++-- .../CairoBackgroundRenderer.h | 11 ++-- .../SplashBackgroundRenderer.cc | 47 +++++++++------ .../SplashBackgroundRenderer.h | 7 +-- src/Param.h | 1 + src/pdf2htmlEX.cc | 3 +- 6 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/BackgroundRenderer/CairoBackgroundRenderer.cc b/src/BackgroundRenderer/CairoBackgroundRenderer.cc index 074e4c1..c92703b 100644 --- a/src/BackgroundRenderer/CairoBackgroundRenderer.cc +++ b/src/BackgroundRenderer/CairoBackgroundRenderer.cc @@ -15,12 +15,28 @@ #if ENABLE_SVG #include "CairoBackgroundRenderer.h" +#include "SplashBackgroundRenderer.h" namespace pdf2htmlEX { using std::string; using std::ifstream; +CairoBackgroundRenderer::CairoBackgroundRenderer(HTMLRenderer * html_renderer, const Param & param) + : CairoOutputDev() + , html_renderer(html_renderer) + , param(param) + , surface(nullptr) + , use_bitmap(false) +{ + if (param.svg_nodes_limit > 0) + { + this->bitmap_renderer = new SplashBackgroundRenderer(html_renderer, param); + } + else + this->bitmap_renderer = nullptr; +} + void CairoBackgroundRenderer::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, @@ -46,6 +62,8 @@ void CairoBackgroundRenderer::drawChar(GfxState *state, double x, double y, void CairoBackgroundRenderer::init(PDFDoc * doc) { startDoc(doc); + if (this->bitmap_renderer != nullptr) + this->bitmap_renderer->init(doc); } static GBool annot_cb(Annot *, void * pflag) { @@ -67,13 +85,11 @@ void CairoBackgroundRenderer::render_page(PDFDoc * doc, int pageno) page_height = doc->getPageMediaHeight(pageno); } - { - auto fn = html_renderer->str_fmt("%s/bg%x.svg", (param.embed_image ? param.tmp_dir : param.dest_dir).c_str(), pageno); - if(param.embed_image) - html_renderer->tmp_files.add((char*)fn); + auto fn = html_renderer->str_fmt("%s/bg%x.svg", (param.embed_image ? param.tmp_dir : param.dest_dir).c_str(), pageno); + if(param.embed_image) + html_renderer->tmp_files.add((char*)fn); - surface = cairo_svg_surface_create((char*)fn, page_width * param.h_dpi / DEFAULT_DPI, page_height * param.v_dpi / DEFAULT_DPI); - } + surface = cairo_svg_surface_create((char*)fn, page_width * param.h_dpi / DEFAULT_DPI, page_height * param.v_dpi / DEFAULT_DPI); cairo_svg_surface_restrict_to_version(surface, CAIRO_SVG_VERSION_1_2); cairo_surface_set_fallback_resolution(surface, param.h_dpi, param.v_dpi); @@ -105,10 +121,39 @@ void CairoBackgroundRenderer::render_page(PDFDoc * doc, int pageno) if(status) throw string("Error in cairo: ") + cairo_status_to_string(status); } + + //check node count in the svg file, fall back to bitmap_renderer if necessary. + if (param.svg_nodes_limit > 0) + { + int n = 0; + char c; + ifstream svgfile((char*)fn); + //count of '<' in the file should be an approximation of node count. + while(svgfile >> c) + { + if (c == '<') + ++n; + } + svgfile.close(); + if (n > param.svg_nodes_limit) + { + html_renderer->tmp_files.add((char*)fn); + use_bitmap = true; + bitmap_renderer->render_page(doc, pageno); + } + else + use_bitmap = false; + } } void CairoBackgroundRenderer::embed_image(int pageno) { + if (use_bitmap) + { + bitmap_renderer->embed_image(pageno); + return; + } + auto & f_page = *(html_renderer->f_curpage); f_page << "str_fmt("%s/bg%x.%s", (param.embed_image ? param.tmp_dir : param.dest_dir).c_str(), pageno, param.bg_format.c_str()); + auto fn = html_renderer->str_fmt("%s/bg%x.%s", (param.embed_image ? param.tmp_dir : param.dest_dir).c_str(), pageno, format.c_str()); if(param.embed_image) html_renderer->tmp_files.add((char*)fn); @@ -118,21 +142,21 @@ void SplashBackgroundRenderer::embed_image(int pageno) if(param.embed_image) { - auto path = html_renderer->str_fmt("%s/bg%x.%s", param.tmp_dir.c_str(), pageno, param.bg_format.c_str()); + auto path = html_renderer->str_fmt("%s/bg%x.%s", param.tmp_dir.c_str(), pageno, format.c_str()); ifstream fin((char*)path, ifstream::binary); if(!fin) throw string("Cannot read background image ") + (char*)path; - auto iter = FORMAT_MIME_TYPE_MAP.find(param.bg_format); + auto iter = FORMAT_MIME_TYPE_MAP.find(format); if(iter == FORMAT_MIME_TYPE_MAP.end()) - throw string("Image format not supported: ") + param.bg_format; + throw string("Image format not supported: ") + format; string mime_type = iter->second; f_page << "data:" << mime_type << ";base64," << Base64Stream(fin); } else { - f_page << (char*)html_renderer->str_fmt("bg%x.%s", pageno, param.bg_format.c_str()); + f_page << (char*)html_renderer->str_fmt("bg%x.%s", pageno, format.c_str()); } f_page << "\"/>"; } @@ -153,23 +177,14 @@ void SplashBackgroundRenderer::dump_image(const char * filename, int x1, int y1, // use unique_ptr to auto delete the object upon exception unique_ptr writer; - if(false) { } -#ifdef ENABLE_LIBPNG - else if(param.bg_format == "png") + if(format == "png") { writer = unique_ptr(new PNGWriter); } -#endif -#ifdef ENABLE_LIBJPEG - else if(param.bg_format == "jpg") + else if(format == "jpg") { writer = unique_ptr(new JpegWriter); } -#endif - else - { - throw string("Image format not supported: ") + param.bg_format; - } if(!writer->init(f, width, height, param.h_dpi, param.v_dpi)) throw "Cannot initialize PNGWriter"; diff --git a/src/BackgroundRenderer/SplashBackgroundRenderer.h b/src/BackgroundRenderer/SplashBackgroundRenderer.h index e999a10..55b9a97 100644 --- a/src/BackgroundRenderer/SplashBackgroundRenderer.h +++ b/src/BackgroundRenderer/SplashBackgroundRenderer.h @@ -27,11 +27,7 @@ class SplashBackgroundRenderer : public BackgroundRenderer, SplashOutputDev public: static const SplashColor white; - SplashBackgroundRenderer(HTMLRenderer * html_renderer, const Param & param) - : SplashOutputDev(splashModeRGB8, 4, gFalse, (SplashColorPtr)(&white), gTrue, gTrue) - , html_renderer(html_renderer) - , param(param) - { } + SplashBackgroundRenderer(HTMLRenderer * html_renderer, const Param & param); virtual ~SplashBackgroundRenderer() { } @@ -68,6 +64,7 @@ protected: void dump_image(const char * filename, int x1, int y1, int x2, int y2); HTMLRenderer * html_renderer; const Param & param; + std::string format; }; } // namespace pdf2htmlEX diff --git a/src/Param.h b/src/Param.h index 9d42620..806f837 100644 --- a/src/Param.h +++ b/src/Param.h @@ -63,6 +63,7 @@ struct Param // background image std::string bg_format; + int svg_nodes_limit = 0; // encryption std::string owner_password, user_password; diff --git a/src/pdf2htmlEX.cc b/src/pdf2htmlEX.cc index 23e8d73..0df3d30 100644 --- a/src/pdf2htmlEX.cc +++ b/src/pdf2htmlEX.cc @@ -190,7 +190,8 @@ void parse_options (int argc, char **argv) // background image .add("bg-format", ¶m.bg_format, "png", "specify background image format") - + .add("svg-nodes-limit", ¶m.svg_nodes_limit, 0, "if node count in a svg background image exceeds this limit," + " fall back to bitmap background. 0 or negative means no limit.") // encryption .add("owner-password,o", ¶m.owner_password, "", "owner password (for encrypted files)", true) .add("user-password,u", ¶m.user_password, "", "user password (for encrypted files)", true)