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

Handle clips during processing of covered text.

This commit is contained in:
Duan Yao 2014-06-15 16:42:34 +08:00
parent bd3f165ae2
commit 1d95b73eee
8 changed files with 100 additions and 30 deletions

View File

@ -30,11 +30,18 @@ void CoveredTextHandler::reset()
void CoveredTextHandler::add_char_bbox(double * bbox) void CoveredTextHandler::add_char_bbox(double * bbox)
{ {
for (int i = 0; i < 4; i++) char_bboxes.insert(char_bboxes.end(), bbox, bbox + 4);
char_bboxes.push_back(bbox[i]);
chars_covered.push_back(false); chars_covered.push_back(false);
} }
void CoveredTextHandler::add_char_bbox_clipped(double * bbox, bool patially)
{
char_bboxes.insert(char_bboxes.end(), bbox, bbox + 4);
chars_covered.push_back(true);
if (patially)
add_non_char_bbox(bbox, chars_covered.size() - 1);
}
void CoveredTextHandler::add_non_char_bbox(double * bbox, int index) void CoveredTextHandler::add_non_char_bbox(double * bbox, int index)
{ {
if (index < 0) if (index < 0)

View File

@ -32,6 +32,8 @@ public:
*/ */
void add_char_bbox(double * bbox); void add_char_bbox(double * bbox);
void add_char_bbox_clipped(double * bbox, bool patially);
/** /**
* Add a drawn non-char graphics' bounding box. * Add a drawn non-char graphics' bounding box.
* If it intersects any previously drawn char's bbox, the char is marked as covered * If it intersects any previously drawn char's bbox, the char is marked as covered
@ -51,7 +53,6 @@ public:
const std::vector<bool> & get_chars_covered() { return chars_covered; } const std::vector<bool> & get_chars_covered() { return chars_covered; }
private: private:
//covered text test
std::vector<bool> chars_covered; std::vector<bool> chars_covered;
// x00, y00, x01, y01; x10, y10, x11, y11;... // x00, y00, x01, y01; x10, y10, x11, y11;...
std::vector<double> char_bboxes; std::vector<double> char_bboxes;

View File

@ -53,15 +53,15 @@ void DrawingTracer::set_ctm(GfxState *state)
matrix.yy = ctm[3]; matrix.yy = ctm[3];
matrix.x0 = ctm[4]; matrix.x0 = ctm[4];
matrix.y0 = ctm[5]; matrix.y0 = ctm[5];
cairo_set_matrix (cairo, &matrix); cairo_set_matrix(cairo, &matrix);
} }
void DrawingTracer::clip(GfxState * state, bool even_odd) void DrawingTracer::clip(GfxState * state, bool even_odd)
{ {
if (!param.process_covered_text) if (!param.process_covered_text)
return; return;
do_path (state, state->getPath()); do_path(state, state->getPath());
cairo_set_fill_rule (cairo, even_odd? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); cairo_set_fill_rule(cairo, even_odd? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
cairo_clip (cairo); cairo_clip (cairo);
} }
@ -91,13 +91,13 @@ void DrawingTracer::do_path(GfxState * state, GfxPath * path)
GfxSubpath *subpath; GfxSubpath *subpath;
int i, j; int i, j;
double x, y; double x, y;
cairo_new_path (cairo); cairo_new_path(cairo);
for (i = 0; i < path->getNumSubpaths(); ++i) { for (i = 0; i < path->getNumSubpaths(); ++i) {
subpath = path->getSubpath(i); subpath = path->getSubpath(i);
if (subpath->getNumPoints() > 0) { if (subpath->getNumPoints() > 0) {
x = subpath->getX(0); x = subpath->getX(0);
y = subpath->getY(0); y = subpath->getY(0);
cairo_move_to (cairo, x, y); cairo_move_to(cairo, x, y);
j = 1; j = 1;
while (j < subpath->getNumPoints()) { while (j < subpath->getNumPoints()) {
if (subpath->getCurve(j)) { if (subpath->getCurve(j)) {
@ -111,7 +111,7 @@ void DrawingTracer::do_path(GfxState * state, GfxPath * path)
} else { } else {
x = subpath->getX(j); x = subpath->getX(j);
y = subpath->getY(j); y = subpath->getY(j);
cairo_line_to (cairo, x, y); cairo_line_to(cairo, x, y);
++j; ++j;
} }
} }
@ -150,22 +150,56 @@ void DrawingTracer::fill(GfxState * state, bool even_odd)
void DrawingTracer::draw_non_char_bbox(GfxState * state, double * bbox) void DrawingTracer::draw_non_char_bbox(GfxState * state, double * bbox)
{ {
double cbox[4], result[4]; double cbox[4];
cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3); cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3);
// TODO intersect if(bbox_intersect(cbox, bbox, bbox))
tm_transform_bbox(state->getCTM(), bbox); {
if (on_non_char_drawn) tm_transform_bbox(state->getCTM(), bbox);
on_non_char_drawn(bbox); if (on_non_char_drawn)
on_non_char_drawn(bbox);
}
} }
void DrawingTracer::draw_char_bbox(GfxState * state, double * bbox) void DrawingTracer::draw_char_bbox(GfxState * state, double * bbox)
{ {
double cbox[4], result[4]; // Note: even if 4 corner of the char are all in the clip area,
cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3); // it still could be partially clipped.
// TODO intersect // TODO better solution?
tm_transform_bbox(state->getCTM(), bbox); int pt_in = 0;
if (on_char_drawn) if (cairo_in_clip(cairo, bbox[0], bbox[1]))
on_char_drawn(bbox); ++pt_in;
if (cairo_in_clip(cairo, bbox[2], bbox[3]))
++pt_in;
if (cairo_in_clip(cairo, bbox[2], bbox[1]))
++pt_in;
if (cairo_in_clip(cairo, bbox[0], bbox[3]))
++pt_in;
if (pt_in == 0)
{
if(on_char_clipped)
on_char_clipped(bbox, false);
}
else
{
if (pt_in < 4)
{
double cbox[4];
cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3);
bbox_intersect(cbox, bbox, bbox);
}
tm_transform_bbox(state->getCTM(), bbox);
if (pt_in < 4)
{
if(on_char_clipped)
on_char_clipped(bbox, true);
}
else
{
if (on_char_drawn)
on_char_drawn(bbox);
}
}
} }
void DrawingTracer::draw_image(GfxState *state) void DrawingTracer::draw_image(GfxState *state)

View File

@ -25,9 +25,12 @@ public:
* The callback to receive drawn event. * The callback to receive drawn event.
* bbox in device space. * bbox in device space.
*/ */
// a non-char graphics is drawn
std::function<void(double * bbox)> on_non_char_drawn; std::function<void(double * bbox)> on_non_char_drawn;
// a char is drawn in the clip area
std::function<void(double * bbox)> on_char_drawn; std::function<void(double * bbox)> on_char_drawn;
std::function<void(double * bbox)> on_char_clipped; // a char is drawn out of/partially in the clip area
std::function<void(double * bbox, bool patially)> on_char_clipped;
DrawingTracer(const Param & param); DrawingTracer(const Param & param);
virtual ~DrawingTracer(); virtual ~DrawingTracer();

View File

@ -32,7 +32,8 @@ using std::ostream;
void HTMLRenderer::restoreState(GfxState * state) void HTMLRenderer::restoreState(GfxState * state)
{ {
updateAll(state); tracer.restore(); updateAll(state);
tracer.restore();
} }
void HTMLRenderer::saveState(GfxState *state) void HTMLRenderer::saveState(GfxState *state)

View File

@ -82,7 +82,7 @@ HTMLRenderer::HTMLRenderer(const Param & param)
tracer.on_char_drawn = tracer.on_char_drawn =
[this](double * box) { covered_text_handler.add_char_bbox(box); }; [this](double * box) { covered_text_handler.add_char_bbox(box); };
tracer.on_char_clipped = tracer.on_char_clipped =
[this](double * box) { covered_text_handler.add_char_bbox(box); }; //TODO [this](double * box, bool partial) { covered_text_handler.add_char_bbox_clipped(box, partial); };
tracer.on_non_char_drawn = tracer.on_non_char_drawn =
[this](double * box) { covered_text_handler.add_non_char_bbox(box); }; [this](double * box) { covered_text_handler.add_non_char_bbox(box); };
} }

