2012-09-25 11:29:59 +00:00
|
|
|
/*
|
|
|
|
* link.cc
|
|
|
|
*
|
|
|
|
* Handling links
|
|
|
|
*
|
|
|
|
* by WangLu
|
|
|
|
* 2012.09.25
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include <Link.h>
|
|
|
|
|
2012-11-29 09:28:05 +00:00
|
|
|
#include "HTMLRenderer.h"
|
|
|
|
#include "util/namespace.h"
|
2012-11-29 10:16:05 +00:00
|
|
|
#include "util/math.h"
|
2012-11-29 10:28:07 +00:00
|
|
|
#include "util/misc.h"
|
2013-02-15 05:07:00 +00:00
|
|
|
#include "util/encoding.h"
|
2013-02-27 18:52:00 +00:00
|
|
|
#include "util/css_const.h"
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
namespace pdf2htmlEX {
|
|
|
|
|
|
|
|
using std::ostringstream;
|
|
|
|
using std::min;
|
|
|
|
using std::max;
|
2012-11-29 10:28:07 +00:00
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The detailed rectangle area of the link destination
|
|
|
|
* Will be parsed and performed by Javascript
|
2013-01-28 13:01:02 +00:00
|
|
|
* The string will be put into a HTML attribute, surrounded by single quotes
|
|
|
|
* So pay attention to the characters used here
|
2012-09-25 11:29:59 +00:00
|
|
|
*/
|
2013-01-28 13:01:02 +00:00
|
|
|
static string get_linkdest_detail_str(LinkDest * dest, Catalog * catalog, int & pageno)
|
2012-09-25 11:29:59 +00:00
|
|
|
{
|
2013-01-28 10:31:02 +00:00
|
|
|
pageno = 0;
|
|
|
|
if(dest->isPageRef())
|
|
|
|
{
|
|
|
|
auto pageref = dest->getPageRef();
|
2013-01-28 13:01:02 +00:00
|
|
|
pageno = catalog->findPage(pageref.num, pageref.gen);
|
2013-01-28 10:31:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pageno = dest->getPageNum();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pageno <= 0)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2012-09-25 11:29:59 +00:00
|
|
|
ostringstream sout;
|
|
|
|
// dec
|
|
|
|
sout << "[" << pageno;
|
|
|
|
|
|
|
|
if(dest)
|
|
|
|
{
|
|
|
|
switch(dest->getKind())
|
|
|
|
{
|
|
|
|
case destXYZ:
|
|
|
|
{
|
|
|
|
sout << ",\"XYZ\",";
|
|
|
|
if(dest->getChangeLeft())
|
|
|
|
sout << (dest->getLeft());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
sout << ",";
|
|
|
|
if(dest->getChangeTop())
|
|
|
|
sout << (dest->getTop());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
sout << ",";
|
|
|
|
if(dest->getChangeZoom())
|
|
|
|
sout << (dest->getZoom());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case destFit:
|
|
|
|
sout << ",\"Fit\"";
|
|
|
|
break;
|
|
|
|
case destFitH:
|
|
|
|
sout << ",\"FitH\",";
|
|
|
|
if(dest->getChangeTop())
|
|
|
|
sout << (dest->getTop());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
break;
|
|
|
|
case destFitV:
|
|
|
|
sout << ",\"FitV\",";
|
|
|
|
if(dest->getChangeLeft())
|
|
|
|
sout << (dest->getLeft());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
break;
|
|
|
|
case destFitR:
|
|
|
|
sout << ",\"FitR\","
|
|
|
|
<< (dest->getLeft()) << ","
|
|
|
|
<< (dest->getBottom()) << ","
|
|
|
|
<< (dest->getRight()) << ","
|
|
|
|
<< (dest->getTop());
|
|
|
|
break;
|
|
|
|
case destFitB:
|
|
|
|
sout << ",\"FitB\"";
|
|
|
|
break;
|
|
|
|
case destFitBH:
|
|
|
|
sout << ",\"FitBH\",";
|
|
|
|
if(dest->getChangeTop())
|
|
|
|
sout << (dest->getTop());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
break;
|
|
|
|
case destFitBV:
|
|
|
|
sout << ",\"FitBV\",";
|
|
|
|
if(dest->getChangeLeft())
|
|
|
|
sout << (dest->getLeft());
|
|
|
|
else
|
|
|
|
sout << "null";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sout << "]";
|
|
|
|
|
|
|
|
return sout.str();
|
|
|
|
}
|
2013-01-28 13:01:02 +00:00
|
|
|
|
|
|
|
string HTMLRenderer::get_linkaction_str(LinkAction * action, string & detail)
|
2012-09-25 11:29:59 +00:00
|
|
|
{
|
2013-01-28 13:01:02 +00:00
|
|
|
string dest_str;
|
|
|
|
detail = "";
|
2012-09-25 11:29:59 +00:00
|
|
|
if(action)
|
|
|
|
{
|
|
|
|
auto kind = action->getKind();
|
|
|
|
switch(kind)
|
|
|
|
{
|
|
|
|
case actionGoTo:
|
|
|
|
{
|
|
|
|
auto * real_action = dynamic_cast<LinkGoTo*>(action);
|
|
|
|
LinkDest * dest = nullptr;
|
|
|
|
if(auto _ = real_action->getDest())
|
|
|
|
dest = _->copy();
|
|
|
|
else if (auto _ = real_action->getNamedDest())
|
2013-01-28 10:31:02 +00:00
|
|
|
dest = cur_catalog->findDest(_);
|
2012-09-25 11:29:59 +00:00
|
|
|
if(dest)
|
|
|
|
{
|
|
|
|
int pageno = 0;
|
2013-01-28 13:01:02 +00:00
|
|
|
detail = get_linkdest_detail_str(dest, cur_catalog, pageno);
|
2012-09-25 11:29:59 +00:00
|
|
|
if(pageno > 0)
|
|
|
|
{
|
2013-02-27 18:52:00 +00:00
|
|
|
dest_str = (char*)str_fmt("#%s%x", CSS::PAGE_FRAME_CN, pageno);
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
delete dest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case actionGoToR:
|
|
|
|
{
|
|
|
|
cerr << "TODO: actionGoToR is not implemented." << endl;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case actionURI:
|
|
|
|
{
|
|
|
|
auto * real_action = dynamic_cast<LinkURI*>(action);
|
|
|
|
dest_str = real_action->getURI()->getCString();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case actionLaunch:
|
|
|
|
{
|
|
|
|
cerr << "TODO: actionLaunch is not implemented." << endl;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Warning: unknown annotation type: " << kind << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-28 13:01:02 +00:00
|
|
|
return dest_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Based on pdftohtml from poppler
|
|
|
|
* TODO: CSS for link rectangles
|
|
|
|
* TODO: share rectangle draw with css-draw
|
|
|
|
*/
|
|
|
|
void HTMLRenderer::processLink(AnnotLink * al)
|
|
|
|
{
|
|
|
|
string dest_detail_str;
|
|
|
|
string dest_str = get_linkaction_str(al->getAction(), dest_detail_str);
|
|
|
|
|
2013-01-28 10:31:02 +00:00
|
|
|
if(!dest_str.empty())
|
2012-09-25 11:29:59 +00:00
|
|
|
{
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "<a class=\"" << CSS::LINK_CN << "\" href=\"";
|
|
|
|
outputURL((*f_curpage), dest_str);
|
|
|
|
(*f_curpage) << "\"";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
2013-01-28 10:31:02 +00:00
|
|
|
if(!dest_detail_str.empty())
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << " data-dest-detail='" << dest_detail_str << "'";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << ">";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
2013-04-06 08:32:31 +00:00
|
|
|
<< all_manager.transform_matrix.install(default_ctm)
|
2012-10-01 17:59:04 +00:00
|
|
|
<< "\" style=\"";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
2012-10-01 17:59:04 +00:00
|
|
|
double x,y,w,h;
|
2012-09-25 11:29:59 +00:00
|
|
|
double x1, y1, x2, y2;
|
2012-10-01 17:59:04 +00:00
|
|
|
al->getRect(&x1, &y1, &x2, &y2);
|
2012-10-02 18:19:40 +00:00
|
|
|
x = min<double>(x1, x2);
|
|
|
|
y = min<double>(y1, y2);
|
|
|
|
w = max<double>(x1, x2) - x;
|
|
|
|
h = max<double>(y1, y2) - y;
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
double border_width = 0;
|
|
|
|
double border_top_bottom_width = 0;
|
|
|
|
double border_left_right_width = 0;
|
|
|
|
auto * border = al->getBorder();
|
|
|
|
if(border)
|
|
|
|
{
|
2012-10-02 06:19:20 +00:00
|
|
|
border_width = border->getWidth();
|
2012-09-25 11:29:59 +00:00
|
|
|
if(border_width > 0)
|
|
|
|
{
|
|
|
|
{
|
2012-10-01 20:06:38 +00:00
|
|
|
css_fix_rectangle_border_width(x1, y1, x2, y2, border_width,
|
2012-10-01 17:59:04 +00:00
|
|
|
x, y, w, h,
|
|
|
|
border_top_bottom_width, border_left_right_width);
|
|
|
|
|
2012-09-25 11:29:59 +00:00
|
|
|
if(abs(border_top_bottom_width - border_left_right_width) < EPS)
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-width:" << round(border_top_bottom_width) << "px;";
|
2012-09-25 11:29:59 +00:00
|
|
|
else
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-width:" << round(border_top_bottom_width) << "px " << round(border_left_right_width) << "px;";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
auto style = border->getStyle();
|
|
|
|
switch(style)
|
|
|
|
{
|
|
|
|
case AnnotBorder::borderSolid:
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:solid;";
|
2012-09-25 11:29:59 +00:00
|
|
|
break;
|
|
|
|
case AnnotBorder::borderDashed:
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:dashed;";
|
2012-09-25 11:29:59 +00:00
|
|
|
break;
|
|
|
|
case AnnotBorder::borderBeveled:
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:outset;";
|
2012-09-25 11:29:59 +00:00
|
|
|
break;
|
|
|
|
case AnnotBorder::borderInset:
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:inset;";
|
2012-09-25 11:29:59 +00:00
|
|
|
break;
|
|
|
|
case AnnotBorder::borderUnderlined:
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:none;border-bottom-style:solid;";
|
2012-09-25 11:29:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Warning:Unknown annotation border style: " << style << endl;
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:solid;";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto color = al->getColor();
|
|
|
|
double r,g,b;
|
|
|
|
if(color && (color->getSpace() == AnnotColor::colorRGB))
|
|
|
|
{
|
|
|
|
const double * v = color->getValues();
|
|
|
|
r = v[0];
|
|
|
|
g = v[1];
|
|
|
|
b = v[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = g = b = 0;
|
|
|
|
}
|
|
|
|
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-color:rgb("
|
2012-09-25 11:29:59 +00:00
|
|
|
<< dec << (int)dblToByte(r) << "," << (int)dblToByte(g) << "," << (int)dblToByte(b) << hex
|
|
|
|
<< ");";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:none;";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "border-style:none;";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
tm_transform(default_ctm, x, y);
|
2012-09-25 11:29:59 +00:00
|
|
|
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "position:absolute;"
|
2012-11-29 10:16:05 +00:00
|
|
|
<< "left:" << round(x) << "px;"
|
|
|
|
<< "bottom:" << round(y) << "px;"
|
|
|
|
<< "width:" << round(w) << "px;"
|
|
|
|
<< "height:" << round(h) << "px;";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
// fix for IE
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "background-color:rgba(255,255,255,0.000001);";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "\"></div>";
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
if(dest_str != "")
|
|
|
|
{
|
2013-06-09 14:19:12 +00:00
|
|
|
(*f_curpage) << "</a>";
|
2012-09-25 11:29:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}// namespace pdf2htmlEX
|