KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pdf_unicode_plot.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <boost/test/unit_test.hpp>
25
26#include <wx/filename.h>
27#include <wx/filefn.h>
28#include <wx/ffile.h>
29#include <wx/utils.h>
30#include <wx/image.h>
31#include <zlib.h>
32
34#include <advanced_config.h>
35#include <render_settings.h>
36#include <trigo.h>
37#include <font/font.h>
38#include <font/stroke_font.h>
41
42/* Test objective:
43 * Ensure PDF_PLOTTER can emit glyphs for ASCII plus some Cyrillic, Japanese and Chinese
44 * characters using stroke font fallback. We verify by checking resulting PDF file contains
45 * expected glyph names or UTF-16 hex sequences for those code points.
46 */
47
48BOOST_AUTO_TEST_SUITE( PDFUnicodePlot )
49
50static wxString getTempPdfPath( const wxString& name ) { return MakeTempPdfPath( name ); }
51
52// Comprehensive mapping test: emit all four style variants in a single PDF and verify that
53// every style's ToUnicode CMap contains expected codepoints (Cyrillic 041F, Japanese 65E5, Chinese 672C).
54BOOST_AUTO_TEST_CASE( PlotMultilingualAllStylesMappings )
55{
56 const std::string sampleUtf8 = "ABCDEF Привет 日本語 漢字";
57 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
58 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode_allstyles" );
59
60 PDF_PLOTTER plotter;
61 SIMPLE_RENDER_SETTINGS renderSettings;
62
63 plotter.SetRenderSettings( &renderSettings );
64 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
65 plotter.SetViewport( VECTOR2I(0,0), 1.0, 1.0, false );
66 BOOST_REQUIRE( plotter.StartPlot( wxT("1"), wxT("TestPage") ) );
67
68 auto emitStyle = [&]( bool bold, bool italic, int yoff )
69 {
70 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, bold, italic );
71 auto strokeFont = LoadStrokeFontUnique();
72 KIFONT::METRICS metrics;
73
74 plotter.PlotText( VECTOR2I( 50000, 60000 - yoff ), COLOR4D( 0, 0, 0, 1 ), sample, attrs,
75 strokeFont.get(), metrics );
76 };
77
78 emitStyle( false, false, 0 ); // normal
79 emitStyle( true, false, 8000 ); // bold
80 emitStyle( false, true, 16000 ); // italic
81 emitStyle( true, true, 24000 ); // bold-italic
82
83 plotter.EndPlot();
84
85 // Read entire PDF (may have compression). We'll search each Type3 font object's preceding
86 // name to separate CMaps logically.
87 std::string buffer; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer ) );
88 BOOST_CHECK( buffer.rfind( "%PDF", 0 ) == 0 );
89
90 // Count how many distinct KiCadStrokeCMap names present; expect at least 4 (one per style).
91 int cmapCount = CountOccurrences( buffer, "/CMapName /KiCadStrokeCMap" );
92
93 BOOST_CHECK_MESSAGE( cmapCount >= 4, "Expected at least 4 CMaps (got " << cmapCount << ")" );
94
95 auto requireAll = [&]( const char* codeHex, const char* label ) {
96 int occurrences = CountOccurrences( buffer, codeHex );
97 BOOST_CHECK_MESSAGE( occurrences >= 4, "Codepoint " << label << " (" << codeHex
98 << ") expected in all 4 styles; found " << occurrences );
99 };
100
101 requireAll( "041F", "Cyrillic PE" );
102 requireAll( "65E5", "Kanji 日" );
103 requireAll( "672C", "Kanji 本" );
104
105 MaybeRemoveFile( pdfPath );
106}
107
108BOOST_AUTO_TEST_CASE( PlotMultilingualText )
109{
110 // UTF-8 sample with Latin, Cyrillic, Japanese, Chinese (shared Han) characters.
111 const std::string sampleUtf8 = "ABCDEF Привет 日本語 漢字";
112 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
113
114 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode" );
115
116 PDF_PLOTTER plotter;
117
118 // Force uncompressed PDF streams via environment so we can directly search for
119 // unicode hex strings in the output (otherwise they are Flate compressed).
120 // Do not force debug writer; allow normal compression so page content is valid.
121 // The plotter expects non-null render settings for default pen width and font queries.
122 // Provide a minimal concrete RENDER_SETTINGS implementation for the plotter.
123 SIMPLE_RENDER_SETTINGS renderSettings; plotter.SetRenderSettings( &renderSettings );
124
125 // Minimal viewport and plot setup. Use 1 IU per decimil so internal coordinates are small
126 // and resulting translation keeps text inside the page for rasterization.
127 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
128 plotter.SetViewport( VECTOR2I(0,0), 1.0, 1.0, false );
129 // StartPlot opens first page stream internally; use simple page number
130 BOOST_REQUIRE( plotter.StartPlot( wxT("1"), wxT("TestPage") ) );
131
132 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, false, false );
133 auto strokeFont = LoadStrokeFontUnique();
134 KIFONT::METRICS metrics; // not used for stroke fallback
135
136 // Plot near lower-left inside the page.
137 // Place text near the top of the page in internal units so after the 0.0072 scale it
138 // appears well within the MediaBox. Empirically m_paperSize.y ~ 116k internal units.
139 plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0.0, 0.0, 0.0, 1.0 ), sample, attrs,
140 strokeFont.get(), metrics );
141
142 plotter.EndPlot();
143
144 // Read file back and check for expected UTF-16 hex encodings for some code points
145 // We expect CMap to contain mappings. E.g. '041F' (Cyrillic capital Pe), '65E5'(日), '672C'(本).
146 std::string buffer2; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer2 ) );
147 auto contains = [&]( const char* needle ) { return PdfContains( buffer2, needle ); };
148
149 BOOST_CHECK_MESSAGE( contains( "041F" ), "Missing Cyrillic glyph mapping (041F)" );
150 BOOST_CHECK_MESSAGE( contains( "0420" ) || contains( "0440" ), "Missing Cyrillic glyph mapping (0420/0440)" );
151 BOOST_CHECK_MESSAGE( contains( "65E5" ), "Missing Japanese Kanji glyph mapping (65E5)" );
152 BOOST_CHECK_MESSAGE( contains( "672C" ), "Missing Japanese Kanji glyph mapping (672C)" );
153 BOOST_CHECK_MESSAGE( contains( "6F22" ) || contains( "6漢" ), "Expect Chinese Han character mapping (6F22 / 漢)" );
154
155 // Cleanup temp file (unless debugging requested)
156 // Optional: rasterize PDF to image (requires poppler 'pdftoppm').
157 // We treat absence of the tool as a skipped sub-check rather than a failure.
158 {
159 long darkPixels = 0;
160 if( RasterizePdfCountDark( pdfPath, 72, 240, darkPixels ) )
161 {
162 BOOST_CHECK_MESSAGE( darkPixels > 200,
163 "Rasterized PDF appears blank or too sparse (" << darkPixels
164 << " dark pixels)" );
165 }
166 else
167 {
168 BOOST_TEST_MESSAGE( "pdftoppm not available or failed; skipping raster validation" );
169 }
170 }
171
172 MaybeRemoveFile( pdfPath );
173}
174
175BOOST_AUTO_TEST_CASE( PlotMultilingualTextBold )
176{
177 const std::string sampleUtf8 = "ABCDEF Привет 日本語 漢字";
178 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
179
180 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode_bold" );
181
182 PDF_PLOTTER plotter;
183 SIMPLE_RENDER_SETTINGS renderSettings;
184 plotter.SetRenderSettings( &renderSettings );
185 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
186 plotter.SetViewport( VECTOR2I(0,0), 1.0, 1.0, false );
187 BOOST_REQUIRE( plotter.StartPlot( wxT("1"), wxT("TestPage") ) );
188
189 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, true, false );
190 auto strokeFont = LoadStrokeFontUnique();
191 KIFONT::METRICS metrics;
192 plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0.0, 0.0, 0.0, 1.0 ), sample, attrs,
193 strokeFont.get(), metrics );
194 plotter.EndPlot();
195 std::string buffer3; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer3 ) );
196 auto contains = [&]( const char* needle ) { return PdfContains( buffer3, needle ); };
197 BOOST_CHECK_MESSAGE( contains( "041F" ), "Missing Cyrillic glyph mapping (bold 041F)" );
198 BOOST_CHECK_MESSAGE( contains( "65E5" ), "Missing Japanese glyph mapping (bold 65E5)" );
199
200 MaybeRemoveFile( pdfPath );
201}
202
203BOOST_AUTO_TEST_CASE( PlotMultilingualTextItalic )
204{
205 const std::string sampleUtf8 = "ABCDEF Привет 日本語 漢字";
206 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
207 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode_italic" );
208 PDF_PLOTTER plotter;
209 SIMPLE_RENDER_SETTINGS renderSettings;
210
211 plotter.SetRenderSettings( &renderSettings );
212 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
213 plotter.SetViewport( VECTOR2I(0,0), 1.0, 1.0, false );
214 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ), wxT( "TestPage" ) ) );
215 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, false, true );
216 auto strokeFont = LoadStrokeFontUnique();
217 KIFONT::METRICS metrics;
218 plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0, 0, 0, 1 ), sample, attrs, strokeFont.get(), metrics );
219 plotter.EndPlot();
220
221 std::string buffer4; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer4 ) );
222 auto contains = [&]( const char* n ) { return PdfContains( buffer4, n ); };
223 BOOST_CHECK_MESSAGE( contains( "041F" ), "Missing Cyrillic glyph mapping (italic 041F)" );
224 BOOST_CHECK_MESSAGE( contains( "65E5" ), "Missing Japanese glyph mapping (italic 65E5)" );
225 MaybeRemoveFile( pdfPath );
226}
227
228BOOST_AUTO_TEST_CASE( PlotMultilingualTextBoldItalic )
229{
230 const std::string sampleUtf8 = "ABCDEF Привет 日本語 漢字";
231 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
232 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode_bolditalic" );
233 PDF_PLOTTER plotter;
234 SIMPLE_RENDER_SETTINGS renderSettings;
235
236 plotter.SetRenderSettings( &renderSettings );
237 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
238
239 plotter.SetViewport( VECTOR2I( 0, 0 ), 1.0, 1.0, false );
240 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ), wxT( "TestPage" ) ) );
241
242 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, true, true );
243 auto strokeFont = LoadStrokeFontUnique();
244 KIFONT::METRICS metrics;
245
246 plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0, 0, 0, 1 ), sample, attrs, strokeFont.get(), metrics );
247 plotter.EndPlot();
248
249 std::string buffer5; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer5 ) );
250 auto contains = [&]( const char* n ) { return PdfContains( buffer5, n ); };
251 BOOST_CHECK_MESSAGE( contains( "041F" ), "Missing Cyrillic glyph mapping (bold-italic 041F)" );
252 BOOST_CHECK_MESSAGE( contains( "65E5" ), "Missing Japanese glyph mapping (bold-italic 65E5)" );
253 MaybeRemoveFile( pdfPath );
254}
255
256// Test Y offset bounding box fix: ensure characters are not clipped when Y offset is applied
257BOOST_AUTO_TEST_CASE( PlotMultilingualTextWithYOffset )
258{
259 // Temporarily modify the Y offset configuration
260 ADVANCED_CFG& cfg = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() );
261 double originalOffset = cfg.m_PDFStrokeFontYOffset;
262 cfg.m_PDFStrokeFontYOffset = 0.2; // 20% of EM unit offset upward
263
264 const std::string sampleUtf8 = "Yg Test ñ"; // characters with ascenders and descenders
265 wxString sample = wxString::FromUTF8( sampleUtf8.c_str() );
266 wxString pdfPath = getTempPdfPath( "kicad_pdf_unicode_yoffset" );
267
268 PDF_PLOTTER plotter;
269 SIMPLE_RENDER_SETTINGS renderSettings;
270
271 plotter.SetRenderSettings( &renderSettings );
272 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
273 plotter.SetViewport( VECTOR2I( 0, 0 ), 1.0, 1.0, false );
274 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ), wxT( "TestPage" ) ) );
275
276 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 4000, 400, false, false );
277 auto strokeFont = LoadStrokeFontUnique();
278 KIFONT::METRICS metrics;
279 plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0, 0, 0, 1 ), sample, attrs, strokeFont.get(), metrics );
280 plotter.EndPlot();
281
282
283 // Restore original Y offset
284 cfg.m_PDFStrokeFontYOffset = originalOffset;
285
286 // Basic PDF validation and decompression
287 std::string buffer6; BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer6 ) );
288 BOOST_CHECK( buffer6.rfind( "%PDF", 0 ) == 0 );
289
290 // Check that bounding boxes exist and are reasonable (not clipped)
291 // Look for d1 operators which specify character bounding boxes
292 BOOST_CHECK_MESSAGE( buffer6.find( "d1" ) != std::string::npos,
293 "PDF should contain d1 operators for glyph bounding boxes" );
294
295 MaybeRemoveFile( pdfPath );
296}
297
298BOOST_AUTO_TEST_CASE( PlotOutlineFontEmbedding )
299{
300 wxString pdfPath = getTempPdfPath( "kicad_pdf_outline_font" );
301
302 // Locate test font file (Noto Sans) in test resources
303 wxFileName fontFile( KI_TEST::GetTestDataRootDir() );
304 fontFile.RemoveLastDir();
305 fontFile.AppendDir( wxT( "resources" ) );
306 fontFile.AppendDir( wxT( "fonts" ) );
307 fontFile.SetFullName( wxT( "NotoSans-Regular.ttf" ) );
308 wxString fontPath = fontFile.GetFullPath();
309
310 BOOST_REQUIRE( wxFileExists( fontPath ) );
311
312 PDF_PLOTTER plotter;
313 SIMPLE_RENDER_SETTINGS renderSettings;
314
315 plotter.SetRenderSettings( &renderSettings );
316 BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
317 plotter.SetViewport( VECTOR2I(0,0), 1.0, 1.0, false );
318 BOOST_REQUIRE( plotter.StartPlot( wxT("1"), wxT("OutlineFont") ) );
319
320 TEXT_ATTRIBUTES attrs = BuildTextAttributes( 4000, 0, false, false );
321
322 std::vector<wxString> embeddedFonts;
323 embeddedFonts.push_back( fontPath );
324
325 KIFONT::FONT* outlineFont = KIFONT::FONT::GetFont( wxT( "Noto Sans" ), false, false, &embeddedFonts );
326 KIFONT::METRICS metrics;
327
328 wxString sample = wxString::FromUTF8( "Outline café" );
329
330 plotter.PlotText( VECTOR2I( 42000, 52000 ), COLOR4D( 0, 0, 0, 1 ), sample, attrs,
331 outlineFont, metrics );
332
333 plotter.EndPlot();
334
335 wxFFile file( pdfPath, "rb" );
336 BOOST_REQUIRE( file.IsOpened() );
337 wxFileOffset len = file.Length();
338 std::string buffer; buffer.resize( (size_t) len ); file.Read( buffer.data(), len );
339 BOOST_CHECK( buffer.rfind( "%PDF", 0 ) == 0 );
340
341 auto appendDecompressed = [&]() { std::string tmp; ReadPdfWithDecompressedStreams( pdfPath, tmp ); buffer.swap( tmp ); };
342 appendDecompressed();
343
344 BOOST_CHECK_MESSAGE( buffer.find( "/CIDFontType2" ) != std::string::npos,
345 "Expected CIDFontType2 descendant font" );
346 BOOST_CHECK_MESSAGE( buffer.find( "/FontFile2" ) != std::string::npos,
347 "Embedded outline font should include FontFile2 stream" );
348 BOOST_CHECK_MESSAGE( buffer.find( "AAAAAA+Noto-Sans" ) != std::string::npos,
349 "BaseFont should reference Noto Sans subset" );
350 BOOST_CHECK_MESSAGE( buffer.find( "00E9" ) != std::string::npos,
351 "ToUnicode map should include Latin character with accent" );
352 BOOST_CHECK_MESSAGE( buffer.find( "/KiCadOutline" ) != std::string::npos,
353 "Outline font resource entry missing" );
354
355 // Optional: rasterize PDF to image (requires poppler 'pdftoppm').
356 // We treat absence of the tool as a skipped sub-check rather than a failure.
357 {
358 wxString rasterBase = wxFileName::CreateTempFileName( wxT("kicad_pdf_raster") );
359 wxString cmd = wxString::Format( wxT("pdftoppm -r 72 -singlefile -png \"%s\" \"%s\""),
360 pdfPath, rasterBase );
361
362 int ret = wxExecute( cmd, wxEXEC_SYNC );
363
364 if( ret == 0 )
365 {
366 wxString pngPath = rasterBase + wxT(".png");
367
368 if( wxFileExists( pngPath ) )
369 {
370 // Ensure PNG handler is available
371 if( !wxImage::FindHandler( wxBITMAP_TYPE_PNG ) )
372 wxImage::AddHandler( new wxPNGHandler );
373
374 wxImage img( pngPath );
375 BOOST_REQUIRE_MESSAGE( img.IsOk(), "Failed to load rasterized PDF image" );
376
377 long darkPixels = 0;
378 int w = img.GetWidth();
379 int h = img.GetHeight();
380
381 for( int y = 0; y < h; ++y )
382 {
383 for( int x = 0; x < w; ++x )
384 {
385 unsigned char r = img.GetRed( x, y );
386 unsigned char g = img.GetGreen( x, y );
387 unsigned char b = img.GetBlue( x, y );
388
389 // Count any non-near-white pixel as drawn content
390 if( r < 240 || g < 240 || b < 240 )
391 ++darkPixels;
392 }
393 }
394
395 // Demand at least 100 non-white pixels to consider outline font rendered correctly.
396 // This threshold is lower than stroke font since outline fonts may render differently.
397 BOOST_CHECK_MESSAGE( darkPixels > 100,
398 "Rasterized PDF appears blank or too sparse (" << darkPixels
399 << " dark pixels). Outline font may not be rendering correctly." );
400
401 // Housekeeping
402 wxRemoveFile( pngPath );
403 }
404 else
405 {
406 BOOST_TEST_MESSAGE( "pdftoppm succeeded but PNG output missing; skipping raster validation" );
407 }
408 }
409 else
410 {
411 BOOST_TEST_MESSAGE( "pdftoppm not available or failed; skipping raster validation" );
412 }
413 }
414
415 MaybeRemoveFile( pdfPath );
416}
417
const char * name
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:147
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
virtual bool EndPlot() override
virtual bool OpenFile(const wxString &aFullFilename) override
Open or create the plot file aFullFilename.
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...
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...
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
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:151
Minimal concrete render settings suitable for plotters in tests.
double m_PDFStrokeFontYOffset
Vertical offset factor applied to stroke font glyph coordinates (in EM units) after Y inversion to co...
std::string GetTestDataRootDir()
int CountOccurrences(const std::string &aHaystack, const std::string &aNeedle)
Count occurrences of a substring in a string (overlapping allowed).
bool PdfContains(const std::string &aBuffer, const char *aNeedle)
Convenience contains check.
bool ReadPdfWithDecompressedStreams(const wxString &aPdfPath, std::string &aOutBuffer)
Read a PDF file and append best-effort decompressed contents of any Flate streams to the returned buf...
std::unique_ptr< KIFONT::STROKE_FONT > LoadStrokeFontUnique()
Load the default stroke font and return a unique_ptr for RAII deletion.
TEXT_ATTRIBUTES BuildTextAttributes(int aSizeIu=3000, int aStrokeWidth=300, bool aBold=false, bool aItalic=false)
Build a commonly used set of text attributes for plotting text in tests.
bool RasterizePdfCountDark(const wxString &aPdfPath, int aDpi, int aNearWhiteThresh, long &aOutDarkPixels)
Rasterize a PDF page to PNG using pdftoppm if available and count non-near-white pixels.
wxString MakeTempPdfPath(const wxString &aPrefix)
Make a temporary file path with .pdf extension using a given prefix.
void MaybeRemoveFile(const wxString &aPath, const wxString &aEnvVar=wxT("KICAD_KEEP_TEST_PDF"))
Remove a file unless the given environment variable is set (defaults to KICAD_KEEP_TEST_PDF).
Plotting engines similar to ps (PostScript, Gerber, svg)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(PlotMultilingualAllStylesMappings)
static wxString getTempPdfPath(const wxString &name)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695