// pdftohtmlEX.cc // // Copyright (C) 2012,2013 Lu Wang #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Param.h" #include "pdf2htmlEX-config.h" #include "HTMLRenderer/HTMLRenderer.h" #include "util/ArgParser.h" #include "util/path.h" #include "util/ffw.h" using namespace std; using namespace pdf2htmlEX; Param param; ArgParser argparser; void show_usage_and_exit(const char * dummy = nullptr) { cerr << "Usage: pdf2htmlEX [options] []" << endl; argparser.show_usage(cerr); exit(EXIT_FAILURE); } void show_version_and_exit(const char * dummy = nullptr) { cerr << "pdftohtmlEX version " << PDF2HTMLEX_VERSION << endl; cerr << "Copyright 2012,2013 Lu Wang " << endl; cerr << "Libraries: "; cerr << "poppler " << POPPLER_VERSION << ", "; cerr << "libfontforge " << ffw_get_version() << endl; exit(EXIT_SUCCESS); } void parse_options (int argc, char **argv) { argparser // pages .add("first-page,f", ¶m.first_page, 1, "first page to convert") .add("last-page,l", ¶m.last_page, numeric_limits::max(), "last page to convert") // dimensions .add("zoom", ¶m.zoom, 0, "zoom ratio", nullptr, true) .add("fit-width", ¶m.fit_width, 0, "fit width to pixels", nullptr, true) .add("fit-height", ¶m.fit_height, 0, "fit height to pixels", nullptr, true) .add("use-cropbox", ¶m.use_cropbox, 0, "use CropBox instead of MediaBox") .add("hdpi", ¶m.h_dpi, 144.0, "horizontal resolution for graphics in DPI") .add("vdpi", ¶m.v_dpi, 144.0, "vertical resolution for graphics in DPI") // output files .add("single-html", ¶m.single_html, 1, "generate a single HTML file") .add("split-pages", ¶m.split_pages, 0, "split pages into separate files") .add("dest-dir", ¶m.dest_dir, ".", "specify destination directory") .add("css-filename", ¶m.css_filename, "", "filename of the generated css file") .add("outline-filename", ¶m.outline_filename, "", "filename of the generated outline file") // fonts .add("embed-base-font", ¶m.embed_base_font, 0, "embed local match for standard 14 fonts") .add("embed-external-font", ¶m.embed_external_font, 0, "embed local match for external fonts") .add("font-suffix", ¶m.font_suffix, ".ttf", "suffix for embedded font files (.ttf,.otf,.woff,.svg)") .add("font-format", ¶m.font_format, "opentype", "CSS @font-face format for embedded fonts") .add("decompose-ligature", ¶m.decompose_ligature, 0, "decompose ligatures, such as \uFB01 -> fi") .add("remove-unused-glyph", ¶m.remove_unused_glyph, 1, "remove unused glyphs in embedded fonts") .add("auto-hint", ¶m.auto_hint, 0, "use fontforge autohint on fonts without hints") .add("external-hint-tool", ¶m.external_hint_tool, "", "external tool for hinting fonts (overrides --auto-hint)") .add("stretch-narrow-glyph", ¶m.stretch_narrow_glyph, 0, "stretch narrow glyphs instead of padding them") .add("squeeze-wide-glyph", ¶m.squeeze_wide_glyph, 1, "shrink wide glyphs instead of truncating them") // text .add("heps", ¶m.h_eps, 1.0, "horizontal threshold for merging text, in pixels") .add("veps", ¶m.v_eps, 1.0, "vertical threshold for merging text, in pixels") .add("space-threshold", ¶m.space_threshold, (1.0/8), "word break threshold (threshold * em)") .add("font-size-multiplier", ¶m.font_size_multiplier, 4.0, "a value greater than 1 increases the rendering accuracy") .add("space-as-offset", ¶m.space_as_offset, 0, "treat space characters as offsets") .add("tounicode", ¶m.tounicode, 0, "how to handle ToUnicode CMaps (0=auto, 1=force, -1=ignore)") // encryption .add("owner-password,o", ¶m.owner_password, "", "owner password (for encrypted files)", nullptr, true) .add("user-password,u", ¶m.user_password, "", "user password (for encrypted files)", nullptr, true) .add("no-drm", ¶m.no_drm, 0, "override document DRM settings") // misc. .add("clean-tmp", ¶m.clean_tmp, 1, "remove temporary files after conversion") .add("process-nontext", ¶m.process_nontext, 1, "render graphics in addition to text") .add("data-dir", ¶m.data_dir, PDF2HTMLEX_DATA_PATH, "specify data directory") .add("css-draw", ¶m.css_draw, 0, "[experimental and unsupported] CSS drawing") .add("debug", ¶m.debug, 0, "print debugging information") // meta .add("version,v", "print copyright and version info", &show_version_and_exit) .add("help,h", "print usage information", &show_usage_and_exit) .add("", ¶m.input_filename, "", "") .add("", ¶m.output_filename, "", "") ; try { argparser.parse(argc, argv); } catch(const char * s) { // if s == "", getopt_long would have printed the error message if(s && s[0]) { cerr << "Error when parsing the arguments:" << endl; cerr << s << endl; } exit(EXIT_FAILURE); } catch(const std::string & s) { // if s == "", getopt_long would have printed the error message if(s != "") { cerr << "Error when parsing the arguments:" << endl; cerr << s << endl; } exit(EXIT_FAILURE); } } int main(int argc, char **argv) { parse_options(argc, argv); if (param.input_filename == "") { show_usage_and_exit(); } //prepare the directories { char buf[] = "/tmp/pdf2htmlEX-XXXXXX"; auto p = mkdtemp(buf); if(p == nullptr) { cerr << "Cannot create temp directory" << endl; exit(EXIT_FAILURE); } param.tmp_dir = buf; } if(param.debug) cerr << "temporary dir: " << (param.tmp_dir) << endl; try { create_directories(param.dest_dir); } catch (const string & s) { cerr << s << endl; exit(EXIT_FAILURE); } bool finished = false; // read config file globalParams = new GlobalParams(); // open PDF file PDFDoc *doc = nullptr; try { { GooString * ownerPW = (param.owner_password == "") ? (nullptr) : (new GooString(param.owner_password.c_str())); GooString * userPW = (param.user_password == "") ? (nullptr) : (new GooString(param.user_password.c_str())); GooString fileName(param.input_filename.c_str()); doc = PDFDocFactory().createPDFDoc(fileName, ownerPW, userPW); delete userPW; delete ownerPW; } if (!doc->isOk()) { throw "Cannot read the file"; } // check for copy permission if (!doc->okToCopy()) { if (param.no_drm == 0) { throw "Copying of text from this document is not allowed."; } cerr << "Document has copy-protection bit set." << endl; } param.first_page = min(max(param.first_page, 1), doc->getNumPages()); param.last_page = min(max(param.last_page, param.first_page), doc->getNumPages()); if(param.output_filename.empty()) { const string s = get_filename(param.input_filename); if(get_suffix(param.input_filename) == ".pdf") { if(param.split_pages) param.output_filename = s.substr(0, s.size() - 4); else param.output_filename = s.substr(0, s.size() - 4) + ".html"; } else { if(param.split_pages) param.output_filename = s; else param.output_filename = s + ".html"; } } if(param.css_filename.empty()) { const string s = get_filename(param.input_filename); if(get_suffix(param.input_filename) == ".pdf") { param.css_filename = s.substr(0, s.size() - 4) + ".css"; } else { if(!param.split_pages) param.css_filename = s + ".css"; } } if(param.outline_filename.empty()) { const string s = get_filename(param.input_filename); if(get_suffix(param.input_filename) == ".pdf") { param.outline_filename = s.substr(0, s.size() - 4) + ".outline"; } else { if(!param.split_pages) param.outline_filename = s + ".outline"; } } HTMLRenderer * htmlOut = new HTMLRenderer(¶m); htmlOut->process(doc); delete htmlOut; finished = true; } catch (const char * s) { cerr << "Error: " << s << endl; } catch (const string & s) { cerr << "Error: " << s << endl; } // clean up if(doc) delete doc; if(globalParams) delete globalParams; // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); exit(finished ? (EXIT_SUCCESS) : (EXIT_FAILURE)); return 0; }