~ubuntu-branches/ubuntu/precise/fritzing/precise

« back to all changes in this revision

Viewing changes to src/mainwindow_gerber.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Georges Khaznadar
  • Date: 2011-08-26 10:11:05 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110826101105-w5hmn7zcf93ig5v6
Tags: 0.6.3b-1
* upgrapded to the newer upstream version
* parameters of the function GraphicsUtils::distanceFromLine in 
  src/svg/groundplanegenerator.cpp:767 are now declared as doubles,
  which Closes: #636441
* the new version fixes src/utils/folderutils.cpp, which
  Closes: #636061

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*******************************************************************
2
 
 
3
 
Part of the Fritzing project - http://fritzing.org
4
 
Copyright (c) 2007-2011 Fachhochschule Potsdam - http://fh-potsdam.de
5
 
 
6
 
Fritzing is free software: you can redistribute it and/or modify
7
 
it under the terms of the GNU General Public License as published by
8
 
the Free Software Foundation, either version 3 of the License, or
9
 
(at your option) any later version.
10
 
 
11
 
Fritzing 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 Fritzing.  If not, see <http://www.gnu.org/licenses/>.
18
 
 
19
 
********************************************************************
20
 
 
21
 
$Revision: 5219 $:
22
 
$Author: cohen@irascible.com $:
23
 
$Date: 2011-07-11 14:13:40 +0200 (Mon, 11 Jul 2011) $
24
 
 
25
 
********************************************************************/
26
 
 
27
 
#include <QMessageBox>
28
 
#include <QFileDialog>
29
 
#include <QSvgRenderer>
30
 
 
31
 
#include "mainwindow.h"
32
 
#include "debugdialog.h"
33
 
#include "fsvgrenderer.h"
34
 
#include "svg/svg2gerber.h"
35
 
#include "sketch/pcbsketchwidget.h"
36
 
#include "svg/svgfilesplitter.h"
37
 
#include "svg/groundplanegenerator.h"
38
 
#include "utils/graphicsutils.h"
39
 
#include "utils/textutils.h"
40
 
#include "utils/folderutils.h"
41
 
#include "items/logoitem.h"
42
 
 
43
 
static QRegExp AaCc("[aAcC]");
44
 
 
45
 
////////////////////////////////////////////
46
 
 
47
 
void MainWindow::exportToGerber() {
48
 
 
49
 
    //NOTE: this assumes just one board per sketch
50
 
 
51
 
    // grab the list of parts
52
 
    ItemBase * board = m_pcbGraphicsView->findBoard();
53
 
    // barf an error if there's no board
54
 
    if (!board) {
55
 
        QMessageBox::critical(this, tr("Fritzing"),
56
 
                   tr("Your sketch does not have a board yet!  Please add a PCB in order to export to Gerber."));
57
 
        return;
58
 
    }
59
 
 
60
 
    QString exportDir = QFileDialog::getExistingDirectory(this, tr("Choose a folder for exporting"),
61
 
                                             defaultSaveFolder(),
62
 
                                             QFileDialog::ShowDirsOnly
63
 
                                             | QFileDialog::DontResolveSymlinks);
64
 
 
65
 
        if (exportDir.isEmpty()) return;
66
 
 
67
 
        FolderUtils::setOpenSaveFolder(exportDir);
68
 
        exportToGerber(exportDir, board, true);
69
 
}
70
 
 
71
 
void MainWindow::exportToGerber(const QString & exportDir, ItemBase * board, bool displayMessageBoxes) 
72
 
