Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "pdfwriter.h"
24 :
25 : #include <QBuffer>
26 : #include <QPdfWriter>
27 :
28 : #include "notation/inotation.h"
29 : #include "notation/inotationpainting.h"
30 :
31 : #include "log.h"
32 :
33 : using namespace mu::iex::imagesexport;
34 : using namespace mu::project;
35 : using namespace mu::notation;
36 : using namespace muse;
37 : using namespace muse::io;
38 : using namespace muse::draw;
39 : using namespace mu::engraving;
40 :
41 0 : std::vector<INotationWriter::UnitType> PdfWriter::supportedUnitTypes() const
42 : {
43 0 : return { UnitType::PER_PART, UnitType::MULTI_PART };
44 : }
45 :
46 0 : Ret PdfWriter::write(INotationPtr notation, io::IODevice& destinationDevice, const Options& options)
47 : {
48 0 : UnitType unitType = unitTypeFromOptions(options);
49 0 : IF_ASSERT_FAILED(unitType == UnitType::PER_PART) {
50 0 : return Ret(Ret::Code::NotSupported);
51 : }
52 :
53 0 : IF_ASSERT_FAILED(notation) {
54 0 : return make_ret(Ret::Code::UnknownError);
55 : }
56 :
57 0 : QByteArray qdata;
58 0 : QBuffer buf(&qdata);
59 0 : buf.open(QIODevice::WriteOnly);
60 :
61 0 : QPdfWriter pdfWriter(&buf);
62 0 : preparePdfWriter(pdfWriter, notation->projectWorkTitleAndPartName(), notation->painting()->pageSizeInch().toQSizeF());
63 :
64 0 : Painter painter(&pdfWriter, "pdfwriter");
65 0 : if (!painter.isActive()) {
66 0 : return false;
67 : }
68 :
69 0 : const bool TRANSPARENT_BACKGROUND = muse::value(options, OptionKey::TRANSPARENT_BACKGROUND,
70 0 : Val(configuration()->exportPdfWithTransparentBackground())).toBool();
71 :
72 0 : INotationPainting::Options opt;
73 0 : opt.deviceDpi = pdfWriter.logicalDpiX();
74 0 : opt.onNewPage = [&pdfWriter]() { pdfWriter.newPage(); };
75 0 : opt.printPageBackground = !TRANSPARENT_BACKGROUND;
76 :
77 0 : auto pageNumIt = options.find(OptionKey::PAGE_NUMBER);
78 0 : if (pageNumIt != options.end()) {
79 0 : opt.fromPage = pageNumIt->second.toInt();
80 0 : opt.toPage = opt.fromPage;
81 : }
82 :
83 0 : notation->painting()->paintPdf(&painter, opt);
84 :
85 0 : painter.endDraw();
86 :
87 0 : ByteArray data = ByteArray::fromQByteArrayNoCopy(qdata);
88 0 : destinationDevice.write(data);
89 :
90 0 : return true;
91 0 : }
92 :
93 0 : Ret PdfWriter::writeList(const INotationPtrList& notations, io::IODevice& destinationDevice, const Options& options)
94 : {
95 0 : IF_ASSERT_FAILED(!notations.empty()) {
96 0 : return make_ret(Ret::Code::UnknownError);
97 : }
98 :
99 0 : UnitType unitType = unitTypeFromOptions(options);
100 0 : IF_ASSERT_FAILED(unitType == UnitType::MULTI_PART) {
101 0 : return Ret(Ret::Code::NotSupported);
102 : }
103 :
104 0 : INotationPtr firstNotation = notations.front();
105 0 : IF_ASSERT_FAILED(firstNotation) {
106 0 : return make_ret(Ret::Code::UnknownError);
107 : }
108 :
109 0 : QByteArray qdata;
110 0 : QBuffer buf(&qdata);
111 0 : buf.open(QIODevice::WriteOnly);
112 :
113 0 : QPdfWriter pdfWriter(&buf);
114 0 : preparePdfWriter(pdfWriter, firstNotation->projectWorkTitle(), firstNotation->painting()->pageSizeInch().toQSizeF());
115 :
116 0 : Painter painter(&pdfWriter, "pdfwriter");
117 0 : if (!painter.isActive()) {
118 0 : return false;
119 : }
120 :
121 0 : const bool TRANSPARENT_BACKGROUND = muse::value(options, OptionKey::TRANSPARENT_BACKGROUND,
122 0 : Val(configuration()->exportPdfWithTransparentBackground())).toBool();
123 :
124 0 : INotationPainting::Options opt;
125 0 : opt.deviceDpi = pdfWriter.logicalDpiX();
126 0 : opt.onNewPage = [&pdfWriter]() { pdfWriter.newPage(); };
127 0 : opt.printPageBackground = !TRANSPARENT_BACKGROUND;
128 :
129 0 : for (const auto& notation : notations) {
130 0 : IF_ASSERT_FAILED(notation) {
131 0 : return make_ret(Ret::Code::UnknownError);
132 : }
133 :
134 0 : if (notation != firstNotation) {
135 0 : QSizeF size = notation->painting()->pageSizeInch().toQSizeF();
136 0 : pdfWriter.setPageSize(QPageSize(size, QPageSize::Inch));
137 0 : pdfWriter.newPage();
138 : }
139 :
140 0 : notation->painting()->paintPdf(&painter, opt);
141 : }
142 :
143 0 : painter.endDraw();
144 :
145 0 : ByteArray data = ByteArray::fromQByteArrayNoCopy(qdata);
146 0 : destinationDevice.write(data);
147 :
148 0 : return true;
149 0 : }
150 :
151 0 : void PdfWriter::preparePdfWriter(QPdfWriter& pdfWriter, const QString& title, const QSizeF& size) const
152 : {
153 0 : pdfWriter.setResolution(configuration()->exportPdfDpiResolution());
154 0 : pdfWriter.setCreator(QString("MuseScore Studio Version: ") + application()->version().toString().toQString());
155 0 : pdfWriter.setTitle(title);
156 0 : pdfWriter.setPageMargins(QMarginsF());
157 0 : pdfWriter.setPageLayout(QPageLayout(QPageSize(size, QPageSize::Inch), QPageLayout::Orientation::Portrait, QMarginsF()));
158 :
159 0 : if (configuration()->exportPdfWithGrayscale()) {
160 0 : pdfWriter.setColorModel(QPdfWriter::ColorModel::Grayscale);
161 : } else {
162 0 : pdfWriter.setColorModel(QPdfWriter::ColorModel::Auto);
163 : }
164 0 : }
|