2012-09-25 11:29:59 +00:00
|
|
|
/*
|
|
|
|
* link.cc
|
|
|
|
*
|
|
|
|
* Handling links
|
|
|
|
*
|
|
|
|
* by WangLu
|
|
|
|
* 2012.09.25
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include <HTMLRenderer.h>
|
|
|
|
#include <Link.h>
|
|
|
|
|
|
|
|
#include "namespace.h"
|
|
|
|
|
|
|
|
namespace pdf2htmlEX {
|
|
|
|
|
|
|
|
using std::ostringstream;
|
|
|
|
using std::min;
|
|
|
|
using std::max;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The detailed rectangle area of the link destination
|
|
|
|
* Will be parsed and performed by Javascript
|
|
|
|
*/
|
|
|
|
static string get_dest_detail_str(int pageno, LinkDest * dest)
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Based on pdftohtml from poppler
|
|
|
|
* TODO: CSS for link rectangles
|
2012-10-01 17:59:04 +00:00
|
|
|
* TODO: share rectangle draw with css-draw
|
2012-09-25 11:29:59 +00:00
|
|
|
*/
|
|
|
|
void HTMLRenderer::processLink(AnnotLink * al)
|
|
|
|
{
|
|
|
|
std::string dest_str, dest_detail_str;
|
|
|
|
auto action = al->getAction();
|
|
|
|
if(action)
|
|
|
|
{
|
|
|
|
auto kind = action->getKind();
|
|
|
|
switch(kind)
|
|
|
|
{
|
|
|
|
case actionGoTo:
|
|
|
|
{
|
|
|
|
auto catalog = cur_doc->getCatalog();
|
|
|
|
auto * real_action = dynamic_cast<LinkGoTo*>(action);
|
|
|
|
LinkDest * dest = nullptr;
|
|
|
|
if(auto _ = real_action->getDest())
|
|
|
|
dest = _->copy();
|
|
|
|
else if (auto _ = real_action->getNamedDest())
|
|
|
|
dest = catalog->findDest(_);
|
|
|
|
if(dest)
|
|
|
|
{
|
|
|
|
int pageno = 0;
|
|
|
|
if(dest->isPageRef())
|
|
|
|
{
|
|
|
|
auto pageref = dest->getPageRef();
|
|
|
|
pageno = catalog->findPage(pageref.num, pageref.gen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pageno = dest->getPageNum();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pageno > 0)
|
|
|
|
{
|
|
|
|
dest_str = (char*)str_fmt("#p%x", pageno);
|
|
|
|
dest_detail_str = get_dest_detail_str(pageno, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dest_str != "")
|
|
|
|
{
|
|
|
|
html_fout << "<a class=\"a\" href=\"" << dest_str << "\"";
|
|
|
|
|
|
|
|
if(dest_detail_str != "")
|
|
|
|
html_fout << " data-dest-detail='" << dest_detail_str << "'";
|
|
|
|
|
|
|
|
html_fout << ">";
|
|
|
|
}
|
|
|
|
|
2012-10-01 20:06:38 +00:00
|
|
|
html_fout << "<div class=\"Cd t"
|
2012-10-01 17:59:04 +00:00
|
|
|
<< install_transform_matrix(default_ctm)
|
|
|
|
<< "\" 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);
|
|
|
|
x = min(x1, x2);
|
|
|
|
y = min(y1, y2);
|
|
|
|
w = max(x1, x2) - x;
|
|
|
|
h = max(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-09-26 16:17:56 +00:00
|
|
|
border_width = border->getWidth() * zoom_factor();
|
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)
|
|
|
|
html_fout << "border-width:" << _round(border_top_bottom_width) << "px;";
|
|
|
|
else
|
|
|
|
html_fout << "border-width:" << _round(border_top_bottom_width) << "px " << _round(border_left_right_width) << "px;";
|
|
|
|
}
|
|
|
|
auto style = border->getStyle();
|
|
|
|
switch(style)
|
|
|
|
{
|
|
|
|
case AnnotBorder::borderSolid:
|
|
|
|
html_fout << "border-style:solid;";
|
|
|
|
break;
|
|
|
|
case AnnotBorder::borderDashed:
|
|
|
|
html_fout << "border-style:dashed;";
|
|
|
|
break;
|
|
|
|
case AnnotBorder::borderBeveled:
|
|
|
|
html_fout << "border-style:outset;";
|
|
|
|
break;
|
|
|
|
case AnnotBorder::borderInset:
|
|
|
|
html_fout << "border-style:inset;";
|
|
|
|
break;
|
|
|
|
case AnnotBorder::borderUnderlined:
|
|
|
|
html_fout << "border-style:none;border-bottom-style:solid;";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Warning:Unknown annotation border style: " << style << endl;
|
|
|
|
html_fout << "border-style:solid;";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
html_fout << "border-color:rgb("
|
|
|
|
<< dec << (int)dblToByte(r) << "," << (int)dblToByte(g) << "," << (int)dblToByte(b) << hex
|
|
|
|
<< ");";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
html_fout << "border-style:none;";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
html_fout << "border-style:none;";
|
|
|
|
}
|
|
|
|
|
2012-10-01 17:59:04 +00:00
|
|
|
_transform(default_ctm, x, y);
|
2012-09-25 11:29:59 +00:00
|
|
|
|
|
|
|
html_fout << "position:absolute;"
|
2012-10-01 17:59:04 +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
|
|
|
|
html_fout << "background-color:rgba(255,255,255,0.000001);";
|
|
|
|
|
|
|
|
html_fout << "\"></div>";
|
|
|
|
|
|
|
|
if(dest_str != "")
|
|
|
|
{
|
|
|
|
html_fout << "</a>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}// namespace pdf2htmlEX
|