1
0
mirror of https://github.com/pdf2htmlEX/pdf2htmlEX.git synced 2024-09-17 21:16:03 +00:00
pdf2htmlEX/src/HTMLRenderer/link.cc
2012-09-25 19:29:59 +08:00

335 lines
9.5 KiB
C++

/*
* 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;
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
*/
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
*/
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 << ">";
}
html_fout << "<div style=\"";
double x1, y1, x2, y2;
_get_transformed_rect(al, default_ctm, x1, y1, x2, y2);
double border_width = 0;
double border_top_bottom_width = 0;
double border_left_right_width = 0;
auto * border = al->getBorder();
if(border)
{
border_width = border->getWidth() * (param->zoom);
if(border_width > 0)
{
{
_fix_border_width(x1, y1, x2, y1,
border_width, 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
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;";
}
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;";
// fix for IE
html_fout << "background-color:rgba(255,255,255,0.000001);";
html_fout << "\"></div>";
if(dest_str != "")
{
html_fout << "</a>";
}
}
}// namespace pdf2htmlEX