View File

@ -60,12 +60,30 @@ void tm_transform_bbox(const double * tm, double * bbox)
} }
} }
bool bbox_intersect(double * bbox1, double * bbox2) bool bbox_intersect(const double * bbox1, const double * bbox2, double * result)
{ {
return min(bbox1[0], bbox1[2]) < max(bbox2[0], bbox2[2]) double x0, y0, x1, y1;
&& max(bbox1[0], bbox1[2]) > min(bbox2[0], bbox2[2])
&& min(bbox1[1], bbox1[3]) < max(bbox2[1], bbox2[3]) x0 = max(min(bbox1[0], bbox1[2]), min(bbox2[0], bbox2[2]));
&& max(bbox1[1], bbox1[3]) > min(bbox2[1], bbox2[3]); x1 = min(max(bbox1[0], bbox1[2]), max(bbox2[0], bbox2[2]));
if (x0 >= x1)
return false;
y0 = max(min(bbox1[1], bbox1[3]), min(bbox2[1], bbox2[3]));
y1 = min(max(bbox1[1], bbox1[3]), max(bbox2[1], bbox2[3]));
if (y0 >= y1)
return false;
if (result)
{
result[0] = x0;
result[1] = y0;
result[2] = x1;
result[3] = y1;
}
return true;
} }
} //namespace pdf2htmlEX } //namespace pdf2htmlEX

View File

@ -39,8 +39,14 @@ static inline double hypot(double x, double y) { return std::sqrt(x*x+y*y); }
void tm_transform(const double * tm, double & x, double & y, bool is_delta = false); void tm_transform(const double * tm, double & x, double & y, bool is_delta = false);
void tm_multiply(double * tm_left, const double * tm_right); void tm_multiply(double * tm_left, const double * tm_right);
void tm_transform_bbox(const double * tm, double * bbox); void tm_transform_bbox(const double * tm, double * bbox);
/**
bool bbox_intersect(double * bbox1, double * bbox2); * Calculate the intersection of 2 boxes.
* If they are intersecting, store the result to result (if not null) and return true.
* Otherwise return false, and result is not touched.
* Param result can be same as one of bbox1 and bbox2.
* Data in boxes are expected in the order of (x0, y0, x1, y1).
*/
bool bbox_intersect(const double * bbox1, const double * bbox2, double * result = nullptr);
} //namespace pdf2htmlEX } //namespace pdf2htmlEX
#endif //MATH_H__ #endif //MATH_H__