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

working on CSS draw

This commit is contained in:
Lu Wang 2012-10-02 01:59:04 +08:00
parent 9014b274e0
commit 1bfe86187e
11 changed files with 229 additions and 101 deletions

View File

@ -127,6 +127,7 @@ add_executable(pdf2htmlEX
src/HTMLRenderer/export.cc
src/HTMLRenderer/text.cc
src/HTMLRenderer/image.cc
src/HTMLRenderer/draw.cc
src/HTMLRenderer/link.cc
src/include/namespace.h
src/HTMLRenderer/LineBuffer.cc

View File

@ -81,4 +81,12 @@ span {
}
.a {
}
.cr {
position:absolute;
transform-origin:0% 100%;
-ms-transform-origin:0% 100%;
-moz-transform-origin:0% 100%;
-webkit-transform-origin:0% 100%;
-o-transform-origin:0% 100%;
}
/* Base CSS END */

View File

@ -22,7 +22,7 @@ using std::ostream;
void HTMLRenderer::LineBuffer::reset(GfxState * state)
{
state->transform(state->getCurX(), state->getCurY(), &x, &y);
tm_id = renderer->cur_tm_id;
tm_id = renderer->cur_ttm_id;
}
void HTMLRenderer::LineBuffer::append_unicodes(const Unicode * u, int l)

96
src/HTMLRenderer/draw.cc Normal file
View File

@ -0,0 +1,96 @@
/*
* Draw.cc
*
* Handling path drawing
*
* by WangLu
* 2012.10.01
*/
#include "HTMLRenderer.h"
#include "util.h"
#include "namespace.h"
namespace pdf2htmlEX {
using std::swap;
static bool is_horizontal_line(GfxSubpath * path)
{
return ((path->getNumPoints() == 2)
&& (!path->getCurve(1))
&& (_equal(path->getY(0), path->getY(1))));
}
static bool is_rectangle(GfxSubpath * path)
{
if (!(((path->getNumPoints() != 4) && (path->isClosed()))
|| ((path->getNumPoints() == 5)
&& _equal(path->getX(0), path->getX(4))
&& _equal(path->getY(0), path->getY(4)))))
return false;
return (_equal(path->getY(0), path->getY(1))
&& _equal(path->getX(1), path->getX(2))
&& _equal(path->getY(2), path->getY(3))
&& _equal(path->getX(3), path->getX(0)))
|| (_equal(path->getX(0), path->getX(1))
&& _equal(path->getY(1), path->getY(2))
&& _equal(path->getX(2), path->getX(3))
&& _equal(path->getY(3), path->getY(0)));
}
//TODO track state
//TODO connection style
void HTMLRenderer::stroke(GfxState *state)
{
GfxPath * path = state->getPath();
for(int i = 0; i < path->getNumSubpaths(); ++i)
{
GfxSubpath * subpath = path->getSubpath(i);
if(is_horizontal_line(subpath))
{
close_text_line();
double x1 = subpath->getX(0);
double x2 = subpath->getX(1);
double y = subpath->getY(0);
if(x1 > x2) swap(x1, x2);
_transform(state->getCTM(), x1, y);
html_fout << "<div style=\"border:solid red;border-width:1px 0 0 0;position:absolute;bottom:"
<< _round(y) << "px;left:"
<< _round(x1) << "px;width:"
<< _round(x2-x1) << "px;height:0;\"></div>";
}
else if (is_rectangle(subpath))
{
close_text_line();
double x1 = subpath->getX(0);
double x2 = subpath->getX(2);
double y1 = subpath->getY(0);
double y2 = subpath->getY(2);
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
double x,y,w,h,w1,w2;
css_fix_rectangle_border_width(x1, y1, x2, y2, state->getLineWidth(),
x,y,w,h,w1,w2);
_transform(state->getCTM(), x, y);
html_fout << "<div class=\"cr t" << install_transform_matrix(state->getCTM())
<< "\" style=\"border:solid red;border-width:"
<< _round(w1) << "px "
<< _round(w2) << " px;left:"
<< _round(x) << "px;bottom:"
<< _round(y) << "px;width:"
<< _round(w) << "px;height:"
<< _round(h) << "px;\"></div>";
}
}
}
} // namespace pdf2htmlEX

View File

@ -225,9 +225,9 @@ void HTMLRenderer::startPage(int pageNum, GfxState *state)
cur_font_size = draw_font_size = 0;
cur_fs_id = install_font_size(cur_font_size);
memcpy(cur_ctm, id_matrix, sizeof(cur_ctm));
memcpy(draw_ctm, id_matrix, sizeof(draw_ctm));
cur_tm_id = install_transform_matrix(draw_ctm);
memcpy(cur_text_tm, id_matrix, sizeof(cur_text_tm));
memcpy(draw_text_tm, id_matrix, sizeof(draw_text_tm));
cur_ttm_id = install_transform_matrix(draw_text_tm);
cur_letter_space = cur_word_space = 0;
cur_ls_id = install_letter_space(cur_letter_space);
@ -247,7 +247,7 @@ void HTMLRenderer::startPage(int pageNum, GfxState *state)
}
void HTMLRenderer::endPage() {
close_line();
close_text_line();
// process links before the page is closed
cur_doc->processLinks(this, pageNum);
@ -404,7 +404,9 @@ void HTMLRenderer::post_process()
void HTMLRenderer::fix_stream (std::ostream & out)
{
out << hex;
// we output all ID's in hex
// browsers are not happy with scientific notations
out << hex << fixed;
}
void HTMLRenderer::add_tmp_file(const string & fn)

View File

@ -22,62 +22,6 @@ using std::ostringstream;
using std::min;
using std::max;
static void _transform(const double * ctm, double & x, double & y)
{
double xx = x, yy = y;
x = ctm[0] * xx + ctm[2] * yy + ctm[4];
y = ctm[1] * xx + ctm[3] * yy + ctm[5];
}
static void _get_transformed_rect(AnnotLink * link, const double * ctm, double & x1, double & y1, double & x2, double & y2)
{
double _x1, _x2, _y1, _y2;
link->getRect(&_x1, &_y1, &_x2, &_y2);
_transform(ctm, _x1, _y1);
_transform(ctm, _x2, _y2);
x1 = min(_x1, _x2);
x2 = max(_x1, _x2);
y1 = min(_y1, _y2);
y2 = max(_y1, _y2);
}
/*
* In PDF, edges of the rectangle are in the middle of the borders
* In HTML, edges are completely outside the rectangle
*/
static void _fix_border_width(double & x1, double & y1, double & x2, double & y2,
double border_width, double & border_top_bottom_width, double & border_left_right_width)
{
double w = x2 - x1;
if(w > border_width)
{
x1 += border_width / 2;
x2 -= border_width / 2;
border_left_right_width = border_width;
}
else
{
x1 += w / 2;
x2 -= w / 2;
border_left_right_width = border_width + w/2;
}
double h = y2 - y1;
if(h > border_width)
{
y1 += border_width / 2;
y2 -= border_width / 2;
border_top_bottom_width = border_width;
}
else
{
y1 += h / 2;
y2 -= h / 2;
border_top_bottom_width = border_width + h/2;
}
}
/*
* The detailed rectangle area of the link destination
* Will be parsed and performed by Javascript
@ -164,6 +108,7 @@ static string get_dest_detail_str(int pageno, LinkDest * dest)
/*
* Based on pdftohtml from poppler
* TODO: CSS for link rectangles
* TODO: share rectangle draw with css-draw
*/
void HTMLRenderer::processLink(AnnotLink * al)
{
@ -239,10 +184,17 @@ void HTMLRenderer::processLink(AnnotLink * al)
html_fout << ">";
}
html_fout << "<div style=\"";
html_fout << "<div class=\"cr tm"
<< install_transform_matrix(default_ctm)
<< "\" style=\"";
double x,y,w,h;
double x1, y1, x2, y2;
_get_transformed_rect(al, default_ctm, x1, y1, x2, y2);
al->getRect(&x1, &y1, &x2, &y2);
x = min(x1, x2);
y = min(y1, y2);
w = max(x1, x2) - x;
h = max(y1, y2) - y;
double border_width = 0;
double border_top_bottom_width = 0;
@ -254,8 +206,10 @@ void HTMLRenderer::processLink(AnnotLink * al)
if(border_width > 0)
{
{
_fix_border_width(x1, y1, x2, y1,
border_width, border_top_bottom_width, border_left_right_width);
css_fix_rectangle_border_width(x1, y2, x2, y2, border_width,
x, y, w, h,
border_top_bottom_width, border_left_right_width);
if(abs(border_top_bottom_width - border_left_right_width) < EPS)
html_fout << "border-width:" << _round(border_top_bottom_width) << "px;";
else
@ -313,12 +267,13 @@ void HTMLRenderer::processLink(AnnotLink * al)
html_fout << "border-style:none;";
}
_transform(default_ctm, x, y);
html_fout << "position:absolute;"
<< "left:" << _round(x1- border_left_right_width) << "px;"
<< "bottom:" << _round(y1 - border_top_bottom_width) << "px;"
<< "width:" << _round(x2-x1) << "px;"
<< "height:" << _round(y2-y1) << "px;";
<< "left:" << _round(x) << "px;"
<< "bottom:" << _round(y) << "px;"
<< "width:" << _round(w) << "px;"
<< "height:" << _round(h) << "px;";
// fix for IE
html_fout << "background-color:rgba(255,255,255,0.000001);";

View File

@ -112,7 +112,7 @@ void HTMLRenderer::check_state_change(GfxState * state)
// backup the current ctm for need_recheck_position
double old_ctm[6];
memcpy(old_ctm, cur_ctm, sizeof(old_ctm));
memcpy(old_ctm, cur_text_tm, sizeof(old_ctm));
// ctm & text ctm & hori scale
if(all_changed || ctm_changed || text_mat_changed || hori_scale_changed)
@ -131,29 +131,29 @@ void HTMLRenderer::check_state_change(GfxState * state)
new_ctm[5] = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
//new_ctm[4] = new_ctm[5] = 0;
if(!_tm_equal(new_ctm, cur_ctm))
if(!_tm_equal(new_ctm, cur_text_tm))
{
need_recheck_position = true;
need_rescale_font = true;
memcpy(cur_ctm, new_ctm, sizeof(cur_ctm));
memcpy(cur_text_tm, new_ctm, sizeof(cur_text_tm));
}
}
// draw_ctm, draw_scale
// draw_text_tm, draw_scale
// depends: font size & ctm & text_ctm & hori scale
if(need_rescale_font)
{
double new_draw_ctm[6];
memcpy(new_draw_ctm, cur_ctm, sizeof(new_draw_ctm));
double new_draw_text_tm[6];
memcpy(new_draw_text_tm, cur_text_tm, sizeof(new_draw_text_tm));
double new_draw_scale = 1.0/scale_factor2 * sqrt(new_draw_ctm[2] * new_draw_ctm[2] + new_draw_ctm[3] * new_draw_ctm[3]);
double new_draw_scale = 1.0/scale_factor2 * sqrt(new_draw_text_tm[2] * new_draw_text_tm[2] + new_draw_text_tm[3] * new_draw_text_tm[3]);
double new_draw_font_size = cur_font_size;
if(_is_positive(new_draw_scale))
{
new_draw_font_size *= new_draw_scale;
for(int i = 0; i < 4; ++i)
new_draw_ctm[i] /= new_draw_scale;
new_draw_text_tm[i] /= new_draw_scale;
}
else
{
@ -172,11 +172,11 @@ void HTMLRenderer::check_state_change(GfxState * state)
draw_font_size = new_draw_font_size;
cur_fs_id = install_font_size(draw_font_size);
}
if(!(_tm_equal(new_draw_ctm, draw_ctm, 4)))
if(!(_tm_equal(new_draw_text_tm, draw_text_tm, 4)))
{
new_line_state = max(new_line_state, NLS_DIV);
memcpy(draw_ctm, new_draw_ctm, sizeof(draw_ctm));
cur_tm_id = install_transform_matrix(draw_ctm);
memcpy(draw_text_tm, new_draw_text_tm, sizeof(draw_text_tm));
cur_ttm_id = install_transform_matrix(draw_text_tm);
}
}
@ -198,23 +198,23 @@ void HTMLRenderer::check_state_change(GfxState * state)
*/
bool merged = false;
if(_tm_equal(old_ctm, cur_ctm, 4))
if(_tm_equal(old_ctm, cur_text_tm, 4))
{
double dy = cur_ty - draw_ty;
double tdx = old_ctm[4] - cur_ctm[4] - cur_ctm[2] * dy;
double tdy = old_ctm[5] - cur_ctm[5] - cur_ctm[3] * dy;
double tdx = old_ctm[4] - cur_text_tm[4] - cur_text_tm[2] * dy;
double tdy = old_ctm[5] - cur_text_tm[5] - cur_text_tm[3] * dy;
if(_equal(cur_ctm[0] * tdy, cur_ctm[1] * tdx))
if(_equal(cur_text_tm[0] * tdy, cur_text_tm[1] * tdx))
{
if(abs(cur_ctm[0]) > EPS)
if(abs(cur_text_tm[0]) > EPS)
{
draw_tx += tdx / cur_ctm[0];
draw_tx += tdx / cur_text_tm[0];
draw_ty += dy;
merged = true;
}
else if (abs(cur_ctm[1]) > EPS)
else if (abs(cur_text_tm[1]) > EPS)
{
draw_tx += tdy / cur_ctm[1];
draw_tx += tdy / cur_text_tm[1];
draw_ty += dy;
merged = true;
}
@ -312,7 +312,7 @@ void HTMLRenderer::reset_state_change()
color_changed = false;
}
void HTMLRenderer::prepare_line(GfxState * state)
void HTMLRenderer::prepare_text_line(GfxState * state)
{
if(!line_opened)
{
@ -321,7 +321,7 @@ void HTMLRenderer::prepare_line(GfxState * state)
if(new_line_state == NLS_DIV)
{
close_line();
close_text_line();
line_buf.reset(state);
@ -353,7 +353,7 @@ void HTMLRenderer::prepare_line(GfxState * state)
line_opened = true;
}
void HTMLRenderer::close_line()
void HTMLRenderer::close_text_line()
{
if(line_opened)
{

View File

@ -484,7 +484,7 @@ void HTMLRenderer::drawString(GfxState * state, GooString * s)
// see if the line has to be closed due to state change
check_state_change(state);
prepare_line(state);
prepare_text_line(state);
// Now ready to output
// get the unicodes

View File

@ -42,6 +42,8 @@
* j - Js data
* p - Page
*
* cr - CSS draw Rectangle
*
* Reusable CSS classes
*
* t<hex> - Transform matrix
@ -82,7 +84,7 @@ class HTMLRenderer : public OutputDev
virtual GBool interpretType3Chars() { return gFalse; }
// Does this device need non-text content?
virtual GBool needNonText() { return gFalse; }
virtual GBool needNonText() { return gTrue; }
virtual void setDefaultCTM(double *ctm);
@ -121,6 +123,8 @@ class HTMLRenderer : public OutputDev
virtual void drawImage(GfxState * state, Object * ref, Stream * str, int width, int height, GfxImageColorMap * colorMap, GBool interpolate, int *maskColors, GBool inlineImg);
virtual void stroke(GfxState *state);
virtual void processLink(AnnotLink * al);
protected:
@ -190,8 +194,13 @@ class HTMLRenderer : public OutputDev
void reset_state_change();
// prepare the line context, (close old tags, open new tags)
// make sure the current HTML style consistent with PDF
void prepare_line(GfxState * state);
void close_line();
void prepare_text_line(GfxState * state);
void close_text_line();
////////////////////////////////////////////////////
// CSS drawing
////////////////////////////////////////////////////
void css_draw_rectange();
////////////////////////////////////////////////////
@ -246,16 +255,15 @@ class HTMLRenderer : public OutputDev
bool font_changed;
// transform matrix
long long cur_tm_id;
long long cur_ttm_id;
bool ctm_changed;
bool text_mat_changed;
// horizontal scaling
bool hori_scale_changed;
// this is CTM * TextMAT in PDF, not only CTM
// this is CTM * TextMAT in PDF
// [4] and [5] are ignored,
// as we'll calculate the position of the origin separately
// TODO: changed this for images
double cur_ctm[6]; // unscaled
double cur_text_tm[6]; // unscaled
// letter spacing
long long cur_ls_id;
@ -283,7 +291,7 @@ class HTMLRenderer : public OutputDev
// draw_ctm is cur_ctm scaled by 1/draw_scale,
// so everything redenered should be multiplied by draw_scale
double draw_ctm[6];
double draw_text_tm[6];
double draw_font_size;
double draw_scale;

View File

@ -47,6 +47,8 @@ static inline bool _tm_equal(const double * tm1, const double * tm2, int size =
return true;
}
void _transform(const double * ctm, double & x, double & y, bool is_delta = false);
static inline long long hash_ref(const Ref * id)
{
return (((long long)(id->num)) << (sizeof(id->gen)*8)) | (id->gen);
@ -223,5 +225,15 @@ bool is_truetype_suffix(const std::string & suffix);
std::string get_filename(const std::string & path);
std::string get_suffix(const std::string & path);
/*
* In PDF, edges of the rectangle are in the middle of the borders
* In HTML, edges are completely outside the rectangle
*/
void css_fix_rectangle_border_width(double x1, double y1, double x2, double y2,
double border_width,
double & x, double & y, double & w, double & h,
double & border_top_bottom_width,
double & border_left_right_width);
} // namespace util
#endif //UTIL_H__

View File

@ -54,6 +54,18 @@ const std::map<std::pair<std::string, bool>, std::pair<std::string, std::string>
{{".js", 1}, {"<script type=\"text/javascript\">", "</script>"}}
});
void _transform(const double * ctm, double & x, double & y, bool is_delta)
{
double xx = x, yy = y;
x = ctm[0] * xx + ctm[2] * yy;
y = ctm[1] * xx + ctm[3] * yy;
if(!is_delta)
{
x += ctm[4];
y += ctm[5];
}
}
bool isLegalUnicode(Unicode u)
{
/*
@ -249,4 +261,38 @@ string get_suffix(const string & path)
}
}
void css_fix_rectangle_border_width(double x1, double y1,
double x2, double y2,
double border_width,
double & x, double & y, double & w, double & h,
double & border_top_bottom_width,
double & border_left_right_width)
{
w = x2 - x1;
if(w > border_width)
{
w -= border_width;
border_left_right_width = border_width;
}
else
{
border_left_right_width = border_width + w/2;
w = 0;
}
x = x1 - border_width / 2;
h = y2 - y1;
if(h > border_width)
{
h -= border_width;
border_top_bottom_width = border_width;
}
else
{
border_top_bottom_width = border_width + h/2;
h = 0;
}
y = y1 - border_width / 2;
}
} // namespace pdf2htmlEX