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:
parent
bd3f165ae2
commit
1d95b73eee
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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); };
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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__
|
||||||
|
Loading…
Reference in New Issue
Block a user