28#include <wx/filename.h>
29#include <wx/mstream.h>
30#include <wx/zstream.h>
31#include <wx/wfstream.h>
32#include <wx/datstrm.h>
33#include <wx/tokenzr.h>
47#include <fmt/format.h>
48#include <fmt/chrono.h>
49#include <fmt/ranges.h>
63#define GLM_ENABLE_EXPERIMENTAL
65#include <glm/gtx/euler_angles.hpp>
77 bool is_ascii7 =
true;
79 for(
size_t ii = 0; ii < aText.Len(); ii++ )
81 if( aText[ii] >= 0x7F )
92 for(
size_t ii = 0; ii < aText.Len(); ii++ )
94 unsigned int code = aText[ii];
96 if( code ==
'(' || code ==
')' || code ==
'\\' )
100 result +=
static_cast<char>( code );
102 else if( code < 0x20 )
106 result += fmt::format(
"\\{:03o}", code );
110 result +=
static_cast<char>( code );
121 for(
size_t ii = 0; ii < aText.Len(); ii++ )
123 unsigned int code = aText[ii];
136 std::string buf = fmt::format(
"{:g}", aValue );
140 if( buf.find(
'e' ) != std::string::npos || buf.find(
'E' ) != std::string::npos )
141 buf = fmt::format(
"{:.10f}", aValue );
143 if( buf.find(
'.' ) != std::string::npos )
146 while( buf.size() > 1 && buf.back() ==
'0' )
150 if( !buf.empty() && buf.back() ==
'.' )
165 result.reserve( aBytes.size() * 4 + 2 );
168 for(
unsigned char byte : aBytes )
170 if(
byte ==
'(' ||
byte ==
')' ||
byte ==
'\\' )
173 result.push_back(
static_cast<char>(
byte ) );
175 else if( byte < 32 || byte > 126 )
177 fmt::format_to( std::back_inserter(
result ),
"\\{:03o}",
byte );
181 result.push_back(
static_cast<char>(
byte ) );
233 wxASSERT_MSG( aWidth > 0,
"Plotter called to set negative pen width" );
257 fmt::println(
m_workFile,
"{} {} {} rg {} {} {} RG",
269 fmt::println(
m_workFile,
"/GS{} gs", extGStateHandle );
280 std::vector<int> pattern;
311 bool allZero = std::all_of( pattern.begin(), pattern.end(), [](
int v ) { return v == 0; } );
313 if( pattern.empty() || allZero )
319 fmt::println(
m_workFile,
"[{}] 0 d", fmt::join( pattern,
" " ) );
332 if( aCornerRadius > 0 )
344 if( size.
x == 0 && size.
y == 0 )
356 std::vector<VECTOR2I> cornerList;
358 cornerList.emplace_back( p1.
x, p1.
y );
359 cornerList.emplace_back( p2.
x, p1.
y );
360 cornerList.emplace_back( p2.
x, p2.
y );
361 cornerList.emplace_back( p1.
x, p2.
y );
362 cornerList.emplace_back( p1.
x, p1.
y );
364 PlotPoly( cornerList, fill, width,
nullptr );
377 paintOp = width > 0 ?
'B' :
'f';
379 fmt::println(
m_workFile,
"{} {} {} {} re {}",
401 char paintOp = aFill ==
FILL_T::NO_FILL ?
's' : ( width == 0 ?
'f' :
'b' );
416 double magic =
radius * 0.551784;
421 "{} {} {} {} {} {} c "
422 "{} {} {} {} {} {} c "
423 "{} {} {} {} {} {} c "
424 "{} {} {} {} {} {} c {}",
448 const EDA_ANGLE& aAngle,
double aRadius )
450 std::vector<VECTOR2D>
path;
457 EDA_ANGLE endAngle = startAngle - aAngle;
462 if( startAngle > endAngle )
463 std::swap( startAngle, endAngle );
466 start.
x =
KiROUND( aCenter.
x + aRadius * ( -startAngle ).Cos() );
467 start.
y =
KiROUND( aCenter.
y + aRadius * ( -startAngle ).Sin() );
472 end.x =
KiROUND( aCenter.
x + aRadius * ( -ii ).Cos() );
473 end.y =
KiROUND( aCenter.
y + aRadius * ( -ii ).Sin() );
477 end.x =
KiROUND( aCenter.
x + aRadius * ( -endAngle ).Cos() );
478 end.y =
KiROUND( aCenter.
y + aRadius * ( -endAngle ).Sin() );
498 std::vector<VECTOR2D>
path =
arcPath( aCenter, aStartAngle, aAngle, aRadius );
500 if(
path.size() >= 2 )
505 for(
int ii = 1; ii < (int)
path.size(); ++ii )
532 if( aCornerList.size() <= 1 )
543 for(
unsigned ii = 1; ii < aCornerList.size(); ii++ )
552 else if( aWidth == 0 )
566 std::set<size_t> handledArcs;
567 std::vector<VECTOR2D>
path;
573 size_t arcIndex = aLineChain.
ArcIndex( ii );
575 if( !handledArcs.contains( arcIndex ) )
577 handledArcs.insert( arcIndex );
582 for(
const VECTOR2D& pt : std::ranges::reverse_view( arc_path ) )
583 path.emplace_back( pt );
594 if(
path.size() <= 1 )
600 for(
int ii = 1; ii < (int)
path.size(); ++ii )
609 else if( aWidth == 0 )
639 plume ==
'D' ?
'l' :
'm' );
650 VECTOR2I pix_size( aImage.GetWidth(), aImage.GetHeight() );
653 VECTOR2D drawsize( aScaleFactor * pix_size.
x, aScaleFactor * pix_size.
y );
656 VECTOR2I start( aPos.
x - drawsize.
x / 2, aPos.
y + drawsize.
y / 2 );
660 auto findHandleForImage =
661 [&](
const wxImage& aCurrImage ) ->
int
665 if(
image.IsSameAs( aCurrImage ) )
668 if(
image.GetWidth() != aCurrImage.GetWidth() )
671 if(
image.GetHeight() != aCurrImage.GetHeight() )
674 if(
image.GetType() != aCurrImage.GetType() )
677 if(
image.HasAlpha() != aCurrImage.HasAlpha() )
680 if(
image.HasMask() != aCurrImage.HasMask()
681 ||
image.GetMaskRed() != aCurrImage.GetMaskRed()
682 ||
image.GetMaskGreen() != aCurrImage.GetMaskGreen()
683 ||
image.GetMaskBlue() != aCurrImage.GetMaskBlue() )
688 int pixCount =
image.GetWidth() *
image.GetHeight();
690 if( memcmp(
image.GetData(), aCurrImage.GetData(), pixCount * 3 ) != 0 )
693 if(
image.HasAlpha() && memcmp(
image.GetAlpha(), aCurrImage.GetAlpha(), pixCount ) != 0 )
702 int imgHandle = findHandleForImage( aImage );
704 if( imgHandle == -1 )
720 fmt::println(
m_workFile,
"q {} 0 0 {} {} {} cm",
726 fmt::println(
m_workFile,
"/Im{} Do", imgHandle );
744 wxASSERT_MSG( aHandle < 0,
"PDF object handle given was not previously allocated" );
774 fmt::print(
m_outputFile,
"<< /Length {} 0 R >>\nstream\n",
779 fmt::print(
m_outputFile,
"<< /Length {} 0 R /Filter /FlateDecode >>\nstream\n",
805 unsigned char *inbuf =
new unsigned char[stream_len];
807 int rc = fread( inbuf, 1, stream_len,
m_workFile );
808 wxASSERT( rc == stream_len );
820 out_count = stream_len;
826 wxMemoryOutputStream memos(
nullptr, std::max( 2000l, stream_len ) ) ;
836 wxZlibOutputStream zos( memos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
838 zos.Write( inbuf, stream_len );
841 wxStreamBuffer* sb = memos.GetOutputStreamBuffer();
843 out_count = sb->Tell();
844 fwrite( sb->GetBufferStart(), 1, out_count,
m_outputFile );
859 const wxString& aParentPageNumber,
const wxString& aParentPageName )
865 m_pageName = aPageName.IsEmpty() ? wxString::Format(
_(
"Page %s" ),
867 : wxString::Format(
_(
"%s (Page %s)" ),
872 : wxString::Format(
_(
"%s (Page %s)" ),
898 "{} 0 0 {} 0 0 cm 1 J 1 j 0 0 0 rg 0 0 0 RG {} w",
906void WriteImageStream(
const wxImage& aImage, wxDataOutputStream& aOut,
const wxColor& bg,
bool colorMode )
908 int w = aImage.GetWidth();
909 int h = aImage.GetHeight();
911 for(
int y = 0; y < h; y++ )
913 for(
int x = 0; x < w; x++ )
915 unsigned char r = aImage.GetRed( x, y ) & 0xFF;
916 unsigned char g = aImage.GetGreen( x, y ) & 0xFF;
917 unsigned char b = aImage.GetBlue( x, y ) & 0xFF;
919 if( aImage.HasMask() )
921 if( r == aImage.GetMaskRed() && g == aImage.GetMaskGreen() && b == aImage.GetMaskBlue() )
938 unsigned char grey =
KiROUND( r * 0.2126 + g * 0.7152 + b * 0.0722 );
949 int w = aImage.GetWidth();
950 int h = aImage.GetHeight();
952 if( aImage.HasMask() )
954 for(
int y = 0; y < h; y++ )
956 for(
int x = 0; x < w; x++ )
958 unsigned char a = 255;
959 unsigned char r = aImage.GetRed( x, y );
960 unsigned char g = aImage.GetGreen( x, y );
961 unsigned char b = aImage.GetBlue( x, y );
963 if( r == aImage.GetMaskRed() && g == aImage.GetMaskGreen() && b == aImage.GetMaskBlue() )
970 else if( aImage.HasAlpha() )
973 aOut.Write8( aImage.GetAlpha(), size );
992 const double PTsPERMIL = 0.072;
995 auto iuToPdfUserSpace =
1009 retval.
x = ( psPaperSize.
x - pos.
x );
1018 std::vector<int> annotHandles;
1024 const BOX2I& box = linkPair.first;
1025 const wxString& url = linkPair.second;
1032 userSpaceBox.
SetEnd( topRight );
1041 const BOX2I& box = menuPair.first;
1042 const std::vector<wxString>& urls = menuPair.second;
1049 userSpaceBox.
SetEnd( topRight );
1056 int annot3DHandle = -1;
1061 annotHandles.push_back( annot3DHandle );
1065 int annotArrayHandle = -1;
1068 if( annotHandles.size() > 0 )
1071 bool isFirst =
true;
1075 for(
int handle : annotHandles )
1098 " /ProcSet [/PDF /Text /ImageC /ImageB]\n"
1100 " /XObject {} 0 R\n"
1101 " /ExtGState {} 0 R >>\n"
1102 "/MediaBox [0 0 {} {}]\n",
1113 if( annotHandles.size() > 0 )
1114 fmt::print(
m_outputFile,
"/Annots {} 0 R", annotArrayHandle );
1127 "/Rect [0 0 {} {}]\n"
1128 "/NM (3D Annotation)\n"
1131 "/3DA<</A/PO/D/PC/TB true/NP true>>\n"
1152 std::stack<OUTLINE_NODE*> nodes;
1155 while( !nodes.empty() )
1169 nodes.push( child );
1181 for(
const std::pair<BOX2I, wxString>& bookmarkPair : groupVector )
1183 const BOX2I& box = bookmarkPair.first;
1184 const wxString& ref = bookmarkPair.second;
1189 actionHandle =
emitGoToAction( pageHandle, bottomLeft, topRight );
1194 std::sort( groupOutlineNode->
children.begin(), groupOutlineNode->
children.end(),
1197 return a->title < b->title;
1210 return StartPlot( aPageNumber, wxEmptyString );
1247 fmt::print(
m_outputFile,
"%PDF-1.5\n%\200\201\202\203\n" );
1276 "<</S /GoTo /D [{} 0 R /FitR {} {} {} {}]\n"
1286 return actionHandle;
1296 "<</S /GoTo /D [{} 0 R /Fit]\n"
1302 return actionHandle;
1309 int prevHandle = -1;
1310 int nextHandle = -1;
1312 for( std::vector<OUTLINE_NODE*>::iterator it = node->
children.begin(); it != node->
children.end(); it++ )
1314 if( it >= node->
children.end() - 1 )
1317 nextHandle = ( *( it + 1 ) )->entryHandle;
1321 prevHandle = ( *it )->entryHandle;
1325 if( parentHandle != -1 )
1337 fmt::println(
m_outputFile,
"/Next {} 0 R", nextNode );
1340 fmt::println(
m_outputFile,
"/Prev {} 0 R", prevNode );
1344 int32_t count = -1 *
static_cast<int32_t
>( node->
children.size() );
1360 const wxString& aTitle )
1381 "<< /Type /Outlines\n"
1421 if( !glyph.m_stream.empty() )
1422 fmt::print(
m_workFile,
"{}\n", glyph.m_stream );
1425 glyph.m_charProcHandle = charProcHandle;
1432 fmt::println(
m_outputFile,
" /{} {} 0 R", glyph.m_name, glyph.m_charProcHandle );
1447 double fontMatrixScale = 1.0 / subset.
UnitsPerEm();
1455 "<<\n/Type /Font\n/Subtype /Type3\n/Name {}\n/FontBBox [ {} {} {} {} ]\n",
1462 "/FontMatrix [ {} 0 0 {} 0 0 ]\n/CharProcs {} 0 R\n",
1467 "/Encoding << /Type /Encoding /Differences {} >>\n",
1470 "/FirstChar {}\n/LastChar {}\n/Widths {}\n",
1475 "/ToUnicode {} 0 R\n/Resources << /ProcSet [/PDF /Text] >>\n>>\n",
1490 if( !subsetPtr || !subsetPtr->HasGlyphs() )
1493 const std::vector<uint8_t>& fontData = subsetPtr->FontFileData();
1495 if( fontData.empty() )
1499 subsetPtr->SetFontFileHandle( fontFileHandle );
1501 if( !fontData.empty() )
1502 fwrite( fontData.data(), fontData.size(), 1,
m_workFile );
1506 std::string cidMap = subsetPtr->BuildCIDToGIDStream();
1508 subsetPtr->SetCIDMapHandle( cidMapHandle );
1510 if( !cidMap.empty() )
1511 fwrite( cidMap.data(), cidMap.size(), 1,
m_workFile );
1515 std::string toUnicode = subsetPtr->BuildToUnicodeCMap();
1517 subsetPtr->SetToUnicodeHandle( toUnicodeHandle );
1519 if( !toUnicode.empty() )
1525 subsetPtr->SetFontDescriptorHandle( descriptorHandle );
1528 "<<\n/Type /FontDescriptor\n/FontName /{}\n/Flags {}\n/ItalicAngle {}\n/Ascent {}\n/Descent {}\n"
1529 "/CapHeight {}\n/StemV {}\n/FontBBox [ {} {} {} {} ]\n/FontFile2 {} 0 R\n>>\n",
1530 subsetPtr->BaseFontName(),
1541 subsetPtr->FontFileHandle() );
1545 subsetPtr->SetCIDFontHandle( cidFontHandle );
1547 std::string widths = subsetPtr->BuildWidthsArray();
1550 "<<\n/Type /Font\n/Subtype /CIDFontType2\n/BaseFont /{}\n"
1551 "/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>\n"
1552 "/FontDescriptor {} 0 R\n/W {}\n/CIDToGIDMap {} 0 R\n>>\n",
1553 subsetPtr->BaseFontName(),
1554 subsetPtr->FontDescriptorHandle(),
1556 subsetPtr->CIDMapHandle() );
1560 subsetPtr->SetFontHandle( fontHandle );
1563 "<<\n/Type /Font\n/Subtype /Type0\n/BaseFont /{}\n/Encoding /Identity-H\n"
1564 "/DescendantFonts [ {} 0 R ]\n/ToUnicode {} 0 R\n>>\n",
1565 subsetPtr->BaseFontName(),
1566 subsetPtr->CIDFontHandle(),
1567 subsetPtr->ToUnicodeHandle() );
1586 {
"/Helvetica",
"/KicadFont", 0 },
1587 {
"/Helvetica-Oblique",
"/KicadFontI", 0 },
1588 {
"/Helvetica-Bold",
"/KicadFontB", 0 },
1589 {
"/Helvetica-BoldOblique",
"/KicadFontBI", 0 }
1594 for(
auto& font : base14 )
1600 " /Subtype /Type1\n"
1601 " /Encoding /WinAnsiEncoding\n"
1613 for(
const auto& font : base14 )
1614 fmt::println(
m_outputFile,
" {} {} 0 R", font.rsname, font.handle );
1621 if( subsetPtr && subsetPtr->FontHandle() >= 0 )
1622 fmt::println(
m_outputFile,
" {} {} 0 R", subsetPtr->ResourceName(), subsetPtr->FontHandle() );
1645 fmt::print(
m_outputFile,
" /Im{} {} 0 R\n", imgHandle, imgHandle );
1669 fmt::println(
m_outputFile,
" /GS{} {} 0 R", handle, handle );
1690 "/BitsPerComponent 8\n"
1694 "/Filter /FlateDecode\n"
1701 if( smaskHandle != -1 )
1702 fmt::println(
m_outputFile,
"/SMask {} 0 R", smaskHandle );
1710 wxFFileOutputStream ffos( outputFFile );
1711 wxZlibOutputStream zos( ffos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
1712 wxDataOutputStream dos( zos );
1718 long imgStreamSize = ftell(
m_outputFile ) - imgStreamStart;
1727 if( smaskHandle != -1 )
1737 "/BitsPerComponent 8\n"
1738 "/ColorSpace /DeviceGray\n"
1742 "/Filter /FlateDecode\n"
1753 wxFFileOutputStream ffos( outputFFile );
1754 wxZlibOutputStream zos( ffos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
1755 wxDataOutputStream dos( zos );
1760 long smaskStreamSize = ftell(
m_outputFile ) - smaskStreamStart;
1766 fmt::println(
m_outputFile,
"{}", (
unsigned) smaskStreamSize );
1770 outputFFile.Detach();
1775 BOX2D box = linkPair.first;
1776 wxString url = linkPair.second;
1784 "/Rect [{} {} {} {}]\n"
1785 "/Border [16 16 0]\n",
1791 wxString pageNumber;
1792 bool pageFound =
false;
1801 "/Dest [{} 0 R /FitB]\n"
1814 "/A << /Type /Action /S /NOP >>\n"
1824 "/A << /Type /Action /S /URI /URI {} >>\n"
1834 const BOX2D& box = menuPair.first;
1835 const std::vector<wxString>& urls = menuPair.second;
1836 wxString js = wxT(
"ShM([\n" );
1838 for(
const wxString& url : urls )
1840 if( url.StartsWith(
"!" ) )
1842 wxString
property = url.AfterFirst(
'!' );
1844 if( property.Find(
"http:" ) >= 0 )
1846 wxString href =
property.substr( property.Find(
"http:" ) );
1854 else if( property.Find(
"https:" ) >= 0 )
1856 wxString href =
property.substr( property.Find(
"https:" ) );
1864 else if( property.Find(
"file:" ) >= 0 )
1866 wxString href =
property.substr( property.Find(
"file:" ) );
1872 wxString displayText =
property.substr( 0, property.Find(
"file:" ) ) + href;
1880 int eqPos =
property.Find( wxS(
" = " ) );
1882 bool converted =
false;
1884 if( eqPos != wxNOT_FOUND )
1886 href =
property.Mid( eqPos + 3 );
1891 if( href.StartsWith( wxS(
"/" ) ) || href.StartsWith( wxS(
"${" ) )
1892 || ( href.Length() >= 2 && wxIsalpha( href[0] ) && href[1] ==
':' )
1893 || href.StartsWith( wxS(
"\\\\" ) ) )
1895 if( !href.StartsWith( wxS(
"/" ) ) )
1897 href.Replace( wxS(
"\\" ), wxS(
"/" ) );
1899 if( href.StartsWith( wxS(
"//" ) ) )
1900 href = wxS(
"file:" ) + href;
1902 href = wxS(
"file:///" ) + href;
1906 href = wxS(
"file://" ) + href;
1916 js += wxString::Format( wxT(
"[\"%s\", \"%s\"],\n" ),
1926 else if( url.StartsWith(
"#" ) )
1928 wxString pageNumber = url.AfterFirst(
'#' );
1934 wxString menuText = wxString::Format(
_(
"Show Page %s" ), pageNumber );
1936 js += wxString::Format( wxT(
"[\"%s\", \"#%d\"],\n" ),
1938 static_cast<int>( ii ) );
1945 wxString href = url;
1951 if( !href.StartsWith( wxS(
"http:" ) )
1952 && !href.StartsWith( wxS(
"https:" ) )
1953 && !href.StartsWith( wxS(
"file:" ) ) )
1955 if( href.StartsWith( wxS(
"/" ) ) || href.StartsWith( wxS(
"${" ) ) )
1957 href = wxS(
"file://" ) + href;
1959 else if( href.Length() >= 2 && wxIsalpha( href[0] ) && href[1] ==
':' )
1961 href.Replace( wxS(
"\\" ), wxS(
"/" ) );
1962 href = wxS(
"file:///" ) + href;
1964 else if( href.StartsWith( wxS(
"\\\\" ) ) )
1966 href.Replace( wxS(
"\\" ), wxS(
"/" ) );
1967 href = wxS(
"file:" ) + href;
1971 if( href.StartsWith( wxS(
"file:" ) ) )
1974 if( href.StartsWith( wxS(
"http:" ) )
1975 || href.StartsWith( wxS(
"https:" ) )
1976 || href.StartsWith( wxS(
"file:" ) ) )
1978 wxString menuText = wxString::Format(
_(
"Open %s" ), href );
1980 js += wxString::Format( wxT(
"[\"%s\", \"%s\"],\n" ),
1995 "/Rect [{} {} {} {}]\n"
1996 "/Border [16 16 0]\n",
2003 "/A << /Type /Action /S /JavaScript /JS {} >>\n"
2014function ShM(aEntries) {
2016 for (var i = 0; i < aEntries.length; ++i) {
2018 cName: aEntries[i][0],
2019 cReturn: aEntries[i].length > 1 ? aEntries[i][1] : ''
2023 var cChoice = app.popUpMenuEx.apply(app, aParams);
2024 if (cChoice == null || cChoice == '') return;
2026 if (cChoice.substring(0, 1) == '#') {
2027 this.pageNum = parseInt(cChoice.slice(1));
2031 // Fallback: some viewers return cName instead of cReturn
2033 if (url.substring(0, 4) != 'http' && url.substring(0, 4) != 'file') {
2034 var idx = url.indexOf('http');
2035 if (idx < 0) idx = url.indexOf('file:');
2036 if (idx >= 0) url = url.substring(idx);
2040 if (url.substring(0, 8) == 'file:///') app.openDoc(url.substring(7));
2041 else if (url.substring(0, 7) == 'file://') app.openDoc('//' + url.substring(7));
2042 else app.launchURL(url);
2049 " [ (JSInit) << /Type /Action /S /JavaScript /JS {} >> ]\n"
2091 std::time_t time = std::time(
nullptr );
2093#if defined( _WIN32 ) || defined( _MSC_VER )
2094 localtime_s( &tm, &time );
2096 localtime_r( &time, &tm );
2098 std::string dt = fmt::format(
"D:{:%Y:%m:%d:%H:%M:%S}", tm );
2109 "/Producer (KiCad PDF)\n"
2110 "/CreationDate ({})\n"
2125 int outlineHandle = -1;
2133 if( outlineHandle > 0 )
2140 "/PageMode /UseOutlines\n"
2141 "/Outlines {} 0 R\n"
2143 "/PageLayout /SinglePage\n"
2156 "/PageMode /UseNone\n"
2157 "/PageLayout /SinglePage\n"
2168 const std::vector<long>& xrefEntries =
m_xrefTable.Entries();
2173 "0000000000 65535 f \n",
2174 xrefEntries.size() );
2176 for(
unsigned i = 1; i < xrefEntries.size(); i++ )
2177 fmt::print(
m_outputFile,
"{:010d} 00000 n \n", xrefEntries[i] );
2182 "<< /Size {} /Root {} 0 R /Info {} 0 R >>\n"
2200 int aWidth,
bool aItalic,
bool aBold,
bool aMultilineAllowed,
KIFONT::FONT* aFont,
2204 if( aSize.
x == 0 || aSize.
y == 0 )
2207 wxString
text( aText );
2209 if(
text.Contains( wxS(
"@{" ) ) )
2230 int render_mode = 3;
2233 const char *fontname = aItalic ? ( aBold ?
"/KicadFontBI" :
"/KicadFontI" )
2234 : ( aBold ?
"/KicadFontB" :
"/KicadFont" );
2239 double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
2240 double wideningFactor, heightFactor;
2243 bool textMirrored = aSize.
x < 0;
2246 aItalic, aBold, &wideningFactor, &ctm_a, &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f,
2252 wxStringTokenizer str_tok(
text,
" ", wxTOKEN_RET_DELIMS );
2275 while( str_tok.HasMoreTokens() )
2277 wxString word = str_tok.GetNextToken();
2281 &ctm_a, &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
2294 if( word.Trim(
false ).Trim(
true ).empty() )
2301 fmt::print(
m_workFile,
"q {:f} {:f} {:f} {:f} {:f} {:f} cm BT {} {:g} Tf {} Tr {:g} Tz ",
2302 ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f,
2306 wideningFactor * 100 );
2309 fmt::println(
m_workFile,
"{} Tj ET", txt_pdf );
2315 PLOTTER::Text( aPos, aColor,
text, aOrient, aSize, aH_justify, aV_justify, aWidth, aItalic,
2316 aBold, aMultilineAllowed, aFont, aFontMetrics, aData );
2326 bool textMirrored = aSize.
x < 0;
2328 if( aWidth == 0 && aBold )
2337 auto computeAlignedStartPos =
2345 alignAttrs.
m_Size = t_size;
2349 alignAttrs.
m_Bold = aBold;
2360 drawOffset.
x = -drawOffset.
x;
2363 startPos = aPos + drawOffset;
2380 startPos -= box_x / 2;
2385 startPos += box_y / 2;
2399 std::unique_ptr<MARKUP::NODE> markupTree( markupParser.
Parse() );
2403 wxLogTrace(
tracePdfPlotter,
"PDF_PLOTTER::Text: Markup parsing failed, falling back to plain text." );
2405 wxStringTokenizer str_tok(
text,
" ", wxTOKEN_RET_DELIMS );
2406 VECTOR2I pos = computeAlignedStartPos();
2408 while( str_tok.HasMoreTokens() )
2410 wxString word = str_tok.GetNextToken();
2411 pos =
renderWord( word, pos, t_size, aOrient, textMirrored, aWidth, aBold, aItalic, aFont,
2412 aFontMetrics, aV_justify, 0 );
2417 VECTOR2I pos = computeAlignedStartPos();
2420 std::vector<OVERBAR_INFO> overbars;
2421 renderMarkupNode( markupTree.get(), pos, t_size, aOrient, textMirrored, aWidth, aBold, aItalic, aFont,
2422 aFontMetrics, aV_justify, 0, overbars );
2430 const EDA_ANGLE& aOrient,
bool aTextMirrored,
int aWidth,
bool aBold,
bool aItalic,
2434 if( wxGetEnv(
"KICAD_DEBUG_SYN_STYLE",
nullptr ) )
2441 styleFlags = (int) face->style_flags;
2444 wxLogTrace(
tracePdfPlotter,
"renderWord enter word='%s' bold=%d italic=%d textStyle=%u styleFlags=%d",
2445 TO_UTF8( aWord ), (
int) aBold, (
int) aItalic, (
unsigned) aTextStyle, styleFlags );
2468 auto cursorAdvanceX =
2469 [&](
const wxString& aText )
2476 if( aWord == wxT(
" " ) )
2478 VECTOR2I spaceBox( cursorAdvanceX( wxT(
" " ) ), 0 );
2483 VECTOR2I rotatedSpaceBox = spaceBox;
2485 return aPosition + rotatedSpaceBox;
2489 if( aWord.Contains( wxT(
'\t' ) ) )
2491 auto positionedAdvance =
2492 [&](
const wxString& aText )
2494 VECTOR2I advance( cursorAdvanceX( aText ), 0 );
2509 if( !segment.IsEmpty() )
2511 renderWord( segment, aPosition + positionedAdvance( prefix ), aSize, aOrient, aTextMirrored,
2512 aWidth, aBold, aItalic, aFont, aFontMetrics, aV_justify, aTextStyle );
2518 for( wxUniChar c : aWord )
2533 return aPosition + positionedAdvance( aWord );
2547 double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
2548 double wideningFactor, heightFactor;
2551 aWidth, aItalic, aBold, &wideningFactor, &ctm_a, &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f,
2554 VECTOR2I bbox( cursorAdvanceX( aWord ), 0 );
2560 VECTOR2I nextPos = aPosition + bbox;
2565 std::vector<PDF_OUTLINE_FONT_RUN> outlineRuns;
2575 if( !outlineRuns.empty() )
2578 double baseline_factor = 0.17;
2579 double alignment_multiplier = 1.0;
2582 alignment_multiplier = 2.0;
2584 alignment_multiplier = 4.0;
2587 double lineHeight = font_size_dev.
y;
2592 double baseline_adjustment = lineHeight * baseline_factor * alignment_multiplier;
2594 double adjusted_ctm_e = ctm_e;
2595 double adjusted_ctm_f = ctm_f;
2598 double cos_angle = cos( angle_rad );
2599 double sin_angle = sin( angle_rad );
2601 adjusted_ctm_e = ctm_e - baseline_adjustment * sin_angle;
2602 adjusted_ctm_f = ctm_f + baseline_adjustment * cos_angle;
2604 double adj_c = ctm_c;
2605 double adj_d = ctm_d;
2608 bool syntheticItalicApplied =
false;
2609 double appliedTilt = 0.0;
2610 double syn_c = adj_c;
2611 double syn_d = adj_d;
2612 double syn_a = ctm_a;
2613 double syn_b = ctm_b;
2616 if( std::getenv(
"KICAD_FORCE_SYN_ITALIC" ) )
2620 bool fontIsItalic = aFont->
IsItalic();
2621 bool fontIsBold = aFont->
IsBold();
2629 bool forceSynItalic =
false;
2630 double overrideTilt = 0.0;
2632 if(
const char* envForce = std::getenv(
"KICAD_FORCE_SYN_ITALIC" ) )
2634 if( *envForce !=
'\0' && *envForce !=
'0' )
2635 forceSynItalic =
true;
2638 if(
const char* envTilt = std::getenv(
"KICAD_SYN_ITALIC_TILT" ) )
2640 std::string tiltStr( envTilt );
2644 if( tiltStr.find(
"deg" ) != std::string::npos )
2646 double deg = std::stod( tiltStr );
2647 overrideTilt = tan( deg *
M_PI / 180.0 );
2651 overrideTilt = std::stod( tiltStr );
2661 wxLogTrace(
tracePdfPlotter,
"Outline path word='%s' runs=%zu wantItalic=%d fontIsItalic=%d "
2662 "fontIsFakeItalic=%d wantBold=%d fontIsBold=%d fontIsFakeBold=%d forceSyn=%d",
2663 TO_UTF8( aWord ), outlineRuns.size(), (
int) wantItalic, (
int) fontIsItalic,
2664 (
int) fontIsFakeItalic, (
int) wantBold, (
int) fontIsBold, (
int) fontIsFakeBold,
2665 (
int) forceSynItalic );
2671 bool realItalicFace = fontIsItalic && !fontIsFakeItalic;
2673 if( wantItalic && ( forceSynItalic || !realItalicFace ) )
2684 double tilt = ( overrideTilt != 0.0 ) ? overrideTilt :
ITALIC_TILT;
2686 if( wideningFactor < 0 )
2689 syn_c = adj_c + tilt * syn_a;
2690 syn_d = adj_d + tilt * syn_b;
2692 syntheticItalicApplied =
true;
2694 wxLogTrace(
tracePdfPlotter,
"Synthetic italic shear applied: tilt=%f a=%f b=%f c->%f d->%f",
2695 tilt, syn_a, syn_b, syn_c, syn_d );
2698 if( wantBold && !fontIsBold )
2705 if( syntheticItalicApplied )
2708 fmt::print(
m_workFile,
"% syn-italic tilt={} a={} b={} c={} d={}\n",
2709 appliedTilt, syn_a, syn_b, syn_c, syn_d );
2712 fmt::print(
m_workFile,
"q {:f} {:f} {:f} {:f} {:f} {:f} cm BT {} Tr {} Tz ",
2713 syn_a, syn_b, syn_c, syn_d, adjusted_ctm_e, adjusted_ctm_f,
2720 run.m_subset->ResourceName(),
2726 static_cast<unsigned char>( ( glyph.
cid >> 8 ) & 0xFF ),
2727 static_cast<unsigned char>( glyph.
cid & 0xFF ) );
2743 wxLogTrace(
tracePdfPlotter,
"Stroke path word='%s' wantItalic=%d aItalic=%d aBold=%d",
2745 (
int) aItalic, (
int) aBold );
2747 std::vector<PDF_STROKE_FONT_RUN> runs;
2753 double fontSize = dev_size.
y;
2755 double adj_c = ctm_c;
2756 double adj_d = ctm_d;
2762 if( wideningFactor < 0 )
2765 adj_c -= ctm_a * tilt;
2766 adj_d -= ctm_b * tilt;
2775 const double xCancelDev = xOffsetEm * dev_size.
x;
2776 const double yCancelDev = yOffsetEm * dev_size.
y;
2777 const double xSign = ( wideningFactor < 0 ) ? -1.0 : 1.0;
2779 const double adj_ctm_e = ctm_e - yCancelDev * adj_c - xSign * xCancelDev * ctm_a;
2780 const double adj_ctm_f = ctm_f - yCancelDev * adj_d - xSign * xCancelDev * ctm_b;
2783 const double tzFactor = wideningFactor < 0 ? -100.0 : 100.0;
2785 fmt::print(
m_workFile,
"q {:f} {:f} {:f} {:f} {:f} {:f} cm BT {} Tr {} Tz ",
2786 ctm_a, ctm_b, adj_c, adj_d, adj_ctm_e, adj_ctm_f,
2793 run.m_subset->ResourceName(),
2809 bool aTextMirrored,
int aWidth,
bool aBaseBold,
bool aBaseItalic,
2812 std::vector<OVERBAR_INFO>& aOverbars )
2817 return nextPosition;
2821 bool drawOverbar =
false;
2824 if( !aNode->is_root() )
2842 if( aNode->has_content() )
2847 wxStringTokenizer str_tok( nodeText,
" ", wxTOKEN_RET_DELIMS );
2849 while( str_tok.HasMoreTokens() )
2851 wxString word = str_tok.GetNextToken();
2852 nextPosition =
renderWord( word, nextPosition, currentSize, aOrient, aTextMirrored, aWidth,
2855 aFont, aFontMetrics, aV_justify, currentStyle );
2861 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
2865 nextPosition =
renderMarkupNode( child.get(), nextPosition, currentSize, aOrient, aTextMirrored, aWidth,
2866 aBaseBold, aBaseItalic, aFont, aFontMetrics, aV_justify, currentStyle,
2873 aOverbars.push_back( { startPos, endPos, currentSize, aFont->
IsOutline(), aV_justify } );
2877 return nextPosition;
2887 VECTOR2D dir( overbar.endPos.x - overbar.startPos.x, overbar.endPos.y - overbar.startPos.y );
2889 double len = hypot( dir.
x, dir.
y );
2910 if( overbar.isOutline )
2911 barOffset += overbar.fontSize.y * 0.25;
2916 double alignMult = 1.0;
2918 switch( overbar.vAlign )
2922 default: alignMult = 1.0;
break;
2925 if( alignMult > 1.0 )
2928 double baseline_factor = 0.17;
2929 barOffset += ( alignMult - 1.0 ) * ( baseline_factor * overbar.fontSize.y );
2933 double barTrim = overbar.fontSize.x * 0.1;
2936 VECTOR2D startPt( overbar.startPos.x, overbar.startPos.y );
2937 VECTOR2D endPt( overbar.endPos.x, overbar.endPos.y );
2941 VECTOR2D offVec( -barOffset * nrm.
x, -barOffset * nrm.
y );
2943 startPt.
x += dir.
x * barTrim + offVec.
x;
2944 startPt.
y += dir.
y * barTrim + offVec.
y;
2945 endPt.
x -= dir.
x * barTrim - offVec.
x;
2946 endPt.
y -= dir.
y * barTrim - offVec.
y;
2960 const wxString& aText,
2969 if( size.
x == 0 || size.
y == 0 )
2977 aFont, aFontMetrics, aData );
2996 m_bookmarksInPage[aGroupName].push_back( std::make_pair( aLocation, aSymbolReference ) );
3002 std::map<float, int> m_fovMap;
3003 std::vector<int> m_viewHandles;
3008 wxASSERT( view.m_cameraMatrix.size() == 12 );
3011 if( !m_fovMap.contains( view.m_fov ) )
3014 m_fovMap[view.m_fov] = fovHandle;
3028 fovHandle = m_fovMap[view.m_fov];
3042 "/C2W [{:f} {:f} {:f} {:f} {:f} {:f} {:f} {:f} {:f} {:f} {:f} {:f}]\n"
3049 "/C [1.000000 1.000000 1.000000]>>\n"
3052 "/Type /3DLightingScheme\n"
3055 encodedName, encodedName,
3056 view.m_cameraMatrix[0],
3057 view.m_cameraMatrix[1],
3058 view.m_cameraMatrix[2], view.m_cameraMatrix[3], view.m_cameraMatrix[4],
3059 view.m_cameraMatrix[5], view.m_cameraMatrix[6], view.m_cameraMatrix[7],
3060 view.m_cameraMatrix[8], view.m_cameraMatrix[9], view.m_cameraMatrix[10],
3061 view.m_cameraMatrix[11],
3062 view.m_cameraCenter,
3067 m_viewHandles.push_back( viewHandle );
3083 for(
int viewHandle : m_viewHandles )
3090 "/Filter /FlateDecode\n"
3101 size_t model_stored_size = 0;
3104 wxFFileOutputStream ffos( outputFFile );
3105 wxZlibOutputStream zos( ffos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB );
3107 wxFFileInputStream fileStream( aSourcePath );
3109 if( !fileStream.IsOk() )
3110 wxLogError(
_(
"Failed to open 3D model file: %s" ), aSourcePath );
3112 zos.Write( fileStream );
3117 model_stored_size -= imgStreamStart;
3123 fmt::println(
m_outputFile,
"{}", (
unsigned) model_stored_size );
3126 outputFFile.Detach();
3131 float aCameraDistance,
3133 float aPitchDegrees,
3134 float aRollDegrees )
3136 float yRadians = glm::radians( aYawDegrees );
3137 float xRadians = glm::radians( aPitchDegrees );
3138 float zRadians = glm::radians( aRollDegrees );
3141 glm::mat4 rotationMatrix = glm::eulerAngleYXZ( yRadians, xRadians, zRadians );
3145 glm::vec4 cameraOffset = glm::vec4( 0.0f, 0.0f, aCameraDistance, 1.0f );
3148 cameraOffset = rotationMatrix * cameraOffset;
3151 glm::vec3 cameraPosition = glm::vec3(aTargetPosition.
x, aTargetPosition.
y, aTargetPosition.
z)
3152 - glm::vec3( cameraOffset );
3154 std::vector<float>
result( 12 );
3158 for(
int col = 0; col < 3; ++col )
3160 for(
int row = 0; row < 3; ++row )
3161 result[
index++] =
static_cast<float>( rotationMatrix[col][row] );
3165 result[9] =
static_cast<float>( cameraPosition.x );
3166 result[10] =
static_cast<float>( cameraPosition.y );
3167 result[11] =
static_cast<float>( cameraPosition.z );
void WriteImageStream(const wxImage &aImage, wxDataOutputStream &aOut, const wxColor &bg, bool colorMode)
void WriteImageSMaskStream(const wxImage &aImage, wxDataOutputStream &aOut)
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr const Vec & GetPosition() const
constexpr const Vec GetEnd() const
constexpr void SetOrigin(const Vec &pos)
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr void SetEnd(coord_type x, coord_type y)
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
EDA_ANGLE GetAngle() const
static bool IsGotoPageHref(const wxString &aHref, wxString *aDestination=nullptr)
Check if aHref is a valid internal hyperlink.
High-level wrapper for evaluating mathematical and string expressions in wxString format.
wxString Evaluate(const wxString &aInput)
Main evaluation function - processes input string and evaluates all '@{}' expressions.
FONT is an abstract base class for both outline and stroke fonts.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
virtual bool IsStroke() const
virtual bool IsItalic() const
virtual bool IsBold() const
virtual bool IsOutline() const
VECTOR2I GetAlignedDrawPosition(const wxString &aText, const VECTOR2I &aAnchor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Return the draw position for the first line of text, using the same alignment rules as GAL rendering ...
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
virtual double GetSuperSubSizeMultiplier() const =0
Return the factor the text size is multiplied by for a superscript or subscript run.
virtual VECTOR2I GetTextAsGlyphs(BOX2I *aBBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aSize, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const =0
Convert text string to an array of GLYPHs.
virtual double GetSuperSubBaselineOffset(TEXT_STYLE_FLAGS aTextStyle) const =0
Return the baseline shift of a superscript or subscript run, as a downwards fraction of the reduced g...
double GetOverbarVerticalPosition(double aGlyphHeight) const
Compute the vertical position of an overbar.
Implement outline font drawing.
EMBEDDING_PERMISSION GetEmbeddingPermission() const
A color representation with 4 components: red, green, blue, alpha.
std::unique_ptr< NODE > Parse()
XREF_TABLE m_xrefTable
The PDF xref offset table.
std::vector< int > m_pageHandles
Handles to the page objects.
FILE * m_workFile
Temporary file to construct the stream before zipping.
wxString m_parentPageName
virtual void ClosePage()
Close the current page in the PDF document (and emit its compressed stream).
void emitOutlineNode(OUTLINE_NODE *aNode, int aParentHandle, int aNextNode, int aPrevNode)
Emits a outline item object and recurses into any children.
std::map< int, wxImage > m_imageHandles
int emitOutline()
Starts emitting the outline object.
virtual bool EndPlot() override
int startPdfObject(int aHandle=-1)
Open a new PDF object and returns the handle if the parameter is -1.
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=nullptr) override
Polygon plotting for PDF.
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width) override
Circle drawing for PDF.
virtual void SetCurrentLineWidth(int width, void *aData=nullptr) override
Pen width setting for PDF.
double m_currentAlpha
Alpha currently set in the page graphics state (PDF starts each page with 1.0).
int m_streamLengthHandle
Handle to the deferred stream length.
void PlotImage(const wxImage &aImage, const VECTOR2I &aPos, double aScaleFactor) override
PDF images are handles as inline, not XObject streams...
int m_jsNamesHandle
Handle for Names dictionary with JS.
virtual void SetDash(int aLineWidth, LINE_STYLE aLineStyle) override
PDF supports dashed lines.
void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs) override
Create a clickable hyperlink menu with a rectangular click area.
virtual bool OpenFile(const wxString &aFullFilename) override
Open or create the plot file aFullFilename.
std::string encodeDoubleForPlotter(double aValue) const
Convert a double to a PDF-compatible numeric token (no exponent notation).
int m_fontResDictHandle
Font resource dictionary.
virtual void emitSetRGBColor(double r, double g, double b, double a) override
PDF supports colors fully.
std::map< int, std::pair< BOX2D, wxString > > m_hyperlinkHandles
Handles for all the hyperlink objects that will be deferred.
int m_pageTreeHandle
Handle to the root of the page tree object.
std::map< double, int > m_alphaToExtGStateHandles
Graphics state objects keyed by alpha.
virtual void Text(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const EDA_ANGLE &aOrient, const VECTOR2I &aSize, enum GR_TEXT_H_ALIGN_T aH_justify, enum GR_TEXT_V_ALIGN_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr) override
Draw text with the plotter.
int emitGoToAction(int aPageHandle, const VECTOR2I &aBottomLeft, const VECTOR2I &aTopRight)
Emit an action object that instructs a goto coordinates on a page.
void closePdfStream()
Finish the current PDF stream (writes the deferred length, too).
void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString) override
Create a bookmark to a symbol.
void endPlotEmitResources()
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width, int aCornerRadius=0) override
Rectangles in PDF.
int startPdfStream(int aHandle=-1)
Start a PDF stream (for the page).
VECTOR2I renderMarkupNode(const MARKUP::NODE *aNode, const VECTOR2I &aPosition, const VECTOR2I &aBaseSize, const EDA_ANGLE &aOrient, bool aTextMirrored, int aWidth, bool aBaseBold, bool aBaseItalic, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, enum GR_TEXT_V_ALIGN_T aV_justify, TEXT_STYLE_FLAGS aTextStyle, std::vector< OVERBAR_INFO > &aOverbars)
Recursively render markup nodes with appropriate styling.
virtual void Arc(const VECTOR2D &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius, FILL_T aFill, int aWidth) override
The PDF engine can't directly plot arcs so we use polygonization.
void HyperlinkBox(const BOX2I &aBox, const wxString &aDestinationURL) override
Create a clickable hyperlink with a rectangular click area.
virtual void PenTo(const VECTOR2I &pos, char plume) override
Moveto/lineto primitive, moves the 'pen' to the specified direction.
int m_extGStateResDictHandle
Graphics state resource dictionary.
std::map< wxString, std::vector< std::pair< BOX2I, wxString > > > m_bookmarksInPage
virtual bool StartPlot(const wxString &aPageNumber) override
The PDF engine supports multiple pages; the first one is opened 'for free' the following are to be cl...
bool m_usedBase14Fonts
Set when the non-embeddable font fallback references the base-14 /KicadFont* resources.
int getExtGStateHandleForAlpha(double aAlpha)
Return the ExtGState resource handle for the given alpha, allocating a new object the first time that...
virtual void StartPage(const wxString &aPageNumber, const wxString &aPageName=wxEmptyString, const wxString &aParentPageNumber=wxEmptyString, const wxString &aParentPageName=wxEmptyString)
Start a new page in the PDF document.
std::unique_ptr< PDF_OUTLINE_FONT_MANAGER > m_outlineFontManager
OUTLINE_NODE * addOutlineNode(OUTLINE_NODE *aParent, int aActionHandle, const wxString &aTitle)
Add a new outline node entry.
int m_imgResDictHandle
Image resource dictionary.
std::string encodeStringForPlotter(const wxString &aUnicode) override
convert a wxString unicode string to a char string compatible with the accepted string PDF format (co...
std::unique_ptr< PDF_STROKE_FONT_MANAGER > m_strokeFontManager
void Plot3DModel(const wxString &aSourcePath, const std::vector< PDF_3D_VIEW > &a3DViews)
std::vector< wxString > m_pageNumbers
List of user-space page numbers for resolving internal hyperlinks.
int allocPdfObject()
Allocate a new handle in the table of the PDF object.
VECTOR2I renderWord(const wxString &aWord, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, bool aTextMirrored, int aWidth, bool aBold, bool aItalic, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, enum GR_TEXT_V_ALIGN_T aV_justify, TEXT_STYLE_FLAGS aTextStyle)
Render a single word with the given style parameters.
std::string encodeByteString(const std::string &aBytes)
void drawOverbars(const std::vector< OVERBAR_INFO > &aOverbars, const EDA_ANGLE &aOrient, const KIFONT::METRICS &aFontMetrics)
Draw overbar lines above text.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
PDF can have multiple pages, so SetPageSettings can be called with the outputFile open (but not insid...
std::map< int, std::pair< BOX2D, std::vector< wxString > > > m_hyperlinkMenuHandles
int m_pageStreamHandle
Handle of the page content object.
virtual void PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr) override
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
std::vector< std::pair< BOX2I, wxString > > m_hyperlinksInPage
List of loaded hyperlinks in current page.
std::unique_ptr< OUTLINE_NODE > m_outlineRoot
Root outline node.
std::vector< std::pair< BOX2I, std::vector< wxString > > > m_hyperlinkMenusInPage
void closePdfObject()
Close the current PDF object.
int m_totalOutlineNodes
Total number of outline nodes.
std::vector< VECTOR2D > arcPath(const VECTOR2D &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius)
const std::string & ResourceName() const
std::string BuildDifferencesArray() const
double FontBBoxMaxY() const
double FontBBoxMinY() const
double UnitsPerEm() const
double FontBBoxMinX() const
void SetToUnicodeHandle(int aHandle)
int CharProcsHandle() const
std::string BuildWidthsArray() const
double FontBBoxMaxX() const
void SetFontHandle(int aHandle)
int ToUnicodeHandle() const
void SetCharProcsHandle(int aHandle)
std::string BuildToUnicodeCMap() const
std::vector< GLYPH > & Glyphs()
double GetDotMarkLenIU(int aLineWidth) const
double GetDashGapLenIU(int aLineWidth) const
const PROJECT * m_project
bool m_mirrorIsHorizontal
static const int USE_DEFAULT_LINE_WIDTH
void MoveTo(const VECTOR2I &pos)
void FinishTo(const VECTOR2I &pos)
virtual VECTOR2D userToDeviceCoordinates(const VECTOR2I &aCoordinate)
Modify coordinates according to the orientation, scale factor, and offsets trace.
virtual VECTOR2D userToDeviceSize(const VECTOR2I &size)
Modify size according to the plotter scale factors (VECTOR2I version, returns a VECTOR2D).
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
FILE * m_outputFile
Output file.
void LineTo(const VECTOR2I &pos)
static const int DO_NOT_SET_LINE_WIDTH
RENDER_SETTINGS * m_renderSettings
virtual void Text(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const EDA_ANGLE &aOrient, const VECTOR2I &aSize, enum GR_TEXT_H_ALIGN_T aH_justify, enum GR_TEXT_V_ALIGN_T aV_justify, int aPenWidth, bool aItalic, bool aBold, bool aMultilineAllowed, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr)
Draw text with the plotter.
virtual int GetCurrentLineWidth() const
double GetDashMarkLenIU(int aLineWidth) const
virtual void SetColor(const COLOR4D &color) override
The SetColor implementation is split with the subclasses: the PSLIKE computes the rgb values,...
double plotScaleAdjX
Fine user scale adjust ( = 1.0 if no correction)
void computeTextParameters(const VECTOR2I &aPos, const wxString &aText, const EDA_ANGLE &aOrient, const VECTOR2I &aSize, bool aMirror, enum GR_TEXT_H_ALIGN_T aH_justify, enum GR_TEXT_V_ALIGN_T aV_justify, int aWidth, bool aItalic, bool aBold, double *wideningFactor, double *ctm_a, double *ctm_b, double *ctm_c, double *ctm_d, double *ctm_e, double *ctm_f, double *heightFactor)
This is the core for postscript/PDF text alignment.
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
EDA_ANGLE GetStartAngle() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
bool IsArcSegment(size_t aSegment) const
const SHAPE_LINE_CHAIN Outline() const
void SetRadius(int aRadius)
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
std::string substr(size_t pos=0, size_t len=npos) const
const wxString ResolveUriByEnvVars(const wxString &aUri, const PROJECT *aProject)
Replace any environment and/or text variables in URIs.
static constexpr EDA_ANGLE ANGLE_0
@ FILLED_SHAPE
Fill with object color.
unsigned int TEXT_STYLE_FLAGS
static constexpr double ITALIC_TILT
Tilt factor for italic style (this is the scaling factor on dY relative coordinates to give a tilted ...
int GetPenSizeForBold(int aTextSize)
double m_PDFStrokeFontXOffset
Horizontal offset factor applied to stroke font glyph coordinates (in EM units) after to compensate m...
double m_PDFStrokeFontYOffset
Vertical offset factor applied to stroke font glyph coordinates (in EM units) after Y inversion to co...
const wxChar *const tracePdfPlotter
Flag to enable PDF plotter debug tracing.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
void ignore_unused(const T &)
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::string FormatPdfUtf16Hex(uint32_t aCodepoint)
Format one Unicode code point as the hex digits of its UTF-16BE representation.
Plotting engines similar to ps (PostScript, Gerber, svg)
wxString NormalizeFileUri(const wxString &aFileUri)
Normalize file path aFileUri to URI convention.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
LINE_STYLE
Dashed line types.
bool isSuperscript() const
wxString asWxString() const
wxString title
Title of outline node.
std::vector< OUTLINE_NODE * > children
Ordered list of children.
int entryHandle
Allocated handle for this outline entry.
OUTLINE_NODE * AddChild(int aActionHandle, const wxString &aTitle, int aEntryHandle)
int actionHandle
Handle to action.
wxString result
Test unit parsing edge cases and error handling.
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D