Add pdf output to hyperlinks
This commit is contained in:
parent
366b0ab08b
commit
f788945cf4
|
@ -700,17 +700,67 @@ void PDF_PLOTTER::ClosePage()
|
||||||
// Close the page stream (and compress it)
|
// Close the page stream (and compress it)
|
||||||
closePdfStream();
|
closePdfStream();
|
||||||
|
|
||||||
// Emit the page object and put it in the page list for later
|
|
||||||
m_pageHandles.push_back( startPdfObject() );
|
|
||||||
|
|
||||||
/* Page size is in 1/72 of inch (default user space units)
|
/* Page size is in 1/72 of inch (default user space units)
|
||||||
Works like the bbox in postscript but there is no need for
|
Works like the bbox in postscript but there is no need for
|
||||||
swapping the sizes, since PDF doesn't require a portrait page.
|
swapping the sizes, since PDF doesn't require a portrait page.
|
||||||
We use the MediaBox but PDF has lots of other less used boxes
|
We use the MediaBox but PDF has lots of other less used boxes
|
||||||
to use */
|
to use */
|
||||||
|
const double PTsPERMIL = 0.072;
|
||||||
|
VECTOR2D psPaperSize = VECTOR2D( m_pageInfo.GetSizeMils() ) * PTsPERMIL;
|
||||||
|
|
||||||
const double BIGPTsPERMIL = 0.072;
|
auto iuToPdfUserSpace = [&]( const VECTOR2I& aCoord ) -> VECTOR2D
|
||||||
VECTOR2I psPaperSize = m_pageInfo.GetSizeMils();
|
{
|
||||||
|
VECTOR2D retval = VECTOR2D( aCoord ) * PTsPERMIL / SCH_IU_PER_MILS;
|
||||||
|
// PDF y=0 is at bottom of page, invert coordinate
|
||||||
|
retval.y = psPaperSize.y - retval.y;
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle annotations (at the moment only "link" type objects)
|
||||||
|
std::vector<int> hyperlinkHandles;
|
||||||
|
|
||||||
|
// Write out all hyperlinks for the page as annotation links
|
||||||
|
for( const std::pair<BOX2I, wxString>& linkPair : m_urlHyperlinks )
|
||||||
|
{
|
||||||
|
const BOX2I& box = linkPair.first;
|
||||||
|
const wxString& url = linkPair.second;
|
||||||
|
|
||||||
|
VECTOR2D bottomLeft = iuToPdfUserSpace( box.GetPosition() );
|
||||||
|
VECTOR2D topRight = iuToPdfUserSpace( box.GetEnd() );
|
||||||
|
|
||||||
|
hyperlinkHandles.push_back( startPdfObject() );
|
||||||
|
fprintf( m_outputFile,
|
||||||
|
"<< /Type /Annot\n"
|
||||||
|
" /Subtype /Link\n"
|
||||||
|
" /Rect[%g %g %g %g] /Border[16 16 1]\n"
|
||||||
|
" /A << /Type /Action /S /URI /URI %s >>\n"
|
||||||
|
">>\n",
|
||||||
|
bottomLeft.x, bottomLeft.y, topRight.x, topRight.y,
|
||||||
|
encodeStringForPlotter( url ).c_str() );
|
||||||
|
closePdfObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
int hyperLinkArrayHandle = -1;
|
||||||
|
|
||||||
|
// If we have added any annotation links, create an array containing all the objects
|
||||||
|
if( hyperlinkHandles.size() > 0 )
|
||||||
|
{
|
||||||
|
hyperLinkArrayHandle = startPdfObject();
|
||||||
|
bool isFirst = true;
|
||||||
|
|
||||||
|
fprintf( m_outputFile, "[%d 0 R", hyperlinkHandles[0] );
|
||||||
|
|
||||||
|
for( auto it = hyperlinkHandles.begin() + 1; it != hyperlinkHandles.end(); ++it )
|
||||||
|
{
|
||||||
|
fprintf( m_outputFile, " %d 0 R", *it );
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs( "]\n", m_outputFile );
|
||||||
|
closePdfObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the page object and put it in the page list for later
|
||||||
|
m_pageHandles.push_back( startPdfObject() );
|
||||||
|
|
||||||
fprintf( m_outputFile,
|
fprintf( m_outputFile,
|
||||||
"<<\n"
|
"<<\n"
|
||||||
|
@ -719,14 +769,19 @@ void PDF_PLOTTER::ClosePage()
|
||||||
"/Resources <<\n"
|
"/Resources <<\n"
|
||||||
" /ProcSet [/PDF /Text /ImageC /ImageB]\n"
|
" /ProcSet [/PDF /Text /ImageC /ImageB]\n"
|
||||||
" /Font %d 0 R >>\n"
|
" /Font %d 0 R >>\n"
|
||||||
"/MediaBox [0 0 %d %d]\n"
|
"/MediaBox [0 0 %g %g]\n"
|
||||||
"/Contents %d 0 R\n"
|
"/Contents %d 0 R\n",
|
||||||
">>\n",
|
|
||||||
m_pageTreeHandle,
|
m_pageTreeHandle,
|
||||||
m_fontResDictHandle,
|
m_fontResDictHandle,
|
||||||
int( ceil( psPaperSize.x * BIGPTsPERMIL ) ),
|
psPaperSize.x,
|
||||||
int( ceil( psPaperSize.y * BIGPTsPERMIL ) ),
|
psPaperSize.y,
|
||||||
m_pageStreamHandle );
|
m_pageStreamHandle );
|
||||||
|
|
||||||
|
if( hyperlinkHandles.size() > 0 )
|
||||||
|
fprintf( m_outputFile, "/Annots %d 0 R", hyperLinkArrayHandle );
|
||||||
|
|
||||||
|
fputs( ">>\n", m_outputFile );
|
||||||
|
|
||||||
closePdfObject();
|
closePdfObject();
|
||||||
|
|
||||||
// Mark the page stream as idle
|
// Mark the page stream as idle
|
||||||
|
@ -956,3 +1011,9 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||||
aBold, aMultilineAllowed, aFont );
|
aBold, aMultilineAllowed, aFont );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDF_PLOTTER::HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL )
|
||||||
|
{
|
||||||
|
m_urlHyperlinks.push_back( std::make_pair( aBox, aDestinationURL ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -436,6 +436,17 @@ public:
|
||||||
KIFONT::FONT* aFont,
|
KIFONT::FONT* aFont,
|
||||||
void* aData = nullptr );
|
void* aData = nullptr );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a clickable hyperlink with a rectangular click area
|
||||||
|
*
|
||||||
|
* @aBox is the rectangular click target
|
||||||
|
* @aDestinationURL is the target
|
||||||
|
*/
|
||||||
|
virtual void HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL )
|
||||||
|
{
|
||||||
|
// NOP for most plotters.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a marker (used for the drill map).
|
* Draw a marker (used for the drill map).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -352,6 +352,8 @@ public:
|
||||||
KIFONT::FONT* aFont = nullptr,
|
KIFONT::FONT* aFont = nullptr,
|
||||||
void* aData = nullptr ) override;
|
void* aData = nullptr ) override;
|
||||||
|
|
||||||
|
virtual void HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL ) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDF images are handles as inline, not XObject streams...
|
* PDF images are handles as inline, not XObject streams...
|
||||||
*/
|
*/
|
||||||
|
@ -414,6 +416,7 @@ protected:
|
||||||
wxString m_workFilename;
|
wxString m_workFilename;
|
||||||
FILE* m_workFile; ///< Temporary file to construct the stream before zipping
|
FILE* m_workFile; ///< Temporary file to construct the stream before zipping
|
||||||
std::vector<long> m_xrefTable; ///< The PDF xref offset table
|
std::vector<long> m_xrefTable; ///< The PDF xref offset table
|
||||||
|
std::vector<std::pair<BOX2I, wxString>> m_urlHyperlinks; ///< List of loaded URLs so far
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue