241 lines
6.9 KiB
C++
241 lines
6.9 KiB
C++
/*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
* MuseScore-CLA-applies
|
|
*
|
|
* MuseScore
|
|
* Music Composition & Notation
|
|
*
|
|
* Copyright (C) 2023 MuseScore BVBA and others
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "drawdatagenerator.h"
|
|
|
|
#include "global/io/dir.h"
|
|
#include "global/io/fileinfo.h"
|
|
|
|
#include "draw/bufferedpaintprovider.h"
|
|
#include "draw/utils/drawdatarw.h"
|
|
|
|
#include "engraving/compat/scoreaccess.h"
|
|
#include "engraving/infrastructure/localfileinfoprovider.h"
|
|
#include "engraving/infrastructure/paint.h"
|
|
#include "engraving/rw/scorereader.h"
|
|
#include "engraving/libmscore/masterscore.h"
|
|
|
|
#ifdef MUE_BUILD_IMPORTEXPORT_MODULE
|
|
#include "importexport/guitarpro/internal/guitarproreader.h"
|
|
#endif
|
|
|
|
#include "log.h"
|
|
|
|
using namespace mu;
|
|
using namespace mu::diagnostics;
|
|
using namespace mu::draw;
|
|
using namespace mu::engraving;
|
|
|
|
//! TODO
|
|
//! 1. Make saving by relative paths
|
|
//! scoreDir = path/scores
|
|
//! outDir = path/json
|
|
//! scorePath = scoreDir/v3/score.mscz
|
|
//! -> jsonPath = outDir/v3/score.json (now just outDir/score.json)
|
|
|
|
static const std::vector<std::string> FILES_FILTER = { "*.mscz", "*.mscx", "*.gp", "*.gpx", "*.gp4", "*.gp5" };
|
|
|
|
Ret DrawDataGenerator::processDir(const io::path_t& scoreDir, const io::path_t& outDir, const GenOpt& opt)
|
|
{
|
|
io::Dir::mkpath(outDir);
|
|
|
|
//PROFILER_CLEAR;
|
|
|
|
RetVal<io::paths_t> scores = io::Dir::scanFiles(scoreDir, FILES_FILTER);
|
|
for (size_t i = 0; i < scores.val.size(); ++i) {
|
|
// if (i < 1919) {
|
|
// continue;
|
|
// }
|
|
|
|
// if (i > 4) {
|
|
// break;
|
|
// }
|
|
|
|
LOGI() << "processFile: " << (i + 1) << "/" << scores.val.size() << " " << scores.val.at(i);
|
|
|
|
bool skip = false;
|
|
std::string scorePath = scores.val.at(i).toStdString();
|
|
|
|
if (scorePath.find("disabled") != std::string::npos || scorePath.find("DISABLED") != std::string::npos) {
|
|
LOGW() << "disabled: " << scores.val.at(i);
|
|
skip = true;
|
|
}
|
|
|
|
if (skip) {
|
|
continue;
|
|
}
|
|
|
|
io::path_t scoreFile = scores.val.at(i);
|
|
io::path_t outFile = outDir + "/" + io::FileInfo(scoreFile).baseName() + ".json";
|
|
processFile(scoreFile, outFile, opt);
|
|
}
|
|
|
|
//PROFILER_PRINT;
|
|
|
|
return make_ok();
|
|
}
|
|
|
|
Ret DrawDataGenerator::processFile(const io::path_t& scoreFile, const io::path_t& outFile, const GenOpt& opt)
|
|
{
|
|
DrawDataPtr drawData = genDrawData(scoreFile, opt);
|
|
DrawDataRW::writeData(outFile, drawData);
|
|
|
|
return make_ok();
|
|
}
|
|
|
|
DrawDataPtr DrawDataGenerator::genDrawData(const io::path_t& scorePath, const GenOpt& opt) const
|
|
{
|
|
MasterScore* score = compat::ScoreAccess::createMasterScoreWithBaseStyle();
|
|
if (!loadScore(score, scorePath)) {
|
|
LOGE() << "failed load score: " << scorePath;
|
|
return nullptr;
|
|
}
|
|
|
|
applyOptions(score, opt);
|
|
|
|
{
|
|
TRACEFUNC_C("Layout");
|
|
score->doLayout();
|
|
}
|
|
|
|
std::shared_ptr<BufferedPaintProvider> pd = std::make_shared<BufferedPaintProvider>();
|
|
{
|
|
TRACEFUNC_C("Paint");
|
|
Painter painter(pd, "DrawData");
|
|
Paint::Options option;
|
|
option.fromPage = 0;
|
|
option.toPage = 0;
|
|
option.deviceDpi = DrawData::CANVAS_DPI;
|
|
option.printPageBackground = true;
|
|
option.isSetViewport = true;
|
|
option.isMultiPage = false;
|
|
option.isPrinting = true;
|
|
|
|
Paint::paintScore(&painter, score, option);
|
|
}
|
|
|
|
delete score;
|
|
|
|
DrawDataPtr drawData = pd->drawData();
|
|
return drawData;
|
|
}
|
|
|
|
Pixmap DrawDataGenerator::genImage(const io::path_t& scorePath) const
|
|
{
|
|
LOGD() << "try: " << scorePath;
|
|
MasterScore* score = compat::ScoreAccess::createMasterScoreWithBaseStyle();
|
|
if (!loadScore(score, scorePath)) {
|
|
LOGE() << "failed load score: " << scorePath;
|
|
return Pixmap();
|
|
}
|
|
|
|
{
|
|
TRACEFUNC_C("Layout");
|
|
score->doLayout();
|
|
}
|
|
|
|
LOGD() << "success loaded: " << scorePath;
|
|
|
|
const SizeF pageSizeInch = Paint::pageSizeInch(score);
|
|
|
|
int width = std::lrint(pageSizeInch.width() * DrawData::CANVAS_DPI);
|
|
int height = std::lrint(pageSizeInch.height() * DrawData::CANVAS_DPI);
|
|
|
|
QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
|
|
image.setDotsPerMeterX(std::lrint((DrawData::CANVAS_DPI * 1000) / mu::engraving::INCH));
|
|
image.setDotsPerMeterY(std::lrint((DrawData::CANVAS_DPI * 1000) / mu::engraving::INCH));
|
|
|
|
image.fill(Qt::white);
|
|
{
|
|
Painter painter(&image, "DrawData");
|
|
|
|
Paint::Options opt;
|
|
opt.fromPage = 0;
|
|
opt.toPage = 0;
|
|
opt.deviceDpi = DrawData::CANVAS_DPI;
|
|
opt.printPageBackground = false;
|
|
opt.isSetViewport = true;
|
|
opt.isMultiPage = false;
|
|
opt.isPrinting = true;
|
|
|
|
Paint::paintScore(&painter, score, opt);
|
|
}
|
|
|
|
return Pixmap::fromQImage(image);
|
|
}
|
|
|
|
bool DrawDataGenerator::loadScore(mu::engraving::MasterScore* score, const mu::io::path_t& path) const
|
|
{
|
|
TRACEFUNC;
|
|
score->setFileInfoProvider(std::make_shared<LocalFileInfoProvider>(path));
|
|
|
|
std::string suffix = io::suffix(path);
|
|
if (isMuseScoreFile(suffix)) {
|
|
// Load
|
|
|
|
TRACEFUNC_C("Load mscz");
|
|
|
|
MscReader::Params params;
|
|
params.filePath = path;
|
|
params.mode = mscIoModeBySuffix(suffix);
|
|
|
|
MscReader reader(params);
|
|
if (!reader.open()) {
|
|
return false;
|
|
}
|
|
|
|
ScoreReader scoreReader;
|
|
SettingsCompat settingsCompat;
|
|
Ret ret = scoreReader.loadMscz(score, reader, settingsCompat, true);
|
|
if (!ret) {
|
|
LOGE() << "failed read file: " << path;
|
|
return false;
|
|
}
|
|
} else {
|
|
// Import
|
|
|
|
TRACEFUNC_C("Load gp");
|
|
#ifdef MUE_BUILD_IMPORTEXPORT_MODULE
|
|
mu::iex::guitarpro::GuitarProReader reader;
|
|
Ret ret = reader.read(score, path);
|
|
if (!ret) {
|
|
LOGE() << "failed read file: " << path;
|
|
return false;
|
|
}
|
|
#else
|
|
NOT_SUPPORTED;
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void DrawDataGenerator::applyOptions(engraving::MasterScore* score, const GenOpt& opt) const
|
|
{
|
|
if (!opt.pageSize.isNull()) {
|
|
PageSizeSetAccessor pageSize = score->pageSize();
|
|
pageSize.setHeight(opt.pageSize.height() / engraving::INCH);
|
|
pageSize.setWidth(opt.pageSize.width() / engraving::INCH);
|
|
pageSize.setPrintableWidth(pageSize.width() - pageSize.evenLeftMargin() - pageSize.oddLeftMargin());
|
|
}
|
|
}
|