FreeCAD

Форк
0
/
PagePrinter.cpp 
409 строк · 15.3 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2023 WandererFan <wandererfan@gmail.com>                *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  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 Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
#include <QApplication>
27
#include <QMessageBox>
28
#include <QPageLayout>
29
#include <QPageSize>
30
#include <QPaintEngine>
31
#include <QPainter>
32
#include <QPdfWriter>
33
#include <QPrintDialog>
34
#include <QPrintPreviewDialog>
35
#include <QPrinter>
36
#endif
37

38
#include <App/Application.h>
39
#include <App/Document.h>
40
#include <App/DocumentObject.h>
41
#include <Base/Console.h>
42
#include <Base/Stream.h>
43
#include <Base/Tools.h>
44
#include <Gui/Application.h>
45
#include <Gui/Command.h>
46
#include <Gui/Document.h>
47
#include <Gui/ViewProvider.h>
48

49
#include <Mod/TechDraw/App/DrawPage.h>
50
#include <Mod/TechDraw/App/DrawPagePy.h>
51
#include <Mod/TechDraw/App/DrawTemplate.h>
52
#include <Mod/TechDraw/App/Preferences.h>
53

54
#include "PagePrinter.h"
55
#include "QGSPage.h"
56
#include "Rez.h"
57
#include "ViewProviderPage.h"
58

59
using namespace TechDrawGui;
60
using namespace TechDraw;
61

62
constexpr double A4Heightmm = 297.0;
63
constexpr double A4Widthmm = 210.0;
64
constexpr double mmPerInch = 25.4;
65

66

67
/* TRANSLATOR TechDrawGui::PagePrinter */
68

69
//TYPESYSTEM_SOURCE_ABSTRACT(TechDrawGui::PagePrinter)
70

71
PagePrinter::PagePrinter(ViewProviderPage* pageVp)
72
    : m_vpPage(pageVp), m_orientation(QPageLayout::Landscape),
73
      m_paperSize(QPageSize::A4), m_pagewidth(0.0), m_pageheight(0.0)
74
{
75
}
76

77
void PagePrinter::setScene(QGSPage* scene)
78
{
79
    m_scene = scene;
80
}
81

82
void PagePrinter::setDocumentName(const std::string& name) { m_documentName = name; }
83

84

85
//! retrieve the attributes of a DrawPage and its Template
86
PaperAttributes PagePrinter::getPaperAttributes(TechDraw::DrawPage* dPage)
87
{
88
    PaperAttributes result;
89
    if (!dPage) {
90
        return result;
91
    }
92
    double width = A4Widthmm;
93
    double height = A4Heightmm;
94
    auto pageTemplate(dynamic_cast<TechDraw::DrawTemplate*>(dPage->Template.getValue()));
95
    if (pageTemplate) {
96
        width = pageTemplate->Width.getValue();
97
        height = pageTemplate->Height.getValue();
98
    }
99
    result.pagewidth = width;
100
    result.pageheight = height;
101

102
    //Qt's page size determination assumes Portrait orientation. To get the right paper size
103
    //we need to ask in the proper form.
104
    QPageSize::PageSizeId paperSizeID =
105
        QPageSize::id(QSizeF(std::min(width, height), std::max(width, height)),
106
                      QPageSize::Millimeter, QPageSize::FuzzyOrientationMatch);
107
    result.paperSize =  paperSizeID;
108

109
    result.orientation = (QPageLayout::Orientation)dPage->getOrientation();
110
    if (result.paperSize == QPageSize::Ledger) {
111
        // Ledger size paper orientation is reversed inside Qt
112
        result.orientation =(QPageLayout::Orientation)(1 - result.orientation);
113
    }
114

115
    return result;
116
}
117

118
void PagePrinter::getPaperAttributes()
119
{
120
    PaperAttributes attr = getPaperAttributes(m_vpPage->getDrawPage());
121
    m_pagewidth = attr.pagewidth;
122
    m_pageheight = attr.pageheight;
123
    m_paperSize = attr.paperSize;
124
    m_orientation = attr.orientation;
125
}
126

127
//! construct a page layout object that reflects the characteristics of a DrawPage
128
//static
129
void PagePrinter::makePageLayout(TechDraw::DrawPage* dPage, QPageLayout& pageLayout, double& width,
130
                                double& height)
131
{
132
    PaperAttributes attr = getPaperAttributes(dPage);
133
    width = attr.pagewidth;
134
    height = attr.pageheight;
135
    pageLayout.setPageSize(QPageSize(attr.paperSize));
136
    pageLayout.setOrientation(attr.orientation);
137
}
138

139
/// print the Page associated with the parent MDIViewPage as a Pdf file
140
void PagePrinter::printPdf(std::string file)
141
{
142
//    Base::Console().Message("PP::printPdf(%s)\n", file.c_str());
143
    if (file.empty()) {
144
        Base::Console().Warning("PagePrinter - no file specified\n");
145
        return;
146
    }
147

148
    // set up the pdfwriter
149
    QString outputFile = QString::fromUtf8(file.data(), file.size());
150
    QPdfWriter pdfWriter(outputFile);
151
    QPageLayout pageLayout = pdfWriter.pageLayout();
152
    QString documentName = QString::fromUtf8(m_vpPage->getDrawPage()->getNameInDocument());
153
    pdfWriter.setTitle(documentName);
154
    // default pdfWriter dpi is 1200.
155

156
    // set up the page layout
157
    auto dPage = m_vpPage->getDrawPage();
158
    double width = A4Heightmm;//default to A4 Landscape 297 x 210
159
    double height = A4Widthmm;
160
    makePageLayout(dPage, pageLayout, width, height);
161
    pdfWriter.setPageLayout(pageLayout);
162

163
    // first page does not respect page layout unless painter is created after
164
    // pdfWriter layout is established.
165
    QPainter painter(&pdfWriter);
166

167
    // render the page
168
    QRectF sourceRect(0.0, Rez::guiX(-height), Rez::guiX(width), Rez::guiX(height));
169
    double dpmm = pdfWriter.resolution() / mmPerInch;
170
    int twide = int(std::round(width * dpmm));
171
    int thigh = int(std::round(height * dpmm));
172
    QRect targetRect(0, 0, twide, thigh);
173
    renderPage(m_vpPage, painter, sourceRect, targetRect);
174
}
175

176

177
/// print the Page associated with the parent MDIViewPage
178
void PagePrinter::print(QPrinter* printer)
179
{
180
//    Base::Console().Message("PP::print(printer)\n");
181
    QPageLayout pageLayout = printer->pageLayout();
182

183
    TechDraw::DrawPage* dp = m_vpPage->getDrawPage();
184
    double width = A4Heightmm;//default to A4 Landscape 297 x 210
185
    double height = A4Widthmm;
186
    makePageLayout(dp, pageLayout, width, height);
187
    printer->setPageLayout(pageLayout);
188

189
    QPainter painter(printer);
190

191
    QRect targetRect = printer->pageLayout().fullRectPixels(printer->resolution());
192
    QRectF sourceRect(0.0, Rez::guiX(-height), Rez::guiX(width), Rez::guiX(height));
193
    renderPage(m_vpPage, painter, sourceRect, targetRect);
194
}
195

196
//static routine to print all pages in a document
197
void PagePrinter::printAll(QPrinter* printer, App::Document* doc)
198
{
199
//    Base::Console().Message("PP::printAll()\n");
200

201
    QPageLayout pageLayout = printer->pageLayout();
202
    std::vector<App::DocumentObject*> docObjs =
203
        doc->getObjectsOfType(TechDraw::DrawPage::getClassTypeId());
204
    auto firstPage = docObjs.front();
205

206
    auto dPage = static_cast<TechDraw::DrawPage*>(firstPage);
207
    double width = A4Heightmm;//default to A4 Landscape 297 x 210
208
    double height = A4Widthmm;
209
    makePageLayout(dPage, pageLayout, width, height);
210
    printer->setPageLayout(pageLayout);
211
    QPainter painter(printer);
212

213
    bool firstTime = true;
214
    for (auto& obj : docObjs) {
215
        Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(obj);
216
        if (!vp) {
217
            continue;// can't print this one
218
        }
219
        auto* vpp = dynamic_cast<TechDrawGui::ViewProviderPage*>(vp);
220
        if (!vpp) {
221
            continue;// can't print this one
222
        }
223

224
        auto dPage = static_cast<TechDraw::DrawPage*>(obj);
225
        double width = A4Heightmm;//default to A4 Landscape 297 x 210
226
        double height = A4Widthmm;
227
        makePageLayout(dPage, pageLayout, width, height);
228
        printer->setPageLayout(pageLayout);
229

230
        //for some reason the first page doesn't obey the pageLayout, so we have to print
231
        //a sacrificial blank page, but we make it a feature instead of a bug by printing a
232
        //table of contents on the sacrificial page.
233
        // Note: if the painter(printer) occurs after the printer->setPageLayout, then the
234
        // first page will obey the layout.  This would mean creating the painter inside the
235
        // loop.
236
        // if (firstTime) {
237
        //     firstTime = false;
238
        //     printBannerPage(printer, painter, pageLayout, doc, docObjs);
239
        // }
240
        if (!firstTime) {
241
            printer->newPage();
242
        }
243
        firstTime = false;
244
        QRectF sourceRect(0.0, Rez::guiX(-height), Rez::guiX(width), Rez::guiX(height));
245
        QRect targetRect = printer->pageLayout().fullRectPixels(printer->resolution());
246

247
        renderPage(vpp, painter, sourceRect, targetRect);
248

249
    }
250
}
251

252
//static routine to print all pages in a document to pdf
253
void PagePrinter::printAllPdf(QPrinter* printer, App::Document* doc)
254
{
255
//    Base::Console().Message("PP::printAllPdf()\n");
256
    double dpmm = printer->resolution() / mmPerInch;
257

258
    QString outputFile = printer->outputFileName();
259
    QString documentName = QString::fromUtf8(doc->getName());
260
    QPdfWriter pdfWriter(outputFile);
261
    // setPdfVersion sets the printed PDF Version to comply with PDF/A-1b, more details under: https://www.kdab.com/creating-pdfa-documents-qt/
262
    // but this is not working as of Qt 5.12
263
    //printer->setPdfVersion(QPagedPaintDevice::PdfVersion_A1b);
264
    //pdfWriter.setPdfVersion(QPagedPaintDevice::PdfVersion_A1b);
265
    pdfWriter.setTitle(documentName);
266
    pdfWriter.setResolution(printer->resolution());
267
    QPageLayout pageLayout = printer->pageLayout();
268
    // we want to set the layout for the first page before we make the painter(&pdfWriter) or the layout for the first page will
269
    // not be correct.
270
    std::vector<App::DocumentObject*> docObjs =
271
        doc->getObjectsOfType(TechDraw::DrawPage::getClassTypeId());
272
    auto firstPage = docObjs.front();
273

274
    auto dPage = static_cast<TechDraw::DrawPage*>(firstPage);
275
    double width = A4Heightmm;//default to A4 Landscape 297 x 210
276
    double height = A4Widthmm;
277
    makePageLayout(dPage, pageLayout, width, height);
278

279
    pdfWriter.setPageLayout(pageLayout);
280
    // to get several pages into the same pdf, we must use the same painter for each page and not have any
281
    // start() or end() until all the pages are printed.
282
    QPainter painter(&pdfWriter);
283

284
    bool firstTime = true;
285
    for (auto& obj : docObjs) {
286
        Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(obj);
287
        if (!vp) {
288
            continue;// can't print this one
289
        }
290
        auto vpp = dynamic_cast<TechDrawGui::ViewProviderPage*>(vp);
291
        if (!vpp) {
292
            continue;// can't print this one
293
        }
294
        auto dPage = static_cast<TechDraw::DrawPage*>(obj);
295
        double width{0};
296
        double height{0};
297
        makePageLayout(dPage, pageLayout, width, height);
298
        pdfWriter.setPageLayout(pageLayout);
299
        if (!firstTime) {
300
            pdfWriter.newPage();
301
        }
302
        firstTime = false;
303

304
        QRectF sourceRect(0.0, Rez::guiX(-height), Rez::guiX(width), Rez::guiX(height));
305
        QRect targetRect(0, 0, width * dpmm, height * dpmm);
306
        renderPage(vpp, painter, sourceRect, targetRect);
307
    }
308
}
309

310
//static
311
//! we don't need the banner page any more
312
void PagePrinter::printBannerPage(QPrinter* printer, QPainter& painter, QPageLayout& pageLayout,
313
                                  App::Document* doc, std::vector<App::DocumentObject*>& docObjs)
314
{
315
    QFont savePainterFont = painter.font();
316
    QFont painterFont;
317
    painterFont.setFamily(Preferences::labelFontQString());
318
    int fontSizeMM = Preferences::labelFontSizeMM();
319
    double dpmm = printer->resolution() / mmPerInch;
320
    int fontSizePx = fontSizeMM * dpmm;
321
    painterFont.setPixelSize(fontSizePx);
322
    painter.setFont(painterFont);
323

324
    //print a header
325
    QString docLine = QObject::tr("Document Name:") + QLatin1String(" ") + QString::fromUtf8(doc->getName());
326
    int leftMargin = pageLayout.margins().left() * dpmm + 5 * dpmm; //layout margin + 5mm
327
    int verticalPos = pageLayout.margins().top() * dpmm + 20 * dpmm;//layout margin + 20mm
328
    int verticalSpacing = 2;                                        //double space
329
    painter.drawText(leftMargin, verticalPos, docLine);
330

331
    //leave some blank space between document name and page entries
332
    verticalPos += 2 * verticalSpacing * fontSizePx;
333
    for (auto& obj : docObjs) {
334
        //print a line for each page
335
        QString pageLine = QString::fromUtf8(obj->getNameInDocument()) + QString::fromUtf8(" / ")
336
            + QString::fromUtf8(obj->Label.getValue());
337
        painter.drawText(leftMargin, verticalPos, pageLine);
338
        verticalPos += verticalSpacing * fontSizePx;
339
    }
340
    painter.setFont(savePainterFont);//restore the original font
341
}
342

343
//static
344
void PagePrinter::renderPage(ViewProviderPage* vpp, QPainter& painter, QRectF& sourceRect,
345
                             QRect& targetRect)
346
{
347
//    Base::Console().Message("PP::renderPage()\n");
348
    //turn off view frames for print
349
    bool saveState = vpp->getFrameState();
350
    vpp->setFrameState(false);
351
    vpp->setTemplateMarkers(false);
352

353
    //scene might be drawn in light text.  we need to redraw in normal text.
354
    bool saveLightOnDark = Preferences::lightOnDark();
355
    if (Preferences::lightOnDark()) {
356
        Preferences::lightOnDark(false);
357
        vpp->getQGSPage()->redrawAllViews();
358
    }
359

360
    vpp->getQGSPage()->refreshViews();
361
    vpp->getQGSPage()->render(&painter, targetRect, sourceRect);
362

363
    // Reset
364
    vpp->setFrameState(saveState);
365
    vpp->setTemplateMarkers(saveState);
366
    Preferences::lightOnDark(saveLightOnDark);
367

368
    vpp->getQGSPage()->refreshViews();
369
}
370

371
void PagePrinter::saveSVG(std::string file)
372
{
373
    if (file.empty()) {
374
        Base::Console().Warning("PagePrinter - no file specified\n");
375
        return;
376
    }
377
    QString filename = QString::fromUtf8(file.data(), file.size());
378
    if (m_scene) {
379
        m_scene->saveSvg(filename);
380
    }
381
}
382

383
void PagePrinter::saveDXF(std::string fileName)
384
{
385
    TechDraw::DrawPage* page = m_vpPage->getDrawPage();
386
    std::string PageName = page->getNameInDocument();
387
    fileName = Base::Tools::escapeEncodeFilename(fileName);
388
    Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Save page to dxf"));
389
    Gui::Command::doCommand(Gui::Command::Doc, "import TechDraw");
390
    Gui::Command::doCommand(Gui::Command::Doc,
391
                            "TechDraw.writeDXFPage(App.activeDocument().%s, u\"%s\")",
392
                            PageName.c_str(), (const char*)fileName.c_str());
393
    Gui::Command::commitCommand();
394
}
395

396
void PagePrinter::savePDF(std::string file)
397
{
398
//    Base::Console().Message("PP::savePDF(%s)\n", file.c_str());
399
    printPdf(file);
400
}
401

402
PaperAttributes::PaperAttributes()
403
{
404
    // set default values to A4 Landscape
405
    orientation = QPageLayout::Orientation::Landscape;
406
    paperSize = QPageSize::A4;
407
    pagewidth = A4Heightmm;
408
    pageheight = A4Widthmm;
409
}
410

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.