Optimize PDF plot data size for property popups; fix unicode escape.

Adds a document-level action JSInit, which defines ShM function,
allowing more compact data representation. Also reduces whitespaces.
This commit is contained in:
Alex Shvartzkop 2023-07-04 08:57:26 +03:00
parent b09ab2daab
commit afe176abe2
3 changed files with 70 additions and 39 deletions

View File

@ -909,6 +909,8 @@ bool PDF_PLOTTER::StartPlot( const wxString& aPageNumber, const wxString& aPageN
(it *could* be inherited via the Pages tree */
m_fontResDictHandle = allocPdfObject();
m_jsNamesHandle = allocPdfObject();
/* Now, the PDF is read from the end, (more or less)... so we start
with the page stream for page 1. Other more important stuff is written
at the end */
@ -980,31 +982,32 @@ void PDF_PLOTTER::emitOutlineNode( OUTLINE_NODE* node, int parentHandle, int nex
startPdfObject( nodeHandle );
fprintf( m_outputFile,
"<< /Title %s\n"
" /Parent %d 0 R\n",
"<<\n"
"/Title %s\n"
"/Parent %d 0 R\n",
encodeStringForPlotter(node->title ).c_str(),
parentHandle);
if( nextNode > 0 )
{
fprintf( m_outputFile, " /Next %d 0 R\n", nextNode );
fprintf( m_outputFile, "/Next %d 0 R\n", nextNode );
}
if( prevNode > 0 )
{
fprintf( m_outputFile, " /Prev %d 0 R\n", prevNode );
fprintf( m_outputFile, "/Prev %d 0 R\n", prevNode );
}
if( node->children.size() > 0 )
{
fprintf( m_outputFile, " /Count %zd\n", -1 * node->children.size() );
fprintf( m_outputFile, " /First %d 0 R\n", node->children.front()->entryHandle );
fprintf( m_outputFile, " /Last %d 0 R\n", node->children.back()->entryHandle );
fprintf( m_outputFile, "/Count %zd\n", -1 * node->children.size() );
fprintf( m_outputFile, "/First %d 0 R\n", node->children.front()->entryHandle );
fprintf( m_outputFile, "/Last %d 0 R\n", node->children.back()->entryHandle );
}
if( node->actionHandle != -1 )
{
fprintf( m_outputFile, " /A %d 0 R\n", node->actionHandle );
fprintf( m_outputFile, "/A %d 0 R\n", node->actionHandle );
}
fputs( ">>\n", m_outputFile );
@ -1114,10 +1117,11 @@ bool PDF_PLOTTER::EndPlot()
startPdfObject( linkHandle );
fprintf( m_outputFile,
"<< /Type /Annot\n"
" /Subtype /Link\n"
" /Rect [%g %g %g %g]\n"
" /Border [16 16 0]\n",
"<<\n"
"/Type /Annot\n"
"/Subtype /Link\n"
"/Rect [%g %g %g %g]\n"
"/Border [16 16 0]\n",
box.GetLeft(), box.GetBottom(), box.GetRight(), box.GetTop() );
wxString pageNumber;
@ -1130,7 +1134,7 @@ bool PDF_PLOTTER::EndPlot()
if( m_pageNumbers[ii] == pageNumber )
{
fprintf( m_outputFile,
" /Dest [%d 0 R /FitB]\n"
"/Dest [%d 0 R /FitB]\n"
">>\n",
m_pageHandles[ii] );
@ -1142,15 +1146,14 @@ bool PDF_PLOTTER::EndPlot()
if( !pageFound )
{
// destination page is not being plotted, assign the NOP action to the link
fprintf( m_outputFile,
" /A << /Type /Action /S /NOP >>\n"
">>\n" );
fprintf( m_outputFile, "/A << /Type /Action /S /NOP >>\n"
">>\n" );
}
}
else
{
fprintf( m_outputFile,
" /A << /Type /Action /S /URI /URI %s >>\n"
"/A << /Type /Action /S /URI /URI %s >>\n"
">>\n",
encodeStringForPlotter( url ).c_str() );
}
@ -1162,7 +1165,7 @@ bool PDF_PLOTTER::EndPlot()
{
const BOX2D& box = menuPair.first;
const std::vector<wxString>& urls = menuPair.second;
wxString js = wxT( "var aParams = [ " );
wxString js = wxT( "ShM([\n" );
for( const wxString& url : urls )
{
@ -1174,7 +1177,7 @@ bool PDF_PLOTTER::EndPlot()
{
wxString href = property.substr( property.Find( "http:" ) );
js += wxString::Format( wxT( "{ cName: '%s', cReturn: '%s' }, " ),
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( property, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
@ -1182,13 +1185,13 @@ bool PDF_PLOTTER::EndPlot()
{
wxString href = property.substr( property.Find( "https:" ) );
js += wxString::Format( wxT( "{ cName: '%s', cReturn: '%s' }, " ),
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( property, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
else
{
js += wxString::Format( wxT( "{ cName: '%s', cReturn: null }, " ),
js += wxString::Format( wxT( "[\"%s\"],\n" ),
EscapeString( property, CTX_JS_STR ) );
}
}
@ -1202,7 +1205,7 @@ bool PDF_PLOTTER::EndPlot()
{
wxString menuText = wxString::Format( _( "Show Page %s" ), pageNumber );
js += wxString::Format( wxT( "{ cName: '%s', cReturn: '#%d' }, " ),
js += wxString::Format( wxT( "[\"%s\", \"#%d\"],\n" ),
EscapeString( menuText, CTX_JS_STR ),
static_cast<int>( ii ) );
break;
@ -1213,33 +1216,58 @@ bool PDF_PLOTTER::EndPlot()
{
wxString menuText = wxString::Format( _( "Open %s" ), url );
js += wxString::Format( wxT( "{ cName: '%s', cReturn: '%s' }, " ),
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( menuText, CTX_JS_STR ),
EscapeString( url, CTX_JS_STR ) );
}
}
js += wxT( "]; " );
js += wxT( "var cChoice = app.popUpMenuEx.apply\\( app, aParams \\); " );
js += wxT( "if\\( cChoice != null && cChoice.substring\\( 0, 1 \\) == '#' \\)"
" this.pageNum = parseInt\\( cChoice.slice\\( 1 \\) \\); " );
js += wxT( "else if\\( cChoice != null && cChoice.substring\\( 0, 4 \\) == 'http' \\)"
" app.launchURL\\( cChoice \\);" );
js += wxT( "]);" );
startPdfObject( menuHandle );
fprintf( m_outputFile,
"<< /Type /Annot\n"
" /Subtype /Link\n"
" /Rect [%g %g %g %g]\n"
" /Border [16 16 0]\n",
"<<\n"
"/Type /Annot\n"
"/Subtype /Link\n"
"/Rect [%g %g %g %g]\n"
"/Border [16 16 0]\n",
box.GetLeft(), box.GetBottom(), box.GetRight(), box.GetTop() );
fprintf( m_outputFile,
" /A << /Type /Action /S /JavaScript /JS (%s) >>\n"
"/A << /Type /Action /S /JavaScript /JS %s >>\n"
">>\n",
js.ToStdString().c_str() );
encodeStringForPlotter( js ).c_str() );
closePdfObject();
}
{
startPdfObject( m_jsNamesHandle );
wxString js = R"JS(
function ShM(aEntries) {
var aParams = [];
for (var i in aEntries) {
aParams.push({
cName: aEntries[i][0],
cReturn: aEntries[i][1]
})
}
var cChoice = app.popUpMenuEx.apply(app, aParams);
if (cChoice != null && cChoice.substring(0, 1) == '#') this.pageNum = parseInt(cChoice.slice(1));
else if (cChoice != null && cChoice.substring(0, 4) == 'http') app.launchURL(cChoice);
}
)JS";
fprintf( m_outputFile,
"<< /JavaScript\n"
" << /Names\n"
" [ (JSInit) << /Type /Action /S /JavaScript /JS %s >> ]\n"
" >>\n"
">>\n",
encodeStringForPlotter( js ).c_str() );
closePdfObject();
}
@ -1303,10 +1331,12 @@ bool PDF_PLOTTER::EndPlot()
"/Version /1.5\n"
"/PageMode /UseOutlines\n"
"/Outlines %d 0 R\n"
"/Names %d 0 R\n"
"/PageLayout /SinglePage\n"
">>\n",
m_pageTreeHandle,
outlineHandle );
outlineHandle,
m_jsNamesHandle );
}
else
{

View File

@ -203,7 +203,7 @@ wxString EscapeString( const wxString& aSource, ESCAPE_CONTEXT aContext )
{
unsigned int code = c;
char buffer[16];
snprintf( buffer, sizeof(buffer), "\\\\u%4.4X", code );
snprintf( buffer, sizeof(buffer), "\\u%4.4X", code );
converted += buffer;
}
else

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -493,6 +493,7 @@ protected:
int m_pageTreeHandle; ///< Handle to the root of the page tree object
int m_fontResDictHandle; ///< Font resource dictionary
int m_jsNamesHandle; ///< Handle for Names dictionary with JS
std::vector<int> m_pageHandles; ///< Handles to the page objects
int m_pageStreamHandle; ///< Handle of the page content object
int m_streamLengthHandle; ///< Handle to the deferred stream length