From 5223541c1f530706b7ceb8aaa025b571d6a51d4c Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Mon, 11 Aug 2014 16:36:35 +0200 Subject: [PATCH 01/10] working but ugly code --- CMakeLists.txt | 1 + src/HTMLRenderer/HTMLRenderer.h | 6 ++ src/HTMLRenderer/form.cc | 103 ++++++++++++++++++++++++++++++++ src/HTMLRenderer/general.cc | 4 ++ src/Param.h | 3 + src/pdf2htmlEX.cc | 3 + 6 files changed, 120 insertions(+) create mode 100644 src/HTMLRenderer/form.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f0aad4..017b43f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,7 @@ set(PDF2HTMLEX_SRC ${PDF2HTMLEX_SRC} src/HTMLRenderer/general.cc src/HTMLRenderer/image.cc src/HTMLRenderer/font.cc + src/HTMLRenderer/form.cc src/HTMLRenderer/link.cc src/HTMLRenderer/outline.cc src/HTMLRenderer/state.cc diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index 80ef25d..6335d6e 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -20,6 +20,10 @@ #include #include +// for form.cc +#include +#include + #include "pdf2htmlEX-config.h" #include "Param.h" @@ -165,6 +169,8 @@ protected: void process_outline(void); void process_outline_items(GooList * items); + void process_form(std::ostream & out); + void set_stream_flags (std::ostream & out); void dump_css(void); diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc new file mode 100644 index 0000000..d2870a9 --- /dev/null +++ b/src/HTMLRenderer/form.cc @@ -0,0 +1,103 @@ +/* + * form.cc + * + * Handling Forms + * + * by Simon Chenard + * 2014.07.25 + */ + +#include +#include +#include + +#include "HTMLRenderer.h" +#include "util/namespace.h" +#include "util/misc.h" + +namespace pdf2htmlEX { + +using std::ostream; +using std::cerr; + +void HTMLRenderer::process_form(ostream & out) +{ + FormPageWidgets * widgets = cur_catalog->getPage(pageNum)->getFormWidgets(); + int num = widgets->getNumWidgets(); + std::ostringstream derp; + + for(int i = 0; i < num; i++) + { + FormWidget * w = widgets->getWidget(i); + double x1, y1, x2, y2; + int width, height, font_size; + + w->getRect(&x1, &y1, &x2, &y2); + x1 = x1 * param.zoom; + x2 = x2 * param.zoom; + y1 = y1 * param.zoom; + y2 = y2 * param.zoom; + + width = x2 - x1; + height = y2 - y1; + + if(w->getType() == formText) + { + font_size = height / 2; + + out << "" << endl; + } + + if(w->getType() == formButton) + { + out << "
X
" << endl; + + } + } + + //output, at the end, the necessary css + if(num > 0) { + //this is usable by the whole document and as such should be in dump_css + out << "" << endl; + + //this is currently page specific + out << "" << endl; + + } +} + +} diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index a7d4e4e..b614a38 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -252,6 +252,10 @@ void HTMLRenderer::endPage() { html_text_page.dump_css(f_css.fs); html_text_page.clear(); + // process form + if(param.include_forms) + process_form(*f_curpage); + // process links before the page is closed cur_doc->processLinks(this, pageNum); diff --git a/src/Param.h b/src/Param.h index b2330ed..9491d42 100644 --- a/src/Param.h +++ b/src/Param.h @@ -62,6 +62,9 @@ struct Param int tounicode; int optimize_text; + // adobe form + int include_forms; + // background image std::string bg_format; int svg_node_count_limit; diff --git a/src/pdf2htmlEX.cc b/src/pdf2htmlEX.cc index 3d4972a..845b5bf 100644 --- a/src/pdf2htmlEX.cc +++ b/src/pdf2htmlEX.cc @@ -189,6 +189,9 @@ void parse_options (int argc, char **argv) .add("optimize-text", ¶m.optimize_text, 0, "try to reduce the number of HTML elements used for text") .add("correct-text-visibility", ¶m.correct_text_visibility, 0, "try to detect texts covered by other graphics and properly arrange them") + // adobe forms + .add("include-forms", ¶m.include_forms, 0, "include text fields and such") + // background image .add("bg-format", ¶m.bg_format, "png", "specify background image format") .add("svg-node-count-limit", ¶m.svg_node_count_limit, -1, "if node count in a svg background image exceeds this limit," From f8404691edb7fb82e3383bb6cc7d6f8779a5a2d7 Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Thu, 14 Aug 2014 10:35:27 +0200 Subject: [PATCH 02/10] cleanup a bit, output css only once --- src/HTMLRenderer/HTMLRenderer.h | 3 ++- src/HTMLRenderer/form.cc | 28 +++++++++++++--------------- src/HTMLRenderer/general.cc | 6 ++++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index 6335d6e..cc40089 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -170,7 +170,8 @@ protected: void process_outline_items(GooList * items); void process_form(std::ostream & out); - + void dump_form_css(std::ostream & out); + void set_stream_flags (std::ostream & out); void dump_css(void); diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index d2870a9..7e55ba8 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -24,7 +24,6 @@ void HTMLRenderer::process_form(ostream & out) { FormPageWidgets * widgets = cur_catalog->getPage(pageNum)->getFormWidgets(); int num = widgets->getNumWidgets(); - std::ostringstream derp; for(int i = 0; i < num; i++) { @@ -61,25 +60,14 @@ void HTMLRenderer::process_form(ostream & out) << " style=\"opacity:0.0; position: absolute; left: " << std::to_string(x1) << "px; bottom: " << std::to_string(y1) << "px;" << "width: " << std::to_string(width) << "px; height: " << std::to_string(height) << - "px; font-size: 20px; \" class=\"checkbox-" << + "px; font-size: 20px; \" class=\"checkbox checkbox-" << std::to_string(pageNum) << "\">X" << endl; } } - //output, at the end, the necessary css + //output, at the end, the necessary js if(num > 0) { - //this is usable by the whole document and as such should be in dump_css - out << "" << endl; - //this is currently page specific out << "" << endl; - } } +void HTMLRenderer::dump_form_css(ostream & out) +{ + out << ".text_input {" << + "border: none; " << + "background-color: rgba(255, 255, 255, 0.0);" << + "}" << endl << + ".checkbox:hover {" << + "cursor: pointer;" << + "}" << endl; +} + } diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index b614a38..6aac48c 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -395,6 +395,12 @@ void HTMLRenderer::pre_process(PDFDoc * doc) void HTMLRenderer::post_process(void) { dump_css(); + + if (param.include_forms) + { + dump_form_css(f_css.fs); + } + // close files if they opened // it's better to brace single liner LLVM complains if (param.process_outline) From ea226cf3021a2068bec7af5e729f4c84a86e036b Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Thu, 2 Oct 2014 16:08:42 -0400 Subject: [PATCH 03/10] Corrections as per Wang Lu's suggestions --- pdf2htmlEX.1.in | 4 + share/base.css.in | 9 + share/pdf2htmlEX.js.in | 17 + share/pdf2htmlEX.min.js | 934 +++++++++++++++++++++++++++++ src/HTMLRenderer/HTMLRenderer.h | 3 +- src/HTMLRenderer/form.cc | 36 +- src/HTMLRenderer/general.cc | 7 +- src/Param.h | 4 +- src/css_class_names.cmakelists.txt | 2 + src/pdf2htmlEX.cc | 4 +- src/util/css_const.h.in | 3 + 11 files changed, 975 insertions(+), 48 deletions(-) create mode 100644 share/pdf2htmlEX.min.js diff --git a/pdf2htmlEX.1.in b/pdf2htmlEX.1.in index 1f44984..d6e5faa 100644 --- a/pdf2htmlEX.1.in +++ b/pdf2htmlEX.1.in @@ -138,6 +138,10 @@ Whether to show outline in the generated HTML .B \-\-process-annotation <0|1> (Default: 0) Whether to show annotation in the generated HTML +.TP +.B \-\-process-forms <0|1> (Default: 0) +Whether to include text fields and radio buttons in the generated HTML + .TP .B \-\-printing <0|1> (Default: 1) Enable printing support. Disabling this option may reduce the size of CSS. diff --git a/share/base.css.in b/share/base.css.in index 7f61507..14e6282 100644 --- a/share/base.css.in +++ b/share/base.css.in @@ -190,4 +190,13 @@ -ms-transform-origin:0% 100%; -webkit-transform-origin:0% 100%; } +/* for the forms */ +.@CSS_INPUT_TEXT_CN@ { + border: none; + background-color: rgba(255, 255, 255, 0.0); +} + +.@CSS_INPUT_RADIO_CN@:hover { + cursor: pointer; +} /* Base CSS END */ diff --git a/share/pdf2htmlEX.js.in b/share/pdf2htmlEX.js.in index 636c94a..7b228bd 100644 --- a/share/pdf2htmlEX.js.in +++ b/share/pdf2htmlEX.js.in @@ -260,7 +260,24 @@ Viewer.prototype = { this.pre_hide_pages(); }, + initialize_radio_button : function() { + var elements = document.getElementsByClassName('ir'); + + for(var i = 0; i < elements.length; i++) { + var r = elements[i]; + + r.addEventListener('click', function() { + if(this.style.opacity == 1) + this.style.opacity = 0; + else + this.style.opacity = 1; + }); + } + }, + init_after_loading_content : function() { + this.initialize_radio_button(); + this.sidebar = document.getElementById(this.config['sidebar_id']); this.outline = document.getElementById(this.config['outline_id']); this.container = document.getElementById(this.config['container_id']); diff --git a/share/pdf2htmlEX.min.js b/share/pdf2htmlEX.min.js new file mode 100644 index 0000000..571e36c --- /dev/null +++ b/share/pdf2htmlEX.min.js @@ -0,0 +1,934 @@ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab filetype=javascript : */ +/** + * @license pdf2htmlEX.js: Core UI functions for pdf2htmlEX + * Copyright 2012,2013 Lu Wang and other contributors + * https://github.com/coolwanglu/pdf2htmlEX/blob/master/share/LICENSE + */ + +/* + * Attention: + * This files is to be optimized by closure-compiler, + * so pay attention to the forms of property names: + * + * string/bracket form is safe, won't be optimized: + * var obj={ 'a':'b' }; obj['a'] = 'b'; + * name/dot form will be optimized, the name is likely to be modified: + * var obj={ a:'b' }; obj.a = 'b'; + * + * Either form can be used for internal objects, + * but must be consistent for each one respectively. + * + * string/bracket form must be used for external objects + * e.g. DEFAULT_CONFIG, object stored in page-data + * property names are part of the `protocol` in these cases. + * + */ + +'use strict'; + +var pdf2htmlEX = window['pdf2htmlEX'] = window['pdf2htmlEX'] || {}; + +/** + * @const + * @struct + */ +var CSS_CLASS_NAMES = { + page_frame : 'pf', + page_content_box : 'pc', + page_data : 'pi', + background_image : 'bi', + link : 'l', + __dummy__ : 'no comma' +}; + +/** + * configurations of Viewer + * @const + * @dict + */ +var DEFAULT_CONFIG = { + // id of the element to put the pages in + 'container_id' : 'page-container', + // id of the element for sidebar (to open and close) + 'sidebar_id' : 'sidebar', + // id of the element for outline + 'outline_id' : 'outline', + // class for the loading indicator + 'loading_indicator_cls' : 'loading-indicator', + // How many page shall we preload that are below the last visible page + 'preload_pages' : 3, + // how many ms should we wait before actually rendering the pages and after a scroll event + 'render_timeout' : 100, + // zoom ratio step for each zoom in/out event + 'scale_step' : 0.9, + // register global key handler + 'key_handler' : true, + // register hashchange handler + 'hashchange_handler' : true, + + '__dummy__' : 'no comma' +}; + +/** @const */ +var EPS = 1e-6; + +/************************************/ +/* utility function */ +/** + * @param{Array.} ctm + */ +function invert(ctm) { + var det = ctm[0] * ctm[3] - ctm[1] * ctm[2]; + return [ ctm[3] / det + ,-ctm[1] / det + ,-ctm[2] / det + ,ctm[0] / det + ,(ctm[2] * ctm[5] - ctm[3] * ctm[4]) / det + ,(ctm[1] * ctm[4] - ctm[0] * ctm[5]) / det + ]; +}; +/** + * @param{Array.} ctm + * @param{Array.} pos + */ +function transform(ctm, pos) { + return [ctm[0] * pos[0] + ctm[2] * pos[1] + ctm[4] + ,ctm[1] * pos[0] + ctm[3] * pos[1] + ctm[5]]; +}; + +/** + * @param{Element} ele + */ +function get_page_number(ele) { + return parseInt(ele.getAttribute('data-page-no'), 16); +}; + +/** + * @param{NodeList} eles + */ +function disable_dragstart(eles) { + for (var i = 0, l = eles.length; i < l; ++i) { + eles[i].addEventListener('dragstart', function() { + return false; + }, false); + } +}; + +/** + * @param{...Object} var_args + */ +function clone_and_extend_objs(var_args) { + var result_obj = {}; + for (var i = 0, l = arguments.length; i < l; ++i) { + var cur_obj = arguments[i]; + for (var k in cur_obj) { + if (cur_obj.hasOwnProperty(k)) { + result_obj[k] = cur_obj[k]; + } + } + } + return result_obj; +}; + +/** + * @constructor + * @param{Element} page The element for the page + */ +function Page(page) { + if (!page) return; + + this.loaded = false; + this.shown = false; + this.page = page; // page frame element + + this.num = get_page_number(page); + + // page size + // Need to make rescale work when page_content_box is not loaded, yet + this.original_height = page.clientHeight; + this.original_width = page.clientWidth; + + // content box + var content_box = page.getElementsByClassName(CSS_CLASS_NAMES.page_content_box)[0]; + + // if page is loaded + if (content_box) { + this.content_box = content_box; + /* + * scale ratios + * + * original_scale : the first one + * cur_scale : currently using + */ + this.original_scale = this.cur_scale = this.original_height / content_box.clientHeight; + this.page_data = JSON.parse(page.getElementsByClassName(CSS_CLASS_NAMES.page_data)[0].getAttribute('data-data')); + + this.ctm = this.page_data['ctm']; + this.ictm = invert(this.ctm); + + this.loaded = true; + } +}; +Page.prototype = { + /* hide & show are for contents, the page frame is still there */ + hide : function(){ + if (this.loaded && this.shown) { + this.content_box.classList.remove('opened'); + this.shown = false; + } + }, + show : function(){ + if (this.loaded && !this.shown) { + this.content_box.classList.add('opened'); + this.shown = true; + } + }, + /** + * @param{number} ratio + */ + rescale : function(ratio) { + if (ratio === 0) { + // reset scale + this.cur_scale = this.original_scale; + } else { + this.cur_scale = ratio; + } + + // scale the content box + if (this.loaded) { + var cbs = this.content_box.style; + cbs.msTransform = cbs.webkitTransform = cbs.transform = 'scale('+this.cur_scale.toFixed(3)+')'; + } + + // stretch the page frame to hold the place + { + var ps = this.page.style; + ps.height = (this.original_height * this.cur_scale) + 'px'; + ps.width = (this.original_width * this.cur_scale) + 'px'; + } + }, + /* + * return the coordinate of the top-left corner of container + * in our coordinate system + * assuming that p.parentNode === p.offsetParent + */ + view_position : function () { + var p = this.page; + var c = p.parentNode; + return [c.scrollLeft - p.offsetLeft - p.clientLeft + ,c.scrollTop - p.offsetTop - p.clientTop]; + }, + height : function () { + return this.page.clientHeight; + }, + width : function () { + return this.page.clientWidth; + } +}; + +/** + * @constructor + * @param{Object=} config + */ +function Viewer(config) { + this.config = clone_and_extend_objs(DEFAULT_CONFIG, (arguments.length > 0 ? config : {})); + this.pages_loading = []; + this.init_before_loading_content(); + + var self = this; + document.addEventListener('DOMContentLoaded', function(){ + self.init_after_loading_content(); + }, false); +}; + +Viewer.prototype = { + scale : 1, + /* + * index of the active page (the one with largest visible area) + * which estimates the page currently being viewed + */ + cur_page_idx : 0, + + /* + * index of the first visible page + * used when determining current view + */ + first_page_idx : 0, + + init_before_loading_content : function() { + /* hide all pages before loading, will reveal only visible ones later */ + this.pre_hide_pages(); + }, + + initialize_radio_button : function() { + var elements = document.getElementsByClassName('ir'); + + for(var i = 0; i < elements.length; i++) { + var r = elements[i]; + + r.addEventListener('click', function() { + if(this.style.opacity == 1) + this.style.opacity = 0; + else + this.style.opacity = 1; + }); + } + }, + + init_after_loading_content : function() { + this.initialize_radio_button(); + + this.sidebar = document.getElementById(this.config['sidebar_id']); + this.outline = document.getElementById(this.config['outline_id']); + this.container = document.getElementById(this.config['container_id']); + this.loading_indicator = document.getElementsByClassName(this.config['loading_indicator_cls'])[0]; + + + { + // Open the outline if nonempty + var empty = true; + var nodes = this.outline.childNodes; + for (var i = 0, l = nodes.length; i < l; ++i) { + var cur_node = nodes[i]; + if (cur_node.nodeName.toLowerCase() === 'ul') { + empty = false; + break; + } + } + if (!empty) + this.sidebar.classList.add('opened'); + } + + this.find_pages(); + // do nothing if there's nothing + if(this.pages.length == 0) return; + + // disable dragging of background images + disable_dragstart(document.getElementsByClassName(CSS_CLASS_NAMES.background_image)); + + if (this.config['key_handler']) + this.register_key_handler(); + + var self = this; + + if (this.config['hashchange_handler']) { + window.addEventListener('hashchange', function(e) { + self.navigate_to_dest(document.location.hash.substring(1)); + }, false); + } + + // register schedule rendering + // renew old schedules since scroll() may be called frequently + this.container.addEventListener('scroll', function() { + self.update_page_idx(); + self.schedule_render(true); + }, false); + + // handle links + [this.container, this.outline].forEach(function(ele) { + ele.addEventListener('click', self.link_handler.bind(self), false); + }); + + this.render(); + }, + + /* + * set up this.pages and this.page_map + * pages is an array holding all the Page objects + * page-Map maps an original page number (in PDF) to the corresponding index in page + */ + find_pages : function() { + var new_pages = []; + var new_page_map = {}; + var nodes = this.container.childNodes; + for (var i = 0, l = nodes.length; i < l; ++i) { + var cur_node = nodes[i]; + if ((cur_node.nodeType === Node.ELEMENT_NODE) + && cur_node.classList.contains(CSS_CLASS_NAMES.page_frame)) { + var p = new Page(cur_node); + new_pages.push(p); + new_page_map[p.num] = new_pages.length - 1; + } + } + this.pages = new_pages; + this.page_map = new_page_map; + }, + + /** + * @param{number} idx + * @param{number=} pages_to_preload + * @param{function(Page)=} callback + * + * TODO: remove callback -> promise ? + */ + load_page : function(idx, pages_to_preload, callback) { + var pages = this.pages; + if (idx >= pages.length) + return; // Page does not exist + + var cur_page = pages[idx]; + if (cur_page.loaded) + return; // Page is loaded + + if (this.pages_loading[idx]) + return; // Page is already loading + + var cur_page_ele = cur_page.page; + var url = cur_page_ele.getAttribute('data-page-url'); + if (url) { + this.pages_loading[idx] = true; // set semaphore + + // add a copy of the loading indicator + var new_loading_indicator = this.loading_indicator.cloneNode(); + new_loading_indicator.classList.add('active'); + cur_page_ele.appendChild(new_loading_indicator); + + // load data + { + var self = this; + var _idx = idx; + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onload = function(){ + if (xhr.status === 200 || xhr.status === 0) { + // find the page element in the data + var div = document.createElement('div'); + div.innerHTML = xhr.responseText; + + var new_page = null; + var nodes = div.childNodes; + for (var i = 0, l = nodes.length; i < l; ++i) { + var cur_node = nodes[i]; + if ((cur_node.nodeType === Node.ELEMENT_NODE) + && cur_node.classList.contains(CSS_CLASS_NAMES.page_frame)) { + new_page = cur_node; + break; + } + } + + // replace the old page with loaded data + // the loading indicator on this page should also be destroyed + var p = self.pages[_idx]; + self.container.replaceChild(new_page, p.page); + p = new Page(new_page); + self.pages[_idx] = p; + + p.hide(); + p.rescale(self.scale); + + // disable background image dragging + disable_dragstart(new_page.getElementsByClassName(CSS_CLASS_NAMES.background_image)); + + self.schedule_render(false); + + if (callback){ callback(p); } + } + + // Reset loading token + delete self.pages_loading[_idx]; + }; + xhr.send(null); + } + } + // Concurrent prefetch of the next pages + if (pages_to_preload === undefined) + pages_to_preload = this.config['preload_pages']; + + if (--pages_to_preload > 0) { + var self = this; + setTimeout(function() { + self.load_page(idx+1, pages_to_preload); + },0); + } + }, + + /* + * Hide all pages that have no 'opened' class + * The 'opened' class will be added to visible pages by JavaScript + * We cannot add this in the default CSS because JavaScript may be disabled + */ + pre_hide_pages : function() { + /* pages might have not been loaded yet, so add a CSS rule */ + var s = '@media screen{.'+CSS_CLASS_NAMES.page_content_box+'{display:none;}}'; + var n = document.createElement('style'); + if (n.styleSheet) { + n.styleSheet.cssText = s; + } else { + n.appendChild(document.createTextNode(s)); + } + document.head.appendChild(n); + }, + + /* + * show visible pages and hide invisible pages + */ + render : function () { + var container = this.container; + /* + * show the pages that are 'nearly' visible -- it's right above or below the container + * + * all the y values are in the all-page element's coordinate system + */ + var container_min_y = container.scrollTop; + var container_height = container.clientHeight; + var container_max_y = container_min_y + container_height; + var visible_min_y = container_min_y - container_height; + var visible_max_y = container_max_y + container_height; + + var cur_page_fully_visible = false; + var cur_page_idx = this.cur_page_idx; + var max_visible_page_idx = cur_page_idx; + var max_visible_ratio = 0.0; + + var pl = this.pages; + for (var i = 0, l = pl.length; i < l; ++i) { + var cur_page = pl[i]; + var cur_page_ele = cur_page.page; + var page_min_y = cur_page_ele.offsetTop + cur_page_ele.clientTop; + var page_height = cur_page_ele.clientHeight; + var page_max_y = page_min_y + page_height; + if ((page_min_y <= visible_max_y) && (page_max_y >= visible_min_y)) + { + // cur_page is 'nearly' visible, show it or load it + if (cur_page.loaded) { + cur_page.show(); + } else { + this.load_page(i); + } + } else { + cur_page.hide(); + } + } + }, + /* + * update cur_page_idx and first_page_idx + * normally called upon scrolling + */ + update_page_idx: function () { + var pages = this.pages; + var pages_len = pages.length; + // there is no chance that cur_page_idx or first_page_idx is modified + if (pages_len < 2) return; + + var container = this.container; + var container_min_y = container.scrollTop; + var container_max_y = container_min_y + container.clientHeight; + + // binary search for the first page + // whose bottom border is below the top border of the container + var first_idx = -1; + var last_idx = pages_len; + var rest_len = last_idx - first_idx; + // TODO: use current first_page_idx as a hint? + while(rest_len > 1) { + var idx = first_idx + Math.floor(rest_len / 2); + var cur_page_ele = pages[idx].page; + if (cur_page_ele.offsetTop + cur_page_ele.clientTop + cur_page_ele.clientHeight >= container_min_y) { + last_idx = idx; + } else { + first_idx = idx; + } + rest_len = last_idx - first_idx; + } + + /* + * with malformed settings it is possible that no page is visible, e.g. + * - the container is to thin, which lies in the margin between two pages + * - all pages are completely above or below the container + * but we just assume that they won't happen. + */ + this.first_page_idx = last_idx; + + // find the page with largest visible area + var cur_page_idx = this.cur_page_idx; + var max_visible_page_idx = cur_page_idx; + var max_visible_ratio = 0.0; + + for(var i = last_idx; i < pages_len; ++i) { + var cur_page_ele = pages[i].page; + var page_min_y = cur_page_ele.offsetTop + cur_page_ele.clientTop; + var page_height = cur_page_ele.clientHeight; + var page_max_y = page_min_y + page_height; + if (page_min_y > container_max_y) break; + + // check the visible fraction of the page + var page_visible_ratio = ( Math.min(container_max_y, page_max_y) + - Math.max(container_min_y, page_min_y) + ) / page_height; + + // stay with the current page if it is still fully visible + if ((i === cur_page_idx) && (Math.abs(page_visible_ratio - 1.0) <= EPS)) { + max_visible_page_idx = cur_page_idx; + break; + } + + if (page_visible_ratio > max_visible_ratio) { + max_visible_ratio = page_visible_ratio; + max_visible_page_idx = i; + } + } + + this.cur_page_idx = max_visible_page_idx; + }, + + /** + * @param{boolean} renew renew the existing schedule instead of using the old one + */ + schedule_render : function(renew) { + if (this.render_timer !== undefined) { + if (!renew) return; + clearTimeout(this.render_timer); + } + + var self = this; + this.render_timer = setTimeout(function () { + /* + * render() may trigger load_page(), which may in turn trigger another render() + * so delete render_timer first + */ + delete self.render_timer; + self.render(); + }, this.config['render_timeout']); + }, + + /* + * Handling key events, zooming, scrolling etc. + */ + register_key_handler: function () { + /* + * When user try to zoom in/out using ctrl + +/- or mouse wheel + * handle this and prevent the default behaviours + * + * Code credit to PDF.js + */ + var self = this; + + // Firefox specific event, so that we can prevent browser from zooming + window.addEventListener('DOMMouseScroll', function(e) { + if (e.ctrlKey) { + e.preventDefault(); + var container = self.container; + var rect = container.getBoundingClientRect(); + var fixed_point = [e.clientX - rect['left'] - container.clientLeft + ,e.clientY - rect['top'] - container.clientTop]; + self.rescale(Math.pow(self.config['scale_step'], e.detail), true, fixed_point); + } + }, false); + + window.addEventListener('keydown', function(e) { + var handled = false; + /* + var cmd = (e.ctrlKey ? 1 : 0) + | (e.altKey ? 2 : 0) + | (e.shiftKey ? 4 : 0) + | (e.metaKey ? 8 : 0) + ; + */ + var with_ctrl = e.ctrlKey || e.metaKey; + var with_alt = e.altKey; + switch (e.keyCode) { + case 61: // FF/Mac '=' + case 107: // FF '+' and '=' + case 187: // Chrome '+' + if (with_ctrl){ + self.rescale(1.0 / self.config['scale_step'], true); + handled = true; + } + break; + case 173: // FF/Mac '-' + case 109: // FF '-' + case 189: // Chrome '-' + if (with_ctrl){ + self.rescale(self.config['scale_step'], true); + handled = true; + } + break; + case 48: // '0' + if (with_ctrl){ + self.rescale(0, false); + handled = true; + } + break; + case 33: // Page UP: + if (with_alt) { // alt-pageup -> scroll one page up + self.scroll_to(self.cur_page_idx - 1); + } else { // pageup -> scroll one screen up + self.container.scrollTop -= self.container.clientHeight; + } + handled = true; + break; + case 34: // Page DOWN + if (with_alt) { // alt-pagedown -> scroll one page down + self.scroll_to(self.cur_page_idx + 1); + } else { // pagedown -> scroll one screen down + self.container.scrollTop += self.container.clientHeight; + } + handled = true; + break; + case 35: // End + self.container.scrollTop = self.container.scrollHeight; + handled = true; + break; + case 36: // Home + self.container.scrollTop = 0; + handled = true; + break; + } + if (handled) { + e.preventDefault(); + return; + } + }, false); + }, + + /** + * @param{number} ratio + * @param{boolean} is_relative + * @param{Array.=} fixed_point preserve the position (relative to the top-left corner of the viewer) after rescaling + */ + rescale : function (ratio, is_relative, fixed_point) { + var old_scale = this.scale; + var new_scale = old_scale; + // set new scale + if (ratio === 0) { + new_scale = 1; + is_relative = false; + } else if (is_relative) + new_scale *= ratio; + else + new_scale = ratio; + + this.scale = new_scale; + + if (!fixed_point) + fixed_point = [0,0]; + + // translate fixed_point to the coordinate system of all pages + var container = this.container; + fixed_point[0] += container.scrollLeft; + fixed_point[1] += container.scrollTop; + + // find the visible page that contains the fixed point + // if the fixed point lies between two pages (including their borders), it's contained in the first one + var pl = this.pages; + var pl_len = pl.length; + for (var i = this.first_page_idx; i < pl_len; ++i) { + var p = pl[i].page; + if (p.offsetTop + p.clientTop >= fixed_point[1]) + break; + } + var fixed_point_page_idx = i - 1; + + // determine the new scroll position + // each-value consists of two parts, one inside the page, which is affected by rescaling, + // the other is outside, (e.g. borders and margins), which is not affected + + // if the fixed_point is above the first page, use the first page as the reference + if (fixed_point_page_idx < 0) + fixed_point_page_idx = 0; + + var fp_p = pl[fixed_point_page_idx].page; + var fp_p_width = fp_p.clientWidth; + var fp_p_height = fp_p.clientHeight; + + var fp_x_ref = fp_p.offsetLeft + fp_p.clientLeft; + var fp_x_inside = fixed_point[0] - fp_x_ref; + if (fp_x_inside < 0) + fp_x_inside = 0; + else if (fp_x_inside > fp_p_width) + fp_x_inside = fp_p_width; + + var fp_y_ref = fp_p.offsetTop + fp_p.clientTop; + var fp_y_inside = fixed_point[1] - fp_y_ref; + if (fp_y_inside < 0) + fp_y_inside = 0; + else if (fp_y_inside > fp_p_height) + fp_y_inside = fp_p_height; + + // Rescale pages + for (var i = 0; i < pl_len; ++i) + pl[i].rescale(new_scale); + + // Correct container scroll to keep view aligned while zooming + container.scrollLeft += fp_x_inside / old_scale * new_scale + fp_p.offsetLeft + fp_p.clientLeft - fp_x_inside - fp_x_ref; + container.scrollTop += fp_y_inside / old_scale * new_scale + fp_p.offsetTop + fp_p.clientTop - fp_y_inside - fp_y_ref; + + // some pages' visibility may be toggled, wait for next render() + // renew old schedules since rescale() may be called frequently + this.schedule_render(true); + }, + + fit_width : function () { + var page_idx = this.cur_page_idx; + this.rescale(this.container.clientWidth / this.pages[page_idx].width(), false); + this.scroll_to(page_idx); + }, + + fit_height : function () { + var page_idx = this.cur_page_idx; + this.rescale(this.container.clientHeight / this.pages[page_idx].height(), false); + this.scroll_to(page_idx); + }, + /** + * @param{Node} ele + */ + get_containing_page : function(ele) { + /* get the page obj containing obj */ + while(ele) { + if ((ele.nodeType === Node.ELEMENT_NODE) + && ele.classList.contains(CSS_CLASS_NAMES.page_frame)) { + /* + * Get original page number and map it to index of pages + * TODO: store the index on the dom element + */ + var pn = get_page_number(/** @type{Element} */(ele)); + var pm = this.page_map; + return (pn in pm) ? this.pages[pm[pn]] : null; + } + ele = ele.parentNode; + } + return null; + }, + + /** + * @param{Event} e + */ + link_handler : function (e) { + var target = /** @type{Node} */(e.target); + var detail_str = /** @type{string} */ (target.getAttribute('data-dest-detail')); + if (!detail_str) return; + + this.navigate_to_dest(detail_str, this.get_containing_page(target)); + e.preventDefault(); + }, + + /** + * @param{string} detail_str may come from user provided hashtag, need sanitzing + * @param{Page=} src_page page containing the source event (e.g. link) + */ + navigate_to_dest : function(detail_str, src_page) { + try { + var detail = JSON.parse(detail_str); + } catch(e) { + return; + } + + if(!(detail instanceof Array)) return; + + var target_page_no = detail[0]; + var page_map = this.page_map; + if (!(target_page_no in page_map)) return; + var target_page_idx = page_map[target_page_no]; + var target_page = this.pages[target_page_idx]; + + for (var i = 2, l = detail.length; i < l; ++i) { + var d = detail[i]; + if(!((d === null) || (typeof d === 'number'))) + return; + } + + while(detail.length < 6) + detail.push(null); + + // cur_page might be undefined, e.g. from Outline + var cur_page = src_page || this.pages[this.cur_page_idx]; + + var cur_pos = cur_page.view_position(); + cur_pos = transform(cur_page.ictm, [cur_pos[0], cur_page.height()-cur_pos[1]]); + + var zoom = this.scale; + var pos = [0,0]; + var upside_down = true; + var ok = false; + + // position specified in `detail` are in the raw coordinate system of the page (unscaled) + var scale = this.scale; + // TODO: fitb* + // TODO: BBox + switch(detail[1]) { + case 'XYZ': + pos = [ (detail[2] === null) ? cur_pos[0] : detail[2] * scale + , (detail[3] === null) ? cur_pos[1] : detail[3] * scale ]; + zoom = detail[4]; + if ((zoom === null) || (zoom === 0)) + zoom = this.scale; + ok = true; + break; + case 'Fit': + case 'FitB': + pos = [0,0]; + ok = true; + break; + case 'FitH': + case 'FitBH': + pos = [0, (detail[2] === null) ? cur_pos[1] : detail[2] * scale]; + ok = true; + break; + case 'FitV': + case 'FitBV': + pos = [(detail[2] === null) ? cur_pos[0] : detail[2] * scale, 0]; + ok = true; + break; + case 'FitR': + /* locate the top-left corner of the rectangle */ + // TODO + pos = [detail[2] * scale, detail[5] * scale]; + upside_down = false; + ok = true; + break; + default: + break; + } + + if (!ok) return; + + this.rescale(zoom, false); + + + var self = this; + /** + * page should of type Page + * @param{Page} page + */ + var transform_and_scroll = function(page) { + pos = transform(page.ctm, pos); + if (upside_down) { + pos[1] = page.height() - pos[1]; + } + self.scroll_to(target_page_idx, pos); + }; + + if (target_page.loaded) { + transform_and_scroll(target_page); + } else { + // TODO: scroll_to may finish before load_page + + // Scroll to the exact position once loaded. + this.load_page(target_page_idx, undefined, transform_and_scroll); + + // In the meantime page gets loaded, scroll approximately position for maximum responsiveness. + this.scroll_to(target_page_idx); + } + }, + + /** + * @param{number} page_idx + * @param{Array.=} pos [x,y] where (0,0) is the top-left corner + */ + scroll_to : function(page_idx, pos) { + var pl = this.pages; + if ((page_idx < 0) || (page_idx >= pl.length)) return; + var target_page = pl[page_idx]; + var cur_target_pos = target_page.view_position(); + + if (pos === undefined) + pos = [0,0]; + + var container = this.container; + container.scrollLeft += pos[0] - cur_target_pos[0]; + container.scrollTop += pos[1] - cur_target_pos[1]; + } +}; + +// export pdf2htmlEX.Viewer +pdf2htmlEX['Viewer'] = Viewer; diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index cc40089..6335d6e 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -170,8 +170,7 @@ protected: void process_outline_items(GooList * items); void process_form(std::ostream & out); - void dump_form_css(std::ostream & out); - + void set_stream_flags (std::ostream & out); void dump_css(void); diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 7e55ba8..02b5036 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -50,7 +50,7 @@ void HTMLRenderer::process_form(ostream & out) "px; bottom: " << std::to_string(y1) << "px;" << "width: " << std::to_string(width) << "px; height: " << std::to_string(height) << "px; line-height: " << std::to_string(height) << "px; font-size: " - << std::to_string(font_size) << "px;\" class=\"text_input\" />" << endl; + << std::to_string(font_size) << "px;\" class=\"" << CSS::INPUT_TEXT_CN << "\" />" << endl; } if(w->getType() == formButton) @@ -60,42 +60,10 @@ void HTMLRenderer::process_form(ostream & out) << " style=\"opacity:0.0; position: absolute; left: " << std::to_string(x1) << "px; bottom: " << std::to_string(y1) << "px;" << "width: " << std::to_string(width) << "px; height: " << std::to_string(height) << - "px; font-size: 20px; \" class=\"checkbox checkbox-" << - std::to_string(pageNum) << "\">X" << endl; + "px; font-size: 20px; \" class=\"" << CSS::INPUT_RADIO_CN << "\">X" << endl; } } - - //output, at the end, the necessary js - if(num > 0) { - //this is currently page specific - out << "" << endl; - } -} - -void HTMLRenderer::dump_form_css(ostream & out) -{ - out << ".text_input {" << - "border: none; " << - "background-color: rgba(255, 255, 255, 0.0);" << - "}" << endl << - ".checkbox:hover {" << - "cursor: pointer;" << - "}" << endl; } } diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index 6aac48c..a370a15 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -253,7 +253,7 @@ void HTMLRenderer::endPage() { html_text_page.clear(); // process form - if(param.include_forms) + if(param.process_forms) process_form(*f_curpage); // process links before the page is closed @@ -396,11 +396,6 @@ void HTMLRenderer::post_process(void) { dump_css(); - if (param.include_forms) - { - dump_form_css(f_css.fs); - } - // close files if they opened // it's better to brace single liner LLVM complains if (param.process_outline) diff --git a/src/Param.h b/src/Param.h index 9491d42..eea1bd9 100644 --- a/src/Param.h +++ b/src/Param.h @@ -38,6 +38,7 @@ struct Param int process_nontext; int process_outline; int process_annotation; + int process_forms; int correct_text_visibility; int printing; int fallback; @@ -62,9 +63,6 @@ struct Param int tounicode; int optimize_text; - // adobe form - int include_forms; - // background image std::string bg_format; int svg_node_count_limit; diff --git a/src/css_class_names.cmakelists.txt b/src/css_class_names.cmakelists.txt index 9240c6e..19c6f8b 100644 --- a/src/css_class_names.cmakelists.txt +++ b/src/css_class_names.cmakelists.txt @@ -34,3 +34,5 @@ set(CSS_WIDTH_CN "w") # Width set(CSS_BOTTTOM_CN "y") # Y set(CSS_CSS_DRAW_CN "d") # Draw set(CSS_LINK_CN "l") # Link +set(CSS_INPUT_TEXT_CN "it") # Text input +set(CSS_INPUT_RADIO_CN "ir") # Radio button diff --git a/src/pdf2htmlEX.cc b/src/pdf2htmlEX.cc index 845b5bf..aa17b59 100644 --- a/src/pdf2htmlEX.cc +++ b/src/pdf2htmlEX.cc @@ -164,6 +164,7 @@ void parse_options (int argc, char **argv) .add("process-nontext", ¶m.process_nontext, 1, "render graphics in addition to text") .add("process-outline", ¶m.process_outline, 1, "show outline in HTML") .add("process-annotation", ¶m.process_annotation, 0, "show annotation in HTML") + .add("process-forms", ¶m.process_forms, 0, "include text fields and radio buttons") .add("printing", ¶m.printing, 1, "enable printing support") .add("fallback", ¶m.fallback, 0, "output in fallback mode") .add("tmp-file-size-limit", ¶m.tmp_file_size_limit, -1, "Maximum size (in KB) used by temporary files, -1 for no limit.") @@ -189,9 +190,6 @@ void parse_options (int argc, char **argv) .add("optimize-text", ¶m.optimize_text, 0, "try to reduce the number of HTML elements used for text") .add("correct-text-visibility", ¶m.correct_text_visibility, 0, "try to detect texts covered by other graphics and properly arrange them") - // adobe forms - .add("include-forms", ¶m.include_forms, 0, "include text fields and such") - // background image .add("bg-format", ¶m.bg_format, "png", "specify background image format") .add("svg-node-count-limit", ¶m.svg_node_count_limit, -1, "if node count in a svg background image exceeds this limit," diff --git a/src/util/css_const.h.in b/src/util/css_const.h.in index 143adcb..795ed10 100644 --- a/src/util/css_const.h.in +++ b/src/util/css_const.h.in @@ -56,6 +56,9 @@ const char * const BOTTOM_CN = "@CSS_BOTTTOM_CN@"; const char * const CSS_DRAW_CN = "@CSS_CSS_DRAW_CN@"; const char * const LINK_CN = "@CSS_LINK_CN@"; +const char * const INPUT_TEXT_CN = "@CSS_INPUT_TEXT_CN@"; +const char * const INPUT_RADIO_CN = "@CSS_INPUT_RADIO_CN@"; + } } From 6fe0262427932006ada67250b7fa73ed0fa207ec Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Thu, 16 Oct 2014 10:34:41 -0400 Subject: [PATCH 04/10] The cross symbol for checkboxes is now an image. --- share/base.css.in | 4 ++++ share/pdf2htmlEX.js.in | 6 +++--- share/pdf2htmlEX.min.js | 6 +++--- src/HTMLRenderer/form.cc | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/share/base.css.in b/share/base.css.in index 14e6282..91eb5be 100644 --- a/share/base.css.in +++ b/share/base.css.in @@ -199,4 +199,8 @@ .@CSS_INPUT_RADIO_CN@:hover { cursor: pointer; } + +.checked { + background: no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goQDSYgDiGofgAAAslJREFUOMvtlM9LFGEYx7/vvOPM6ywuuyPFihWFBUsdNnA6KLIh+QPx4KWExULdHQ/9A9EfUodYmATDYg/iRewQzklFWxcEBcGgEplDkDtI6sw4PzrIbrOuedBb9MALD7zv+3m+z4/3Bf7bZS2bzQIAcrmcMDExcTeXy10DAFVVAQDksgFUVZ1ljD3yfd+0LOuFpmnvVVW9GHhkZAQcxwkNDQ2FSCQyRMgJxnVdy7KstKZpn7nwha6urqqfTqfPBAJAuVymlNLXoigOhfd5nmeiKL5TVTV+lmIKwAOA7u5u6Lped2BsbOwjY6yf4zgQQkAIAcedaPR9H67r3uYBQFEUFItFtLe332lpaVkUBOHK3t5eRtf1DwAwODiIubk5DA8PM8bYW1EU+wEgCIJqsCAIQAiB7/u253k2BQDDMJBKpa4mEon5eDx+UxAESJL0uK2t7XosFlvSdf0QAEmlUnlRFJ9Waho2Qghc1/U9z3uWz+eX+Wr+lL6SZfleEAQIggA8z6OpqSknimIvYyybSCReMsZ6TislhCAIAti2Dc/zejVNWwCAavN8339j27YbTg0AGGM3WltbP4WhlRWq6Q/btrs1TVsYHx+vNgqKoqBUKn2NRqPFxsbGJzzP05puUlpt0ukyOI6z7zjOwNTU1OLo6CgmJyf/gA3DgKIoWF1d/cIY24/FYgOU0pp0z/Ityzo8Pj5OTk9PbwHA+vp6zWghDC+VSiuRSOQgGo32UErJ38CO42wdHR09LBQK3zKZDDY2NupmFmF4R0cHVlZWlmRZ/iVJUn9FeWWcCCE4ODjYtG27Z2Zm5juAOmgdGAB2d3cBADs7O8uSJN2SZfl+WKlpmpumaT6Yn58vn/fs6XmbhmHMNjc3tzDGFI7jYJrm5vb29sDa2trPC/9aiqJUy5pOp4f6+vqeJ5PJBAB0dnZe/t8NBajx/z37Df5OGX8d13xzAAAAAElFTkSuQmCC); +} /* Base CSS END */ diff --git a/share/pdf2htmlEX.js.in b/share/pdf2htmlEX.js.in index 7b228bd..118c8d6 100644 --- a/share/pdf2htmlEX.js.in +++ b/share/pdf2htmlEX.js.in @@ -267,10 +267,10 @@ Viewer.prototype = { var r = elements[i]; r.addEventListener('click', function() { - if(this.style.opacity == 1) - this.style.opacity = 0; + if(this.className.search("checked") == -1) + this.className += " checked"; else - this.style.opacity = 1; + this.className = "ir"; }); } }, diff --git a/share/pdf2htmlEX.min.js b/share/pdf2htmlEX.min.js index 571e36c..4aa848e 100644 --- a/share/pdf2htmlEX.min.js +++ b/share/pdf2htmlEX.min.js @@ -267,10 +267,10 @@ Viewer.prototype = { var r = elements[i]; r.addEventListener('click', function() { - if(this.style.opacity == 1) - this.style.opacity = 0; + if(this.className.search("checked") == -1) + this.className += " checked"; else - this.style.opacity = 1; + this.className = "ir"; }); } }, diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 02b5036..72e6fdf 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -55,12 +55,15 @@ void HTMLRenderer::process_form(ostream & out) if(w->getType() == formButton) { + width += 3; + height += 3; + out << "
X
" << endl; + "px; \" class=\"" << CSS::INPUT_RADIO_CN << "\">" << endl; } } From c9201c6a1d629096ce44c6a747af7f967213fe05 Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Fri, 14 Nov 2014 14:28:17 -0500 Subject: [PATCH 05/10] some more corrections and cleaning --- pdf2htmlEX.1.in | 2 +- share/base.css.in | 3 - share/fancy.css.in | 3 + share/pdf2htmlEX.min.js | 934 ----------------------------- src/HTMLRenderer/HTMLRenderer.h | 2 +- src/HTMLRenderer/form.cc | 37 +- src/HTMLRenderer/general.cc | 2 +- src/Param.h | 2 +- src/css_class_names.cmakelists.txt | 1 + src/pdf2htmlEX.cc | 2 +- src/util/css_const.h.in | 1 + 11 files changed, 30 insertions(+), 959 deletions(-) delete mode 100644 share/pdf2htmlEX.min.js diff --git a/pdf2htmlEX.1.in b/pdf2htmlEX.1.in index d6e5faa..6852507 100644 --- a/pdf2htmlEX.1.in +++ b/pdf2htmlEX.1.in @@ -139,7 +139,7 @@ Whether to show outline in the generated HTML Whether to show annotation in the generated HTML .TP -.B \-\-process-forms <0|1> (Default: 0) +.B \-\-process-form <0|1> (Default: 0) Whether to include text fields and radio buttons in the generated HTML .TP diff --git a/share/base.css.in b/share/base.css.in index 91eb5be..a15a23f 100644 --- a/share/base.css.in +++ b/share/base.css.in @@ -200,7 +200,4 @@ cursor: pointer; } -.checked { - background: no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goQDSYgDiGofgAAAslJREFUOMvtlM9LFGEYx7/vvOPM6ywuuyPFihWFBUsdNnA6KLIh+QPx4KWExULdHQ/9A9EfUodYmATDYg/iRewQzklFWxcEBcGgEplDkDtI6sw4PzrIbrOuedBb9MALD7zv+3m+z4/3Bf7bZS2bzQIAcrmcMDExcTeXy10DAFVVAQDksgFUVZ1ljD3yfd+0LOuFpmnvVVW9GHhkZAQcxwkNDQ2FSCQyRMgJxnVdy7KstKZpn7nwha6urqqfTqfPBAJAuVymlNLXoigOhfd5nmeiKL5TVTV+lmIKwAOA7u5u6Lped2BsbOwjY6yf4zgQQkAIAcedaPR9H67r3uYBQFEUFItFtLe332lpaVkUBOHK3t5eRtf1DwAwODiIubk5DA8PM8bYW1EU+wEgCIJqsCAIQAiB7/u253k2BQDDMJBKpa4mEon5eDx+UxAESJL0uK2t7XosFlvSdf0QAEmlUnlRFJ9Waho2Qghc1/U9z3uWz+eX+Wr+lL6SZfleEAQIggA8z6OpqSknimIvYyybSCReMsZ6TislhCAIAti2Dc/zejVNWwCAavN8339j27YbTg0AGGM3WltbP4WhlRWq6Q/btrs1TVsYHx+vNgqKoqBUKn2NRqPFxsbGJzzP05puUlpt0ukyOI6z7zjOwNTU1OLo6CgmJyf/gA3DgKIoWF1d/cIY24/FYgOU0pp0z/Ityzo8Pj5OTk9PbwHA+vp6zWghDC+VSiuRSOQgGo32UErJ38CO42wdHR09LBQK3zKZDDY2NupmFmF4R0cHVlZWlmRZ/iVJUn9FeWWcCCE4ODjYtG27Z2Zm5juAOmgdGAB2d3cBADs7O8uSJN2SZfl+WKlpmpumaT6Yn58vn/fs6XmbhmHMNjc3tzDGFI7jYJrm5vb29sDa2trPC/9aiqJUy5pOp4f6+vqeJ5PJBAB0dnZe/t8NBajx/z37Df5OGX8d13xzAAAAAElFTkSuQmCC); -} /* Base CSS END */ diff --git a/share/fancy.css.in b/share/fancy.css.in index b8d9dc5..bdba3f6 100644 --- a/share/fancy.css.in +++ b/share/fancy.css.in @@ -81,5 +81,8 @@ -webkit-animation: swing 1.5s ease-in-out 0.01s infinite alternate none; animation: swing 1.5s ease-in-out 0.01s infinite alternate none; } + .@CSS_RADIO_CHECKED_CN@ { + background: no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goQDSYgDiGofgAAAslJREFUOMvtlM9LFGEYx7/vvOPM6ywuuyPFihWFBUsdNnA6KLIh+QPx4KWExULdHQ/9A9EfUodYmATDYg/iRewQzklFWxcEBcGgEplDkDtI6sw4PzrIbrOuedBb9MALD7zv+3m+z4/3Bf7bZS2bzQIAcrmcMDExcTeXy10DAFVVAQDksgFUVZ1ljD3yfd+0LOuFpmnvVVW9GHhkZAQcxwkNDQ2FSCQyRMgJxnVdy7KstKZpn7nwha6urqqfTqfPBAJAuVymlNLXoigOhfd5nmeiKL5TVTV+lmIKwAOA7u5u6Lped2BsbOwjY6yf4zgQQkAIAcedaPR9H67r3uYBQFEUFItFtLe332lpaVkUBOHK3t5eRtf1DwAwODiIubk5DA8PM8bYW1EU+wEgCIJqsCAIQAiB7/u253k2BQDDMJBKpa4mEon5eDx+UxAESJL0uK2t7XosFlvSdf0QAEmlUnlRFJ9Waho2Qghc1/U9z3uWz+eX+Wr+lL6SZfleEAQIggA8z6OpqSknimIvYyybSCReMsZ6TislhCAIAti2Dc/zejVNWwCAavN8339j27YbTg0AGGM3WltbP4WhlRWq6Q/btrs1TVsYHx+vNgqKoqBUKn2NRqPFxsbGJzzP05puUlpt0ukyOI6z7zjOwNTU1OLo6CgmJyf/gA3DgKIoWF1d/cIY24/FYgOU0pp0z/Ityzo8Pj5OTk9PbwHA+vp6zWghDC+VSiuRSOQgGo32UErJ38CO42wdHR09LBQK3zKZDDY2NupmFmF4R0cHVlZWlmRZ/iVJUn9FeWWcCCE4ODjYtG27Z2Zm5juAOmgdGAB2d3cBADs7O8uSJN2SZfl+WKlpmpumaT6Yn58vn/fs6XmbhmHMNjc3tzDGFI7jYJrm5vb29sDa2trPC/9aiqJUy5pOp4f6+vqeJ5PJBAB0dnZe/t8NBajx/z37Df5OGX8d13xzAAAAAElFTkSuQmCC); + } } /* Fancy CSS END */ diff --git a/share/pdf2htmlEX.min.js b/share/pdf2htmlEX.min.js deleted file mode 100644 index 4aa848e..0000000 --- a/share/pdf2htmlEX.min.js +++ /dev/null @@ -1,934 +0,0 @@ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab filetype=javascript : */ -/** - * @license pdf2htmlEX.js: Core UI functions for pdf2htmlEX - * Copyright 2012,2013 Lu Wang and other contributors - * https://github.com/coolwanglu/pdf2htmlEX/blob/master/share/LICENSE - */ - -/* - * Attention: - * This files is to be optimized by closure-compiler, - * so pay attention to the forms of property names: - * - * string/bracket form is safe, won't be optimized: - * var obj={ 'a':'b' }; obj['a'] = 'b'; - * name/dot form will be optimized, the name is likely to be modified: - * var obj={ a:'b' }; obj.a = 'b'; - * - * Either form can be used for internal objects, - * but must be consistent for each one respectively. - * - * string/bracket form must be used for external objects - * e.g. DEFAULT_CONFIG, object stored in page-data - * property names are part of the `protocol` in these cases. - * - */ - -'use strict'; - -var pdf2htmlEX = window['pdf2htmlEX'] = window['pdf2htmlEX'] || {}; - -/** - * @const - * @struct - */ -var CSS_CLASS_NAMES = { - page_frame : 'pf', - page_content_box : 'pc', - page_data : 'pi', - background_image : 'bi', - link : 'l', - __dummy__ : 'no comma' -}; - -/** - * configurations of Viewer - * @const - * @dict - */ -var DEFAULT_CONFIG = { - // id of the element to put the pages in - 'container_id' : 'page-container', - // id of the element for sidebar (to open and close) - 'sidebar_id' : 'sidebar', - // id of the element for outline - 'outline_id' : 'outline', - // class for the loading indicator - 'loading_indicator_cls' : 'loading-indicator', - // How many page shall we preload that are below the last visible page - 'preload_pages' : 3, - // how many ms should we wait before actually rendering the pages and after a scroll event - 'render_timeout' : 100, - // zoom ratio step for each zoom in/out event - 'scale_step' : 0.9, - // register global key handler - 'key_handler' : true, - // register hashchange handler - 'hashchange_handler' : true, - - '__dummy__' : 'no comma' -}; - -/** @const */ -var EPS = 1e-6; - -/************************************/ -/* utility function */ -/** - * @param{Array.} ctm - */ -function invert(ctm) { - var det = ctm[0] * ctm[3] - ctm[1] * ctm[2]; - return [ ctm[3] / det - ,-ctm[1] / det - ,-ctm[2] / det - ,ctm[0] / det - ,(ctm[2] * ctm[5] - ctm[3] * ctm[4]) / det - ,(ctm[1] * ctm[4] - ctm[0] * ctm[5]) / det - ]; -}; -/** - * @param{Array.} ctm - * @param{Array.} pos - */ -function transform(ctm, pos) { - return [ctm[0] * pos[0] + ctm[2] * pos[1] + ctm[4] - ,ctm[1] * pos[0] + ctm[3] * pos[1] + ctm[5]]; -}; - -/** - * @param{Element} ele - */ -function get_page_number(ele) { - return parseInt(ele.getAttribute('data-page-no'), 16); -}; - -/** - * @param{NodeList} eles - */ -function disable_dragstart(eles) { - for (var i = 0, l = eles.length; i < l; ++i) { - eles[i].addEventListener('dragstart', function() { - return false; - }, false); - } -}; - -/** - * @param{...Object} var_args - */ -function clone_and_extend_objs(var_args) { - var result_obj = {}; - for (var i = 0, l = arguments.length; i < l; ++i) { - var cur_obj = arguments[i]; - for (var k in cur_obj) { - if (cur_obj.hasOwnProperty(k)) { - result_obj[k] = cur_obj[k]; - } - } - } - return result_obj; -}; - -/** - * @constructor - * @param{Element} page The element for the page - */ -function Page(page) { - if (!page) return; - - this.loaded = false; - this.shown = false; - this.page = page; // page frame element - - this.num = get_page_number(page); - - // page size - // Need to make rescale work when page_content_box is not loaded, yet - this.original_height = page.clientHeight; - this.original_width = page.clientWidth; - - // content box - var content_box = page.getElementsByClassName(CSS_CLASS_NAMES.page_content_box)[0]; - - // if page is loaded - if (content_box) { - this.content_box = content_box; - /* - * scale ratios - * - * original_scale : the first one - * cur_scale : currently using - */ - this.original_scale = this.cur_scale = this.original_height / content_box.clientHeight; - this.page_data = JSON.parse(page.getElementsByClassName(CSS_CLASS_NAMES.page_data)[0].getAttribute('data-data')); - - this.ctm = this.page_data['ctm']; - this.ictm = invert(this.ctm); - - this.loaded = true; - } -}; -Page.prototype = { - /* hide & show are for contents, the page frame is still there */ - hide : function(){ - if (this.loaded && this.shown) { - this.content_box.classList.remove('opened'); - this.shown = false; - } - }, - show : function(){ - if (this.loaded && !this.shown) { - this.content_box.classList.add('opened'); - this.shown = true; - } - }, - /** - * @param{number} ratio - */ - rescale : function(ratio) { - if (ratio === 0) { - // reset scale - this.cur_scale = this.original_scale; - } else { - this.cur_scale = ratio; - } - - // scale the content box - if (this.loaded) { - var cbs = this.content_box.style; - cbs.msTransform = cbs.webkitTransform = cbs.transform = 'scale('+this.cur_scale.toFixed(3)+')'; - } - - // stretch the page frame to hold the place - { - var ps = this.page.style; - ps.height = (this.original_height * this.cur_scale) + 'px'; - ps.width = (this.original_width * this.cur_scale) + 'px'; - } - }, - /* - * return the coordinate of the top-left corner of container - * in our coordinate system - * assuming that p.parentNode === p.offsetParent - */ - view_position : function () { - var p = this.page; - var c = p.parentNode; - return [c.scrollLeft - p.offsetLeft - p.clientLeft - ,c.scrollTop - p.offsetTop - p.clientTop]; - }, - height : function () { - return this.page.clientHeight; - }, - width : function () { - return this.page.clientWidth; - } -}; - -/** - * @constructor - * @param{Object=} config - */ -function Viewer(config) { - this.config = clone_and_extend_objs(DEFAULT_CONFIG, (arguments.length > 0 ? config : {})); - this.pages_loading = []; - this.init_before_loading_content(); - - var self = this; - document.addEventListener('DOMContentLoaded', function(){ - self.init_after_loading_content(); - }, false); -}; - -Viewer.prototype = { - scale : 1, - /* - * index of the active page (the one with largest visible area) - * which estimates the page currently being viewed - */ - cur_page_idx : 0, - - /* - * index of the first visible page - * used when determining current view - */ - first_page_idx : 0, - - init_before_loading_content : function() { - /* hide all pages before loading, will reveal only visible ones later */ - this.pre_hide_pages(); - }, - - initialize_radio_button : function() { - var elements = document.getElementsByClassName('ir'); - - for(var i = 0; i < elements.length; i++) { - var r = elements[i]; - - r.addEventListener('click', function() { - if(this.className.search("checked") == -1) - this.className += " checked"; - else - this.className = "ir"; - }); - } - }, - - init_after_loading_content : function() { - this.initialize_radio_button(); - - this.sidebar = document.getElementById(this.config['sidebar_id']); - this.outline = document.getElementById(this.config['outline_id']); - this.container = document.getElementById(this.config['container_id']); - this.loading_indicator = document.getElementsByClassName(this.config['loading_indicator_cls'])[0]; - - - { - // Open the outline if nonempty - var empty = true; - var nodes = this.outline.childNodes; - for (var i = 0, l = nodes.length; i < l; ++i) { - var cur_node = nodes[i]; - if (cur_node.nodeName.toLowerCase() === 'ul') { - empty = false; - break; - } - } - if (!empty) - this.sidebar.classList.add('opened'); - } - - this.find_pages(); - // do nothing if there's nothing - if(this.pages.length == 0) return; - - // disable dragging of background images - disable_dragstart(document.getElementsByClassName(CSS_CLASS_NAMES.background_image)); - - if (this.config['key_handler']) - this.register_key_handler(); - - var self = this; - - if (this.config['hashchange_handler']) { - window.addEventListener('hashchange', function(e) { - self.navigate_to_dest(document.location.hash.substring(1)); - }, false); - } - - // register schedule rendering - // renew old schedules since scroll() may be called frequently - this.container.addEventListener('scroll', function() { - self.update_page_idx(); - self.schedule_render(true); - }, false); - - // handle links - [this.container, this.outline].forEach(function(ele) { - ele.addEventListener('click', self.link_handler.bind(self), false); - }); - - this.render(); - }, - - /* - * set up this.pages and this.page_map - * pages is an array holding all the Page objects - * page-Map maps an original page number (in PDF) to the corresponding index in page - */ - find_pages : function() { - var new_pages = []; - var new_page_map = {}; - var nodes = this.container.childNodes; - for (var i = 0, l = nodes.length; i < l; ++i) { - var cur_node = nodes[i]; - if ((cur_node.nodeType === Node.ELEMENT_NODE) - && cur_node.classList.contains(CSS_CLASS_NAMES.page_frame)) { - var p = new Page(cur_node); - new_pages.push(p); - new_page_map[p.num] = new_pages.length - 1; - } - } - this.pages = new_pages; - this.page_map = new_page_map; - }, - - /** - * @param{number} idx - * @param{number=} pages_to_preload - * @param{function(Page)=} callback - * - * TODO: remove callback -> promise ? - */ - load_page : function(idx, pages_to_preload, callback) { - var pages = this.pages; - if (idx >= pages.length) - return; // Page does not exist - - var cur_page = pages[idx]; - if (cur_page.loaded) - return; // Page is loaded - - if (this.pages_loading[idx]) - return; // Page is already loading - - var cur_page_ele = cur_page.page; - var url = cur_page_ele.getAttribute('data-page-url'); - if (url) { - this.pages_loading[idx] = true; // set semaphore - - // add a copy of the loading indicator - var new_loading_indicator = this.loading_indicator.cloneNode(); - new_loading_indicator.classList.add('active'); - cur_page_ele.appendChild(new_loading_indicator); - - // load data - { - var self = this; - var _idx = idx; - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.onload = function(){ - if (xhr.status === 200 || xhr.status === 0) { - // find the page element in the data - var div = document.createElement('div'); - div.innerHTML = xhr.responseText; - - var new_page = null; - var nodes = div.childNodes; - for (var i = 0, l = nodes.length; i < l; ++i) { - var cur_node = nodes[i]; - if ((cur_node.nodeType === Node.ELEMENT_NODE) - && cur_node.classList.contains(CSS_CLASS_NAMES.page_frame)) { - new_page = cur_node; - break; - } - } - - // replace the old page with loaded data - // the loading indicator on this page should also be destroyed - var p = self.pages[_idx]; - self.container.replaceChild(new_page, p.page); - p = new Page(new_page); - self.pages[_idx] = p; - - p.hide(); - p.rescale(self.scale); - - // disable background image dragging - disable_dragstart(new_page.getElementsByClassName(CSS_CLASS_NAMES.background_image)); - - self.schedule_render(false); - - if (callback){ callback(p); } - } - - // Reset loading token - delete self.pages_loading[_idx]; - }; - xhr.send(null); - } - } - // Concurrent prefetch of the next pages - if (pages_to_preload === undefined) - pages_to_preload = this.config['preload_pages']; - - if (--pages_to_preload > 0) { - var self = this; - setTimeout(function() { - self.load_page(idx+1, pages_to_preload); - },0); - } - }, - - /* - * Hide all pages that have no 'opened' class - * The 'opened' class will be added to visible pages by JavaScript - * We cannot add this in the default CSS because JavaScript may be disabled - */ - pre_hide_pages : function() { - /* pages might have not been loaded yet, so add a CSS rule */ - var s = '@media screen{.'+CSS_CLASS_NAMES.page_content_box+'{display:none;}}'; - var n = document.createElement('style'); - if (n.styleSheet) { - n.styleSheet.cssText = s; - } else { - n.appendChild(document.createTextNode(s)); - } - document.head.appendChild(n); - }, - - /* - * show visible pages and hide invisible pages - */ - render : function () { - var container = this.container; - /* - * show the pages that are 'nearly' visible -- it's right above or below the container - * - * all the y values are in the all-page element's coordinate system - */ - var container_min_y = container.scrollTop; - var container_height = container.clientHeight; - var container_max_y = container_min_y + container_height; - var visible_min_y = container_min_y - container_height; - var visible_max_y = container_max_y + container_height; - - var cur_page_fully_visible = false; - var cur_page_idx = this.cur_page_idx; - var max_visible_page_idx = cur_page_idx; - var max_visible_ratio = 0.0; - - var pl = this.pages; - for (var i = 0, l = pl.length; i < l; ++i) { - var cur_page = pl[i]; - var cur_page_ele = cur_page.page; - var page_min_y = cur_page_ele.offsetTop + cur_page_ele.clientTop; - var page_height = cur_page_ele.clientHeight; - var page_max_y = page_min_y + page_height; - if ((page_min_y <= visible_max_y) && (page_max_y >= visible_min_y)) - { - // cur_page is 'nearly' visible, show it or load it - if (cur_page.loaded) { - cur_page.show(); - } else { - this.load_page(i); - } - } else { - cur_page.hide(); - } - } - }, - /* - * update cur_page_idx and first_page_idx - * normally called upon scrolling - */ - update_page_idx: function () { - var pages = this.pages; - var pages_len = pages.length; - // there is no chance that cur_page_idx or first_page_idx is modified - if (pages_len < 2) return; - - var container = this.container; - var container_min_y = container.scrollTop; - var container_max_y = container_min_y + container.clientHeight; - - // binary search for the first page - // whose bottom border is below the top border of the container - var first_idx = -1; - var last_idx = pages_len; - var rest_len = last_idx - first_idx; - // TODO: use current first_page_idx as a hint? - while(rest_len > 1) { - var idx = first_idx + Math.floor(rest_len / 2); - var cur_page_ele = pages[idx].page; - if (cur_page_ele.offsetTop + cur_page_ele.clientTop + cur_page_ele.clientHeight >= container_min_y) { - last_idx = idx; - } else { - first_idx = idx; - } - rest_len = last_idx - first_idx; - } - - /* - * with malformed settings it is possible that no page is visible, e.g. - * - the container is to thin, which lies in the margin between two pages - * - all pages are completely above or below the container - * but we just assume that they won't happen. - */ - this.first_page_idx = last_idx; - - // find the page with largest visible area - var cur_page_idx = this.cur_page_idx; - var max_visible_page_idx = cur_page_idx; - var max_visible_ratio = 0.0; - - for(var i = last_idx; i < pages_len; ++i) { - var cur_page_ele = pages[i].page; - var page_min_y = cur_page_ele.offsetTop + cur_page_ele.clientTop; - var page_height = cur_page_ele.clientHeight; - var page_max_y = page_min_y + page_height; - if (page_min_y > container_max_y) break; - - // check the visible fraction of the page - var page_visible_ratio = ( Math.min(container_max_y, page_max_y) - - Math.max(container_min_y, page_min_y) - ) / page_height; - - // stay with the current page if it is still fully visible - if ((i === cur_page_idx) && (Math.abs(page_visible_ratio - 1.0) <= EPS)) { - max_visible_page_idx = cur_page_idx; - break; - } - - if (page_visible_ratio > max_visible_ratio) { - max_visible_ratio = page_visible_ratio; - max_visible_page_idx = i; - } - } - - this.cur_page_idx = max_visible_page_idx; - }, - - /** - * @param{boolean} renew renew the existing schedule instead of using the old one - */ - schedule_render : function(renew) { - if (this.render_timer !== undefined) { - if (!renew) return; - clearTimeout(this.render_timer); - } - - var self = this; - this.render_timer = setTimeout(function () { - /* - * render() may trigger load_page(), which may in turn trigger another render() - * so delete render_timer first - */ - delete self.render_timer; - self.render(); - }, this.config['render_timeout']); - }, - - /* - * Handling key events, zooming, scrolling etc. - */ - register_key_handler: function () { - /* - * When user try to zoom in/out using ctrl + +/- or mouse wheel - * handle this and prevent the default behaviours - * - * Code credit to PDF.js - */ - var self = this; - - // Firefox specific event, so that we can prevent browser from zooming - window.addEventListener('DOMMouseScroll', function(e) { - if (e.ctrlKey) { - e.preventDefault(); - var container = self.container; - var rect = container.getBoundingClientRect(); - var fixed_point = [e.clientX - rect['left'] - container.clientLeft - ,e.clientY - rect['top'] - container.clientTop]; - self.rescale(Math.pow(self.config['scale_step'], e.detail), true, fixed_point); - } - }, false); - - window.addEventListener('keydown', function(e) { - var handled = false; - /* - var cmd = (e.ctrlKey ? 1 : 0) - | (e.altKey ? 2 : 0) - | (e.shiftKey ? 4 : 0) - | (e.metaKey ? 8 : 0) - ; - */ - var with_ctrl = e.ctrlKey || e.metaKey; - var with_alt = e.altKey; - switch (e.keyCode) { - case 61: // FF/Mac '=' - case 107: // FF '+' and '=' - case 187: // Chrome '+' - if (with_ctrl){ - self.rescale(1.0 / self.config['scale_step'], true); - handled = true; - } - break; - case 173: // FF/Mac '-' - case 109: // FF '-' - case 189: // Chrome '-' - if (with_ctrl){ - self.rescale(self.config['scale_step'], true); - handled = true; - } - break; - case 48: // '0' - if (with_ctrl){ - self.rescale(0, false); - handled = true; - } - break; - case 33: // Page UP: - if (with_alt) { // alt-pageup -> scroll one page up - self.scroll_to(self.cur_page_idx - 1); - } else { // pageup -> scroll one screen up - self.container.scrollTop -= self.container.clientHeight; - } - handled = true; - break; - case 34: // Page DOWN - if (with_alt) { // alt-pagedown -> scroll one page down - self.scroll_to(self.cur_page_idx + 1); - } else { // pagedown -> scroll one screen down - self.container.scrollTop += self.container.clientHeight; - } - handled = true; - break; - case 35: // End - self.container.scrollTop = self.container.scrollHeight; - handled = true; - break; - case 36: // Home - self.container.scrollTop = 0; - handled = true; - break; - } - if (handled) { - e.preventDefault(); - return; - } - }, false); - }, - - /** - * @param{number} ratio - * @param{boolean} is_relative - * @param{Array.=} fixed_point preserve the position (relative to the top-left corner of the viewer) after rescaling - */ - rescale : function (ratio, is_relative, fixed_point) { - var old_scale = this.scale; - var new_scale = old_scale; - // set new scale - if (ratio === 0) { - new_scale = 1; - is_relative = false; - } else if (is_relative) - new_scale *= ratio; - else - new_scale = ratio; - - this.scale = new_scale; - - if (!fixed_point) - fixed_point = [0,0]; - - // translate fixed_point to the coordinate system of all pages - var container = this.container; - fixed_point[0] += container.scrollLeft; - fixed_point[1] += container.scrollTop; - - // find the visible page that contains the fixed point - // if the fixed point lies between two pages (including their borders), it's contained in the first one - var pl = this.pages; - var pl_len = pl.length; - for (var i = this.first_page_idx; i < pl_len; ++i) { - var p = pl[i].page; - if (p.offsetTop + p.clientTop >= fixed_point[1]) - break; - } - var fixed_point_page_idx = i - 1; - - // determine the new scroll position - // each-value consists of two parts, one inside the page, which is affected by rescaling, - // the other is outside, (e.g. borders and margins), which is not affected - - // if the fixed_point is above the first page, use the first page as the reference - if (fixed_point_page_idx < 0) - fixed_point_page_idx = 0; - - var fp_p = pl[fixed_point_page_idx].page; - var fp_p_width = fp_p.clientWidth; - var fp_p_height = fp_p.clientHeight; - - var fp_x_ref = fp_p.offsetLeft + fp_p.clientLeft; - var fp_x_inside = fixed_point[0] - fp_x_ref; - if (fp_x_inside < 0) - fp_x_inside = 0; - else if (fp_x_inside > fp_p_width) - fp_x_inside = fp_p_width; - - var fp_y_ref = fp_p.offsetTop + fp_p.clientTop; - var fp_y_inside = fixed_point[1] - fp_y_ref; - if (fp_y_inside < 0) - fp_y_inside = 0; - else if (fp_y_inside > fp_p_height) - fp_y_inside = fp_p_height; - - // Rescale pages - for (var i = 0; i < pl_len; ++i) - pl[i].rescale(new_scale); - - // Correct container scroll to keep view aligned while zooming - container.scrollLeft += fp_x_inside / old_scale * new_scale + fp_p.offsetLeft + fp_p.clientLeft - fp_x_inside - fp_x_ref; - container.scrollTop += fp_y_inside / old_scale * new_scale + fp_p.offsetTop + fp_p.clientTop - fp_y_inside - fp_y_ref; - - // some pages' visibility may be toggled, wait for next render() - // renew old schedules since rescale() may be called frequently - this.schedule_render(true); - }, - - fit_width : function () { - var page_idx = this.cur_page_idx; - this.rescale(this.container.clientWidth / this.pages[page_idx].width(), false); - this.scroll_to(page_idx); - }, - - fit_height : function () { - var page_idx = this.cur_page_idx; - this.rescale(this.container.clientHeight / this.pages[page_idx].height(), false); - this.scroll_to(page_idx); - }, - /** - * @param{Node} ele - */ - get_containing_page : function(ele) { - /* get the page obj containing obj */ - while(ele) { - if ((ele.nodeType === Node.ELEMENT_NODE) - && ele.classList.contains(CSS_CLASS_NAMES.page_frame)) { - /* - * Get original page number and map it to index of pages - * TODO: store the index on the dom element - */ - var pn = get_page_number(/** @type{Element} */(ele)); - var pm = this.page_map; - return (pn in pm) ? this.pages[pm[pn]] : null; - } - ele = ele.parentNode; - } - return null; - }, - - /** - * @param{Event} e - */ - link_handler : function (e) { - var target = /** @type{Node} */(e.target); - var detail_str = /** @type{string} */ (target.getAttribute('data-dest-detail')); - if (!detail_str) return; - - this.navigate_to_dest(detail_str, this.get_containing_page(target)); - e.preventDefault(); - }, - - /** - * @param{string} detail_str may come from user provided hashtag, need sanitzing - * @param{Page=} src_page page containing the source event (e.g. link) - */ - navigate_to_dest : function(detail_str, src_page) { - try { - var detail = JSON.parse(detail_str); - } catch(e) { - return; - } - - if(!(detail instanceof Array)) return; - - var target_page_no = detail[0]; - var page_map = this.page_map; - if (!(target_page_no in page_map)) return; - var target_page_idx = page_map[target_page_no]; - var target_page = this.pages[target_page_idx]; - - for (var i = 2, l = detail.length; i < l; ++i) { - var d = detail[i]; - if(!((d === null) || (typeof d === 'number'))) - return; - } - - while(detail.length < 6) - detail.push(null); - - // cur_page might be undefined, e.g. from Outline - var cur_page = src_page || this.pages[this.cur_page_idx]; - - var cur_pos = cur_page.view_position(); - cur_pos = transform(cur_page.ictm, [cur_pos[0], cur_page.height()-cur_pos[1]]); - - var zoom = this.scale; - var pos = [0,0]; - var upside_down = true; - var ok = false; - - // position specified in `detail` are in the raw coordinate system of the page (unscaled) - var scale = this.scale; - // TODO: fitb* - // TODO: BBox - switch(detail[1]) { - case 'XYZ': - pos = [ (detail[2] === null) ? cur_pos[0] : detail[2] * scale - , (detail[3] === null) ? cur_pos[1] : detail[3] * scale ]; - zoom = detail[4]; - if ((zoom === null) || (zoom === 0)) - zoom = this.scale; - ok = true; - break; - case 'Fit': - case 'FitB': - pos = [0,0]; - ok = true; - break; - case 'FitH': - case 'FitBH': - pos = [0, (detail[2] === null) ? cur_pos[1] : detail[2] * scale]; - ok = true; - break; - case 'FitV': - case 'FitBV': - pos = [(detail[2] === null) ? cur_pos[0] : detail[2] * scale, 0]; - ok = true; - break; - case 'FitR': - /* locate the top-left corner of the rectangle */ - // TODO - pos = [detail[2] * scale, detail[5] * scale]; - upside_down = false; - ok = true; - break; - default: - break; - } - - if (!ok) return; - - this.rescale(zoom, false); - - - var self = this; - /** - * page should of type Page - * @param{Page} page - */ - var transform_and_scroll = function(page) { - pos = transform(page.ctm, pos); - if (upside_down) { - pos[1] = page.height() - pos[1]; - } - self.scroll_to(target_page_idx, pos); - }; - - if (target_page.loaded) { - transform_and_scroll(target_page); - } else { - // TODO: scroll_to may finish before load_page - - // Scroll to the exact position once loaded. - this.load_page(target_page_idx, undefined, transform_and_scroll); - - // In the meantime page gets loaded, scroll approximately position for maximum responsiveness. - this.scroll_to(target_page_idx); - } - }, - - /** - * @param{number} page_idx - * @param{Array.=} pos [x,y] where (0,0) is the top-left corner - */ - scroll_to : function(page_idx, pos) { - var pl = this.pages; - if ((page_idx < 0) || (page_idx >= pl.length)) return; - var target_page = pl[page_idx]; - var cur_target_pos = target_page.view_position(); - - if (pos === undefined) - pos = [0,0]; - - var container = this.container; - container.scrollLeft += pos[0] - cur_target_pos[0]; - container.scrollTop += pos[1] - cur_target_pos[1]; - } -}; - -// export pdf2htmlEX.Viewer -pdf2htmlEX['Viewer'] = Viewer; diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index 6335d6e..d47e91c 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -169,7 +169,7 @@ protected: void process_outline(void); void process_outline_items(GooList * items); - void process_form(std::ostream & out); + void process_form(std::ofstream & out); void set_stream_flags (std::ostream & out); diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 72e6fdf..5ac3054 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -17,10 +17,10 @@ namespace pdf2htmlEX { -using std::ostream; +using std::ofstream; using std::cerr; -void HTMLRenderer::process_form(ostream & out) +void HTMLRenderer::process_form(ofstream & out) { FormPageWidgets * widgets = cur_catalog->getPage(pageNum)->getFormWidgets(); int num = widgets->getNumWidgets(); @@ -28,8 +28,8 @@ void HTMLRenderer::process_form(ostream & out) for(int i = 0; i < num; i++) { FormWidget * w = widgets->getWidget(i); - double x1, y1, x2, y2; - int width, height, font_size; + double x1, y1, x2, y2, width, font_size; + int height; w->getRect(&x1, &y1, &x2, &y2); x1 = x1 * param.zoom; @@ -44,13 +44,15 @@ void HTMLRenderer::process_form(ostream & out) { font_size = height / 2; - out << "" << endl; + out + << "" << endl; } if(w->getType() == formButton) @@ -58,12 +60,13 @@ void HTMLRenderer::process_form(ostream & out) width += 3; height += 3; - out << "
" << endl; + out + << "
" << endl; } } diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index a370a15..6c17ef5 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -253,7 +253,7 @@ void HTMLRenderer::endPage() { html_text_page.clear(); // process form - if(param.process_forms) + if(param.process_form) process_form(*f_curpage); // process links before the page is closed diff --git a/src/Param.h b/src/Param.h index eea1bd9..84fa426 100644 --- a/src/Param.h +++ b/src/Param.h @@ -38,7 +38,7 @@ struct Param int process_nontext; int process_outline; int process_annotation; - int process_forms; + int process_form; int correct_text_visibility; int printing; int fallback; diff --git a/src/css_class_names.cmakelists.txt b/src/css_class_names.cmakelists.txt index 19c6f8b..067d95a 100644 --- a/src/css_class_names.cmakelists.txt +++ b/src/css_class_names.cmakelists.txt @@ -36,3 +36,4 @@ set(CSS_CSS_DRAW_CN "d") # Draw set(CSS_LINK_CN "l") # Link set(CSS_INPUT_TEXT_CN "it") # Text input set(CSS_INPUT_RADIO_CN "ir") # Radio button +set(CSS_RADIO_CHECKED_CN "checked") # Show picture of checked out radio button diff --git a/src/pdf2htmlEX.cc b/src/pdf2htmlEX.cc index aa17b59..53a96ed 100644 --- a/src/pdf2htmlEX.cc +++ b/src/pdf2htmlEX.cc @@ -164,7 +164,7 @@ void parse_options (int argc, char **argv) .add("process-nontext", ¶m.process_nontext, 1, "render graphics in addition to text") .add("process-outline", ¶m.process_outline, 1, "show outline in HTML") .add("process-annotation", ¶m.process_annotation, 0, "show annotation in HTML") - .add("process-forms", ¶m.process_forms, 0, "include text fields and radio buttons") + .add("process-form", ¶m.process_form, 0, "include text fields and radio buttons") .add("printing", ¶m.printing, 1, "enable printing support") .add("fallback", ¶m.fallback, 0, "output in fallback mode") .add("tmp-file-size-limit", ¶m.tmp_file_size_limit, -1, "Maximum size (in KB) used by temporary files, -1 for no limit.") diff --git a/src/util/css_const.h.in b/src/util/css_const.h.in index 795ed10..08c23fc 100644 --- a/src/util/css_const.h.in +++ b/src/util/css_const.h.in @@ -58,6 +58,7 @@ const char * const LINK_CN = "@CSS_LINK_CN@"; const char * const INPUT_TEXT_CN = "@CSS_INPUT_TEXT_CN@"; const char * const INPUT_RADIO_CN = "@CSS_INPUT_RADIO_CN@"; +const char * const RADIO_CHECKED_CN = "@CSS_RADIO_CHECKED_CN@"; } } From 87bc6c06d4b3a12e2afbb34cc7da31c51f6517b0 Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Wed, 3 Dec 2014 14:31:38 -0500 Subject: [PATCH 06/10] small CSS fix for the radio button image --- src/HTMLRenderer/form.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 5ac3054..b8b0521 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -65,7 +65,7 @@ void HTMLRenderer::process_form(ofstream & out) << " style=\"position: absolute; left: " << x1 << "px; bottom: " << y1 << "px;" << " width: " << width << "px; height: " - << std::to_string(height) << "px; \" class=\"" + << std::to_string(height) << "px; background-size: cover;\" class=\"" << CSS::INPUT_RADIO_CN << "\">" << endl; } From f284a8aabe171cc61e96c93a4497df24ce1d7b14 Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Thu, 18 Dec 2014 10:49:53 -0500 Subject: [PATCH 07/10] added tests for the process-form flag --- test/browser_tests.py | 7 +- test/browser_tests/with_form.pdf | Bin 0 -> 92273 bytes test/browser_tests/with_form/bg1.png | Bin 0 -> 9334 bytes test/browser_tests/with_form/f1.woff | Bin 0 -> 6396 bytes test/browser_tests/with_form/f2.woff | Bin 0 -> 3700 bytes test/browser_tests/with_form/f3.woff | Bin 0 -> 5004 bytes test/browser_tests/with_form/f4.woff | Bin 0 -> 10796 bytes test/browser_tests/with_form/f5.woff | Bin 0 -> 5972 bytes test/browser_tests/with_form/f6.woff | Bin 0 -> 6600 bytes test/browser_tests/with_form/with_form.html | 415 ++++++++++++++++++++ 10 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 test/browser_tests/with_form.pdf create mode 100644 test/browser_tests/with_form/bg1.png create mode 100644 test/browser_tests/with_form/f1.woff create mode 100644 test/browser_tests/with_form/f2.woff create mode 100644 test/browser_tests/with_form/f3.woff create mode 100644 test/browser_tests/with_form/f4.woff create mode 100644 test/browser_tests/with_form/f5.woff create mode 100644 test/browser_tests/with_form/f6.woff create mode 100644 test/browser_tests/with_form/with_form.html diff --git a/test/browser_tests.py b/test/browser_tests.py index c6cbba4..0db5cf5 100644 --- a/test/browser_tests.py +++ b/test/browser_tests.py @@ -44,7 +44,7 @@ class BrowserTests(Common): os.path.join(self.TEST_DATA_DIR, filename), htmlfilename ] - + result = self.run_pdf2htmlEX(pdf2htmlEX_args) self.assertIn(htmlfilename, result['output_files'], 'HTML file is not generated') @@ -76,7 +76,7 @@ class BrowserTests(Common): @unittest.skipIf(Common.GENERATING_MODE, 'Do not auto generate reference for test_fail') def test_fail(self): - # The HTML reference is generated manually, which mismatches the PDF + # The HTML reference is generated manually, which mismatches the PDF # To test if the environment can detect any errors # E.g. when network is down, 404 message is shown for any HTML message with self.assertRaises(AssertionError): @@ -91,3 +91,6 @@ class BrowserTests(Common): def test_text_visibility(self): self.run_test_case('text_visibility.pdf', ['--correct-text-visibility', 1]) + def test_process_form(self): + self.run_test_case('with_form.pdf', ['--process-form', 1]) + diff --git a/test/browser_tests/with_form.pdf b/test/browser_tests/with_form.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e491abfd4adbdf25493fb17ea11960d6297974c8 GIT binary patch literal 92273 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 KDW@S%`2PVAGq2YG literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/bg1.png b/test/browser_tests/with_form/bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..4528d03bfafcd1844e467fdecbab98fb0e09ddf2 GIT binary patch literal 9334 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 literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/f1.woff b/test/browser_tests/with_form/f1.woff new file mode 100644 index 0000000000000000000000000000000000000000..639534ba64eece4773fbbffdc982d9783633c7b5 GIT binary patch literal 6396 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 NJAvOu$j|_Q{{go_!XW?v literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/f2.woff b/test/browser_tests/with_form/f2.woff new file mode 100644 index 0000000000000000000000000000000000000000..18d9ceebf8c211895460abfefd24583fffb35428 GIT binary patch literal 3700 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 aiX;{u{+WF0;eK)AqX5)#W?m%!H~$5Q4EwkM literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/f4.woff b/test/browser_tests/with_form/f4.woff new file mode 100644 index 0000000000000000000000000000000000000000..82c8772daf223928f99e7120cc859862b05dbe48 GIT binary patch literal 10796 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 literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/f6.woff b/test/browser_tests/with_form/f6.woff new file mode 100644 index 0000000000000000000000000000000000000000..b76a45e56ffca0c1b525b9be0dfdcefad17c58b2 GIT binary patch literal 6600 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 Gxc>urT0?~Z literal 0 HcmV?d00001 diff --git a/test/browser_tests/with_form/with_form.html b/test/browser_tests/with_form/with_form.html new file mode 100644 index 0000000..4064028 --- /dev/null +++ b/test/browser_tests/with_form/with_form.html @@ -0,0 +1,415 @@ + + + + + + + + + + + + + +

+
Éditions « À Reproduire » Internet : www.envolee.com
Question de textes 4
7
Nom
Mona veut un chien
4 Que veut dire la mère de Mona quand elle dit : « C’est beaucoup de travail, avoir un chien » ?
a) Mona doit faire plus de recherche avant d’être prête à avoir un chien.
b) Les chiens travaillent fort afi n d’être de bons animaux de compagnie pour les gens.
c) Les chiens ont besoin de nourriture et d’exercice. Il faut aussi ramasser leurs dégâts.
d) Mona devra se reposer plus si elle a un chien.
5 Comment Mona a-t-elle acquis autant de connaissances sur les chiens ?
a) En écoutant son enseignante à l’école.
b) En visitant un site Web.
c) En écrivant à la Société protectrice des animaux.
d) En regardant une vidéo sur les chiens.
6 Pourquoi Mona veut-elle un Jack Russell ?
7 Que devra faire Mona même si elle est fatiguée ou qu’il pleut ?
8 Décris physiquement le chien que Mona veut choisir.
9 Quand fait-elle ses recherches sur le Web ?
10 Que contient le site Web préféré de Mona ? Nomme deux éléments.
REPÉRAGE
+
+
+
+
+ + + + + + +
+
+
+
+ +
+
+ + From db10f6744a90fa6ce8da3c251ec65a1210f80fd2 Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Fri, 16 Jan 2015 15:23:38 -0500 Subject: [PATCH 08/10] added mention when encountering unsupported field + some stylistic changes --- share/pdf2htmlEX.js.in | 9 ++++---- src/HTMLRenderer/form.cc | 44 ++++++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/share/pdf2htmlEX.js.in b/share/pdf2htmlEX.js.in index 118c8d6..2b22d45 100644 --- a/share/pdf2htmlEX.js.in +++ b/share/pdf2htmlEX.js.in @@ -267,17 +267,15 @@ Viewer.prototype = { var r = elements[i]; r.addEventListener('click', function() { - if(this.className.search("checked") == -1) - this.className += " checked"; + if(!this.classList.contains("checked")) + this.classList.add("checked"); else - this.className = "ir"; + this.classList.remove("checked"); }); } }, init_after_loading_content : function() { - this.initialize_radio_button(); - this.sidebar = document.getElementById(this.config['sidebar_id']); this.outline = document.getElementById(this.config['outline_id']); this.container = document.getElementById(this.config['container_id']); @@ -329,6 +327,7 @@ Viewer.prototype = { ele.addEventListener('click', self.link_handler.bind(self), false); }); + this.initialize_radio_button(); this.render(); }, diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index b8b0521..9acff2c 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -44,30 +44,34 @@ void HTMLRenderer::process_form(ofstream & out) { font_size = height / 2; - out - << "" << endl; - } - - if(w->getType() == formButton) + out << "" << endl; + } + else if(w->getType() == formButton) { + //Ideally would check w->getButtonType() + //for more specific rendering width += 3; height += 3; - out - << "
" << endl; - + out << "
" << endl; + } + else if(w->getType() == formChoice || + w->getType() == formSignature || + w->getType() == formUndef) + { + cerr << "Unsupported form field detected" << endl; } } } From 54781e0523401beaeff6b38cedf2a12426454daa Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Mon, 26 Jan 2015 10:20:00 -0500 Subject: [PATCH 09/10] include-forms option : a few style changes --- AUTHORS | 1 + share/pdf2htmlEX.js.in | 5 +---- src/HTMLRenderer/form.cc | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0d5c84b..30b4d98 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ Marc Sanfacon Michele Redolfi Mick Giles Ryan Morlok +Simon Chenard Wanmin Liu Packagers: diff --git a/share/pdf2htmlEX.js.in b/share/pdf2htmlEX.js.in index 2b22d45..1b00b12 100644 --- a/share/pdf2htmlEX.js.in +++ b/share/pdf2htmlEX.js.in @@ -267,10 +267,7 @@ Viewer.prototype = { var r = elements[i]; r.addEventListener('click', function() { - if(!this.classList.contains("checked")) - this.classList.add("checked"); - else - this.classList.remove("checked"); + this.classList.toggle("checked"); }); } }, diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 9acff2c..816f770 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -67,9 +67,7 @@ void HTMLRenderer::process_form(ofstream & out) << " width: " << width << "px; height: " << std::to_string(height) << "px; background-size: cover;\" >" << endl; } - else if(w->getType() == formChoice || - w->getType() == formSignature || - w->getType() == formUndef) + else { cerr << "Unsupported form field detected" << endl; } From a90ae31a8a6a832d12e16c29c75159d41320ac2d Mon Sep 17 00:00:00 2001 From: Simon Chenard Date: Tue, 27 Jan 2015 16:01:30 -0500 Subject: [PATCH 10/10] cleanup in form.cc --- src/HTMLRenderer/form.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/HTMLRenderer/form.cc b/src/HTMLRenderer/form.cc index 816f770..6b51622 100644 --- a/src/HTMLRenderer/form.cc +++ b/src/HTMLRenderer/form.cc @@ -28,8 +28,7 @@ void HTMLRenderer::process_form(ofstream & out) for(int i = 0; i < num; i++) { FormWidget * w = widgets->getWidget(i); - double x1, y1, x2, y2, width, font_size; - int height; + double x1, y1, x2, y2; w->getRect(&x1, &y1, &x2, &y2); x1 = x1 * param.zoom; @@ -37,12 +36,12 @@ void HTMLRenderer::process_form(ofstream & out) y1 = y1 * param.zoom; y2 = y2 * param.zoom; - width = x2 - x1; - height = y2 - y1; + double width = x2 - x1; + double height = y2 - y1; if(w->getType() == formText) { - font_size = height / 2; + double font_size = height / 2; out << "