{
73
 
        if (board == NULL) {
74
 
                board = m_pcbGraphicsView->findBoard();
75
 
        }
76
 
        if (board == NULL) {
77
 
                DebugDialog::debug("board not found");
78
 
                return;
79
 
        }
80
 
 
81
 
        LayerList viewLayerIDs = ViewLayer::copperLayers(ViewLayer::Bottom);
82
 
        int copperInvalidCount = doCopper(board, viewLayerIDs, "Copper0", "_copperBottom.gbl", exportDir, displayMessageBoxes);
83
 
 
84
 
        if (m_pcbGraphicsView->boardLayers() == 2) {
85
 
                viewLayerIDs = ViewLayer::copperLayers(ViewLayer::Top);
86
 
                copperInvalidCount += doCopper(board, viewLayerIDs, "Copper1", "_copperTop.gtl", exportDir, displayMessageBoxes);
87
 
        }
88
 
 
89
 
        LayerList maskLayerIDs = ViewLayer::maskLayers(ViewLayer::Bottom);
90
 
        int maskInvalidCount = doMask(maskLayerIDs, "Mask0", "_maskBottom.gbs", board, exportDir, displayMessageBoxes);
91
 
 
92
 
        if (m_pcbGraphicsView->boardLayers() == 2) {
93
 
                maskLayerIDs = ViewLayer::maskLayers(ViewLayer::Top);
94
 
                maskInvalidCount += doMask(maskLayerIDs, "Mask1", "_maskTop.gts", board, exportDir, displayMessageBoxes);
95
 
        }
96
 
 
97
 
    LayerList silkLayerIDs;
98
 
    silkLayerIDs << ViewLayer::Silkscreen1  << ViewLayer::Silkscreen1Label;
99
 
        int silkInvalidCount = doSilk(silkLayerIDs, "Silk1", "_silkTop.gto", board, exportDir, displayMessageBoxes);
100
 
    silkLayerIDs.clear();
101
 
    silkLayerIDs << ViewLayer::Silkscreen0  << ViewLayer::Silkscreen0Label;
102
 
        silkInvalidCount += doSilk(silkLayerIDs, "Silk0", "_silkBottom.gbo", board, exportDir, displayMessageBoxes);
103
 
 
104
 
    // now do it for the outline/contour
105
 
    LayerList outlineLayerIDs;
106
 
    outlineLayerIDs << ViewLayer::Board;
107
 
        QSizeF imageSize;
108
 
        bool empty;
109
 
        QString svgOutline = m_pcbGraphicsView->renderToSVG(FSvgRenderer::printerScale(), outlineLayerIDs, outlineLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
110
 
    if (svgOutline.isEmpty()) {
111
 
        displayMessage(tr("outline is empty"), displayMessageBoxes);
112
 
        return;
113
 
    }
114
 
 
115
 
        QXmlStreamReader streamReader(svgOutline);
116
 
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
117
 
 
118
 
        QDomDocument domDocument;
119
 
        QString errorStr;
120
 
        int errorLine;
121
 
        int errorColumn;
122
 
    bool result = domDocument.setContent(svgOutline, &errorStr, &errorLine, &errorColumn);
123
 
    if (!result) {
124
 
                displayMessage(tr("outline file export failure (1)"), displayMessageBoxes);
125
 
        return;
126
 
    }
127
 
 
128
 
    // create copper0 gerber from svg
129
 
    SVG2gerber outlineGerber;
130
 
        int outlineInvalidCount = outlineGerber.convert(svgOutline, m_pcbGraphicsView->boardLayers() == 2, "contour", SVG2gerber::ForOutline, svgSize * GraphicsUtils::StandardFritzingDPI);
131
 
        if (outlineInvalidCount > 0) {
132
 
                outlineInvalidCount = 0;
133
 
                svgOutline = clipToBoard(svgOutline, board, "board");
134
 
                outlineInvalidCount = outlineGerber.convert(svgOutline, m_pcbGraphicsView->boardLayers() == 2, "contour", SVG2gerber::ForOutline, svgSize * GraphicsUtils::StandardFritzingDPI);
135
 
        }
136
 
 
137
 
        doDrill(board, exportDir, displayMessageBoxes);
138
 
 
139
 
    // contour / board outline
140
 
    QString contourFile = exportDir + "/" +
141
 
                          QFileInfo(m_fileName).fileName().remove(FritzingSketchExtension)
142
 
                          + "_contour.gm1";
143
 
    QFile contourOut(contourFile);
144
 
        if (!contourOut.open(QIODevice::WriteOnly | QIODevice::Text)) {
145
 
                displayMessage(tr("outline file export failure (2)"), displayMessageBoxes);
146
 
                return;
147
 
        }
148
 
 
149
 
    QTextStream contourStream(&contourOut);
150
 
    contourStream << outlineGerber.getGerber();
151
 
 
152
 
        if (outlineInvalidCount > 0 || silkInvalidCount > 0 || copperInvalidCount > 0 || maskInvalidCount) {
153
 
                QString s;
154
 
                if (outlineInvalidCount > 0) s += tr("the board outline layer, ");
155
 
                if (silkInvalidCount > 0) s += tr("silkscreen layer(s), ");
156
 
                if (copperInvalidCount > 0) s += tr("copper layer(s), ");
157
 
                if (maskInvalidCount > 0) s += tr("mask layer(s), ");
158
 
                s.chop(2);
159
 
                displayMessage(tr("Unable to translate svg curves in ").arg(s), displayMessageBoxes);
160
 
        }
161
 
 
162
 
}
163
 
 
164
 
int MainWindow::doCopper(ItemBase * board, LayerList & viewLayerIDs, const QString & copperName, const QString & copperSuffix, const QString & exportDir, bool displayMessageBoxes) 
165
 
{
166
 
        QSizeF imageSize;
167
 
        bool empty;
168
 
        QString svg = m_pcbGraphicsView->renderToSVG(FSvgRenderer::printerScale(), viewLayerIDs, viewLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
169
 
        if (svg.isEmpty()) {
170
 
                displayMessage(tr("%1 file export failure (1)").arg(copperName), displayMessageBoxes);
171
 
                return 0;
172
 
        }
173
 
 
174
 
        QXmlStreamReader streamReader(svg);
175
 
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
176
 
 
177
 
        svg = clipToBoard(svg, board, copperName);
178
 
        if (svg.isEmpty()) {
179
 
                displayMessage(tr("%1 file export failure (3)").arg(copperName), displayMessageBoxes);
180
 
                return 0;
181
 
        }
182
 
 
183
 
    // create copper gerber from svg
184
 
    SVG2gerber copperGerber;
185
 
        int copperInvalidCount = copperGerber.convert(svg, m_pcbGraphicsView->boardLayers() == 2, copperName, SVG2gerber::ForNormal, svgSize * GraphicsUtils::StandardFritzingDPI);
186
 
 
187
 
    QString copperFile = exportDir + "/" +
188
 
                          QFileInfo(m_fileName).fileName().remove(FritzingSketchExtension)
189
 
                          + copperSuffix;
190
 
    QFile copperOut(copperFile);
191
 
        if (!copperOut.open(QIODevice::WriteOnly | QIODevice::Text)) {
192
 
                displayMessage(tr("%1 file export failure (3)").arg(copperName), displayMessageBoxes);
193
 
                return 0;
194
 
        }
195
 
 
196
 
    QTextStream copperStream(&copperOut);
197
 
    copperStream << copperGerber.getGerber();
198
 
        copperStream.flush();
199
 
        copperOut.close();
200
 
 
201
 
        return copperInvalidCount;
202
 
}
203
 
 
204
 
 
205
 
int MainWindow::doSilk(LayerList silkLayerIDs, const QString & silkName, const QString & gerberSuffix, ItemBase * board, const QString & exportDir, bool displayMessageBoxes ) 
206
 
{
207
 
        QSizeF imageSize;
208
 
        bool empty;
209
 
        QString svgSilk = m_pcbGraphicsView->renderToSVG(FSvgRenderer::printerScale(), silkLayerIDs, silkLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
210
 
    if (svgSilk.isEmpty()) {
211
 
                displayMessage(tr("silk file export failure (1)"), displayMessageBoxes);
212
 
        return 0;
213
 
    }
214
 
 
215
 
        if (empty) {
216
 
                // don't bother with file
217
 
                return 0;
218
 
        }
219
 
 
220
 
        QXmlStreamReader streamReader(svgSilk);
221
 
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
222
 
 
223
 
        svgSilk = clipToBoard(svgSilk, board, silkName);
224
 
        if (svgSilk.isEmpty()) {
225
 
                displayMessage(tr("silk export failure"), displayMessageBoxes);
226
 
                return 0;
227
 
        }
228
 
 
229
 
    // create silk gerber from svg
230
 
    SVG2gerber silkGerber;
231
 
        int silkInvalidCount = silkGerber.convert(svgSilk, m_pcbGraphicsView->boardLayers() == 2, silkName, SVG2gerber::ForNormal, svgSize * GraphicsUtils::StandardFritzingDPI);
232
 
 
233
 
    QString silkFile = exportDir + "/" +
234
 
                          QFileInfo(m_fileName).fileName().remove(FritzingSketchExtension)
235
 
                          + gerberSuffix;
236
 
    QFile silkOut(silkFile);
237
 
        if (!silkOut.open(QIODevice::WriteOnly | QIODevice::Text)) {
238
 
                displayMessage(tr("silk file export failure (2)"), displayMessageBoxes);
239
 
                return 0;
240
 
        }
241
 
 
242
 
    QTextStream silkStream(&silkOut);
243
 
    silkStream << silkGerber.getGerber();
244
 
        silkStream.flush();
245
 
        silkOut.close();
246
 
 
247
 
        return silkInvalidCount;
248
 
}
249
 
 
250
 
 
251
 
int MainWindow::doDrill(ItemBase * board, const QString & exportDir, bool displayMessageBoxes) 
252
 
{
253
 
    LayerList drillLayerIDs;
254
 
    drillLayerIDs << ViewLayer::Copper0;
255
 
 
256
 
        QSizeF imageSize;
257
 
        bool empty;
258
 
        QString svgDrill = m_pcbGraphicsView->renderToSVG(FSvgRenderer::printerScale(), drillLayerIDs, drillLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
259
 
    if (svgDrill.isEmpty()) {
260
 
                displayMessage(tr("drill file export failure (1)"), displayMessageBoxes);
261
 
        return 0;
262
 
    }
263
 
 
264
 
        if (empty) {
265
 
                // don't bother with file
266
 
                return 0;
267
 
        }
268
 
 
269
 
        QXmlStreamReader streamReader(svgDrill);
270
 
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
271
 
 
272
 
        svgDrill = clipToBoard(svgDrill, board, "Copper0");
273
 
        if (svgDrill.isEmpty()) {
274
 
                displayMessage(tr("drill export failure"), displayMessageBoxes);
275
 
                return 0;
276
 
        }
277
 
 
278
 
    // create silk gerber from svg
279
 
    SVG2gerber drillGerber;
280
 
        int drillInvalidCount = drillGerber.convert(svgDrill, m_pcbGraphicsView->boardLayers() == 2, "drill", SVG2gerber::ForDrill, svgSize * GraphicsUtils::StandardFritzingDPI);
281
 
 
282
 
 
283
 
                // drill file
284
 
        QString drillFile = exportDir + "/" +
285
 
                                                          QFileInfo(m_fileName).fileName().remove(FritzingSketchExtension)
286
 
                                                          + "_drill.txt";
287
 
        QFile drillOut(drillFile);
288
 
        if (!drillOut.open(QIODevice::WriteOnly | QIODevice::Text)) {
289
 
                displayMessage(tr("drill file export failure (5)"), displayMessageBoxes);
290
 
                return 0;
291
 
        }
292
 
 
293
 
        QTextStream drillStream(&drillOut);
294
 
        drillStream << drillGerber.getGerber();
295
 
        drillStream.flush();
296
 
        drillOut.close();
297
 
 
298
 
        return drillInvalidCount;
299
 
}
300
 
 
301
 
int MainWindow::doMask(LayerList maskLayerIDs, const QString &maskName, const QString & gerberSuffix, ItemBase * board, const QString & exportDir, bool displayMessageBoxes ) 
302
 
{
303
 
        // don't want these in the mask laqyer
304
 
        QList<ItemBase *> copperLogoItems;
305
 
        foreach (QGraphicsItem * item, m_pcbGraphicsView->items()) {
306
 
                CopperLogoItem * logoItem = dynamic_cast<CopperLogoItem *>(item);
307
 
                if (logoItem && logoItem->isVisible()) {
308
 
                        copperLogoItems.append(logoItem);
309
 
                        logoItem->setVisible(false);
310
 
                }
311
 
        }
312
 
 
313
 
        QSizeF imageSize;
314
 
        bool empty;
315
 
        QString svgMask = m_pcbGraphicsView->renderToSVG(FSvgRenderer::printerScale(), maskLayerIDs, maskLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
316
 
    if (svgMask.isEmpty()) {
317
 
                displayMessage(tr("mask file export failure (1)"), displayMessageBoxes);
318
 
        return 0;
319
 
    }
320
 
 
321
 
        foreach (ItemBase * logoItem, copperLogoItems) {
322
 
                logoItem->setVisible(true);
323
 
        }
324
 
 
325
 
        if (empty) {
326
 
                // don't bother with file
327
 
                return 0;
328
 
        }
329
 
 
330
 
        QDomDocument domDocument;
331
 
        QString errorStr;
332
 
        int errorLine;
333
 
        int errorColumn;
334
 
        bool result = domDocument.setContent(svgMask, &errorStr, &errorLine, &errorColumn);
335
 
        if (!result) {
336
 
                displayMessage(tr("%1 file export failure (2)").arg(maskName), displayMessageBoxes);
337
 
                return 0;
338
 
        }
339
 
 
340
 
        QXmlStreamReader streamReader(svgMask);
341
 
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
342
 
 
343
 
        svgMask = clipToBoard(svgMask, board, maskName);
344
 
        if (svgMask.isEmpty()) {
345
 
                displayMessage(tr("mask export failure"), displayMessageBoxes);
346
 
                return 0;
347
 
        }
348
 
 
349
 
    // create mask gerber from svg
350
 
    SVG2gerber maskGerber;
351
 
        int maskInvalidCount = maskGerber.convert(svgMask, m_pcbGraphicsView->boardLayers() == 2, maskName, SVG2gerber::ForMask, svgSize * GraphicsUtils::StandardFritzingDPI);
352
 
 
353
 
    QString maskFile = exportDir + "/" +
354
 
                          QFileInfo(m_fileName).fileName().remove(FritzingSketchExtension)
355
 
                          + gerberSuffix;
356
 
    QFile maskOut(maskFile);
357
 
        if (!maskOut.open(QIODevice::WriteOnly | QIODevice::Text)) {
358
 
                displayMessage(tr("mask file export failure (2)"), displayMessageBoxes);
359
 
                return 0;
360
 
        }
361
 
 
362
 
    QTextStream maskStream(&maskOut);
363
 
    maskStream << maskGerber.getGerber();
364
 
        maskStream.flush();
365
 
        maskOut.close();
366
 
 
367
 
        return maskInvalidCount;
368
 
}
369
 
 
370
 
void MainWindow::displayMessage(const QString & message, bool displayMessageBoxes) {
371
 
        // don't use QMessageBox if running conversion as a service
372
 
        if (displayMessageBoxes) {
373
 
                QMessageBox::warning(this, tr("Fritzing"), message);
374
 
                return;
375
 
        }
376
 
 
377
 
        DebugDialog::debug(message);
378
 
}
379
 
 
380
 
QString MainWindow::clipToBoard(QString svgString, ItemBase * board, const QString & layerName) {
381
 
        QDomDocument domDocument1;
382
 
        QString errorStr;
383
 
        int errorLine;
384
 
        int errorColumn;
385
 
        bool result = domDocument1.setContent(svgString, &errorStr, &errorLine, &errorColumn);
386
 
        if (!result) {
387
 
                return "";
388
 
        }
389
 
 
390
 
        QDomDocument domDocument2;
391
 
        domDocument2.setContent(svgString, &errorStr, &errorLine, &errorColumn);
392
 
 
393
 
        bool anyConverted = false;
394
 
    if (TextUtils::squashElement(domDocument1, "text", "", QRegExp())) {
395
 
        anyConverted = true; 
396
 
        }
397
 
 
398
 
        // gerber can't handle ellipses that are rotated, so cull them all
399
 
    if (TextUtils::squashElement(domDocument1, "ellipse", "", QRegExp())) {
400
 
                anyConverted = true;
401
 
    }
402
 
 
403
 
        // gerber can't handle paths with curves
404
 
    if (TextUtils::squashElement(domDocument1, "path", "d", AaCc)) {
405
 
                anyConverted = true;
406
 
    }
407
 
 
408
 
        QVector <QDomElement> leaves1;
409
 
        int transformCount1 = 0;
410
 
        QDomElement e1 = domDocument1.documentElement();
411
 
        TextUtils::collectLeaves(e1, transformCount1, leaves1);
412
 
 
413
 
        QVector <QDomElement> leaves2;
414
 
        int transformCount2 = 0;
415
 
        QDomElement e2 = domDocument2.documentElement();
416
 
        TextUtils::collectLeaves(e2, transformCount2, leaves2);
417
 
 
418
 
        qreal res = GraphicsUtils::StandardFritzingDPI;
419
 
        QRectF source = board->boundingRect();
420
 
        int twidth = res * source.width() / FSvgRenderer::printerScale();
421
 
        int theight = res * source.height() / FSvgRenderer::printerScale();
422
 
 
423
 
        svgString = TextUtils::removeXMLEntities(domDocument1.toString());
424
 
        QXmlStreamReader reader(svgString);
425
 
        QSvgRenderer renderer(&reader);
426
 
        bool anyClipped = false;
427
 
        for (int i = 0; i < transformCount1; i++) {
428
 
                QString n = QString::number(i);
429
 
                QRectF bounds = renderer.boundsOnElement(n);
430
 
                QMatrix m = renderer.matrixForElement(n);
431
 
                QDomElement element = leaves1.at(i);
432
 
                QString ms = element.attribute("transform");
433
 
                if (!ms.isEmpty()) {
434
 
                        m *= TextUtils::transformStringToMatrix(ms);
435
 
                }
436
 
                QRectF mBounds = m.mapRect(bounds);
437
 
                if (mBounds.left() < 0 || mBounds.top() < 0 || bounds.right() > twidth || bounds.bottom() > theight) {
438
 
                        // element is outside of bounds, squash it so it will be clipped
439
 
                        element.setTagName("g");
440
 
                        anyClipped = anyConverted = true;
441
 
                }       
442
 
        }
443
 
 
444
 
        if (anyClipped) {
445
 
                svgString = TextUtils::removeXMLEntities(domDocument1.toString());
446
 
        }
447
 
 
448
 
    if (anyConverted) {
449
 
                for (int i = 0; i < transformCount1; i++) {
450
 
                        QDomElement element1 = leaves1.at(i);
451
 
                        if (element1.tagName() != "g") {
452
 
                                QDomElement element2 = leaves2.at(i);
453
 
                                element2.setTagName("g");
454
 
                        }
455
 
                }
456
 
                
457
 
                QString svg = TextUtils::removeXMLEntities(domDocument2.toString());
458
 
 
459
 
                QSize imgSize(twidth, theight);
460
 
 
461
 
                // expand the svg to fill the space of the image
462
 
                QRegExp widthFinder("width=[^i]+in.");
463
 
                int ix = widthFinder.indexIn(svg);
464
 
                if (ix >= 0) {
465
 
                        svg.replace(ix, widthFinder.cap(0).length(), QString("width=\"%1px\"").arg(twidth));
466
 
                }
467
 
                QRegExp heightFinder("height=[^i]+in.");
468
 
                ix = heightFinder.indexIn(svg);
469
 
                if (ix > 0) {
470
 
                        svg.replace(ix, heightFinder.cap(0).length(), QString("height=\"%1px\"").arg(theight));
471
 
                }
472
 
 
473
 
                QStringList exceptions;
474
 
                exceptions << "none" << "";
475
 
                QString toColor("#000000");
476
 
                QByteArray svgByteArray;
477
 
                SvgFileSplitter::changeColors(svg, toColor, exceptions, svgByteArray);
478
 
 
479
 
                QImage image(imgSize, QImage::Format_RGB32);
480
 
                image.fill(0xffffffff);
481
 
                image.setDotsPerMeterX(res * GraphicsUtils::InchesPerMeter);
482
 
                image.setDotsPerMeterY(res * GraphicsUtils::InchesPerMeter);
483
 
                QRectF target(0, 0, twidth, theight);
484
 
 
485
 
                QSvgRenderer renderer(svgByteArray);
486
 
                QPainter painter;
487
 
                painter.begin(&image);
488
 
                renderer.render(&painter, target);
489
 
                painter.end();
490
 
                image.invertPixels();                           // need white pixels on a black background for GroundPlaneGenerator
491
 
                //image.save("output.png");
492
 
 
493
 
                GroundPlaneGenerator gpg;
494
 
                gpg.scanImage(image, image.width(), image.height(), GraphicsUtils::StandardFritzingDPI / res, GraphicsUtils::StandardFritzingDPI, "#ffffff", layerName, false, 1, false, QSizeF(0, 0), 0);
495
 
                
496
 
                if (gpg.newSVGs().count() > 0) {
497
 
                        QDomDocument doc;
498
 
                        TextUtils::mergeSvg(doc, svgString, "");
499
 
                        foreach (QString gsvg, gpg.newSVGs()) {
500
 
                                TextUtils::mergeSvg(doc, gsvg, "");
501
 
                        }
502
 
                        svgString = TextUtils::mergeSvgFinish(doc);
503
 
                }
504
 
        }
505
 
 
506
 
        return svgString;
507
 
}