Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/engraving/dom/imageStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ImageStoreItem
bool isUsed() const { return !m_references.empty(); }
std::string hashName() const;
const muse::ByteArray& hash() const { return m_hash; }
const std::string& type() const { return m_type; }
void set(const muse::ByteArray& b, const muse::ByteArray& h) { m_buffer = b; m_hash = h; }

private:
Expand Down
146 changes: 138 additions & 8 deletions src/importexport/musicxml/internal/export/exportmusicxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
#include "engraving/dom/hammeronpulloff.h"
#include "engraving/dom/harmonicmark.h"
#include "engraving/dom/harmony.h"
#include "engraving/dom/image.h"
#include "engraving/dom/imageStore.h"
#include "engraving/dom/harppedaldiagram.h"
#include "engraving/dom/instrchange.h"
#include "engraving/dom/jump.h"
Expand Down Expand Up @@ -347,6 +349,7 @@ class ExportMusicXml : public muse::Contextable
void moveToTickIfNeed(const Fraction& t, track_idx_t track, const Fraction& measureTick);
void words(TextBase const* const text, staff_idx_t staff);
void tboxTextAsWords(TextBase const* const text, const staff_idx_t staff, PointF position);
void image(const Image* const img, staff_idx_t staff);
void rehearsal(RehearsalMark const* const rmk, staff_idx_t staff);
void harpPedals(HarpPedalDiagram const* const hpd, staff_idx_t staff);
void hairpin(Hairpin const* const hp, staff_idx_t staff, const Fraction& tick);
Expand All @@ -361,6 +364,7 @@ class ExportMusicXml : public muse::Contextable
void tempoSound(TempoText const* const text);
void harmony(Harmony const* const, FretDiagram const* const fd, const Fraction& offset = Fraction(0, 1));
Score* score() const { return m_score; }
void setMxl(bool v) { m_isMxl = v; }
double getTenthsFromInches(double) const;
double getTenthsFromDots(double) const;
Fraction tick() const { return m_tick; }
Expand Down Expand Up @@ -438,6 +442,7 @@ class ExportMusicXml : public muse::Contextable
TrillHash m_trillStop;
MusicXmlInstrumentMap m_instrMap;
PlayingTechniqueType m_currPlayTechnique;
bool m_isMxl = false;
};

//---------------------------------------------------------
Expand Down Expand Up @@ -5062,7 +5067,7 @@ void ExportMusicXml::playText(PlayTechAnnotation const* const annot, staff_idx_t
{
const int offset = calculateTimeDeltaInDivisions(annot->tick(), tick(), m_div);

if (annot->plainText() == "") {
if (annot->plainText().empty()) {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
Expand Down Expand Up @@ -5111,7 +5116,7 @@ void ExportMusicXml::words(TextBase const* const text, staff_idx_t staff)
muPrintable(text->plainText()));
*/

if (text->plainText() == "") {
if (text->plainText().empty()) {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
Expand All @@ -5123,6 +5128,119 @@ void ExportMusicXml::words(TextBase const* const text, staff_idx_t staff)
directionETag(m_xml, staff);
}

//---------------------------------------------------------
// getImageInfo
//---------------------------------------------------------

static void getImageInfo(const ImageStoreItem* isi, String& source, String& type)
{
source = String::fromStdString(isi->hashName());
String suffix = String::fromStdString(isi->type()).toLower();

if (suffix == u"svg" || suffix == u"svgz") {
type = u"image/svg+xml";
} else if (suffix == u"png") {
type = u"image/png";
} else if (suffix == u"jpg" || suffix == u"jpeg") {
type = u"image/jpeg";
} else if (suffix == u"gif") {
type = u"image/gif";
} else if (suffix == u"bmp") {
type = u"image/bmp";
} else if (suffix == u"tif" || suffix == u"tiff") {
type = u"image/tiff";
}

if (type.isEmpty()) {
const ByteArray& ba = isi->buffer();
if (ba.size() >= 4) {
if (ba.at(0) == 0x89 && ba.at(1) == 0x50 && ba.at(2) == 0x4E && ba.at(3) == 0x47) {
type = u"image/png";
if (suffix.isEmpty()) {
source += u".png";
}
} else if (ba.at(0) == 0xFF && ba.at(1) == 0xD8 && ba.at(2) == 0xFF) {
type = u"image/jpeg";
if (suffix.isEmpty()) {
source += u".jpg";
}
} else if (ba.at(0) == 0x47 && ba.at(1) == 0x49 && ba.at(2) == 0x46 && ba.at(3) == 0x38) {
type = u"image/gif";
if (suffix.isEmpty()) {
source += u".gif";
}
} else if (ba.at(0) == 0x42 && ba.at(1) == 0x4D) {
type = u"image/bmp";
if (suffix.isEmpty()) {
source += u".bmp";
}
} else if ((ba.at(0) == 0x49 && ba.at(1) == 0x49 && ba.at(2) == 0x2A && ba.at(3) == 0x00)
|| (ba.at(0) == 0x4D && ba.at(1) == 0x4D && ba.at(2) == 0x00 && ba.at(3) == 0x2A)) {
type = u"image/tiff";
if (suffix.isEmpty()) {
source += u".tif";
}
} else if (ba.at(0) == 0x3C && (ba.at(1) == 0x3F || ba.at(1) == 0x73)) {
type = u"image/svg+xml";
if (suffix.isEmpty()) {
source += u".svg";
}
}
}
}

if (type.isEmpty()) {
type = u"application/octet-stream";
}
}

//---------------------------------------------------------
// image
//---------------------------------------------------------

void ExportMusicXml::image(const Image* const img, staff_idx_t staff)
{
ImageStoreItem* isi = img->storeItem();
if (!isi) {
return;
}

directionTag(m_xml, m_attr, img);
m_xml.startElement("direction-type");

String source;
String type;
getImageInfo(isi, source, type);

if (m_isMxl) {
String imgTag = u"image source=\"" + XmlWriter::xmlString(source) + u"\"";
imgTag += u" type=\"" + XmlWriter::xmlString(type) + u"\"";

double width = img->imageWidth();
double height = img->imageHeight();
if (!img->sizeIsSpatium()) {
double sp = img->spatium();
if (sp > 0.0) {
width /= sp;
height /= sp;
}
}

imgTag += u" height=\"" + String::number(height * 10.0, 2) + u"\"";
imgTag += u" width=\"" + String::number(width * 10.0, 2) + u"\"";
imgTag += positioningAttributes(img);

m_xml.tagRaw(imgTag);
} else {
String otherTag = u"other-direction";
otherTag += positioningAttributes(img);
m_xml.tagRaw(otherTag, XmlWriter::xmlString(source));
}
m_xml.endElement(); // direction-type

directionETag(m_xml, staff);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

//---------------------------------------------------------
// systemText
//---------------------------------------------------------
Expand All @@ -5131,7 +5249,7 @@ void ExportMusicXml::systemText(StaffTextBase const* const text, staff_idx_t sta
{
const int offset = calculateTimeDeltaInDivisions(text->tick(), tick(), m_div);

if (text->plainText() == "") {
if (text->plainText().empty()) {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
Expand Down Expand Up @@ -5167,7 +5285,7 @@ String ExportMusicXml::positioningAttributesForTboxText(const PointF position, f

void ExportMusicXml::tboxTextAsWords(TextBase const* const text, const staff_idx_t staff, const PointF relativePosition)
{
if (text->plainText() == "") {
if (text->plainText().empty()) {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
Expand Down Expand Up @@ -5196,7 +5314,7 @@ void ExportMusicXml::tboxTextAsWords(TextBase const* const text, const staff_idx

void ExportMusicXml::rehearsal(RehearsalMark const* const rmk, staff_idx_t staff)
{
if (rmk->plainText() == "") {
if (rmk->plainText().empty()) {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
Expand Down Expand Up @@ -6188,7 +6306,7 @@ static void directionMarker(XmlWriter& xml, const Marker* const m, const std::ve
case MarkerType::CODA:
case MarkerType::CODETTA:
type = u"coda";
if (m->label() == "") {
if (m->label().empty()) {
sound = u"coda=\"1\"";
} else {
sound = u"coda=\"" + m->label() + u"\"";
Expand All @@ -6199,7 +6317,7 @@ static void directionMarker(XmlWriter& xml, const Marker* const m, const std::ve
[[fallthrough]];
case MarkerType::SEGNO:
type = u"segno";
if (m->label() == "") {
if (m->label().empty()) {
sound = u"segno=\"1\"";
} else {
sound = u"segno=\"" + m->label() + u"\"";
Expand All @@ -6213,7 +6331,7 @@ static void directionMarker(XmlWriter& xml, const Marker* const m, const std::ve
case MarkerType::TOCODASYM:
case MarkerType::DA_CODA:
case MarkerType::DA_DBLCODA: {
if (m->xmlText() == "") {
if (m->xmlText().empty()) {
words = u"To Coda";
} else {
words = m->xmlText();
Expand Down Expand Up @@ -6525,6 +6643,8 @@ static bool commonAnnotations(ExportMusicXml* exp, const EngravingItem* e, staff
exp->harpPedals(toHarpPedalDiagram(e), sstaff);
} else if (e->isRehearsalMark()) {
exp->rehearsal(toRehearsalMark(e), sstaff);
} else if (e->isImage()) {
exp->image(toImage(e), sstaff);
} else if (e->isSystemText()) {
exp->systemText(toStaffTextBase(e), sstaff);
}
Expand Down Expand Up @@ -8847,9 +8967,19 @@ static void writeMxlArchive(Score* score, muse::ZipWriter& zip, const String& fi

auto dbuf = Buffer::opened(IODevice::ReadWrite);
ExportMusicXml em(score);
em.setMxl(true);
em.write(&dbuf);
dbuf.seek(0);
zip.addFile(filename.toStdString(), dbuf.data());

for (const ImageStoreItem* isi : imageStore) {
if (isi->isUsed(score)) {
String source;
String type;
getImageInfo(isi, source, type);
zip.addFile(source.toStdString(), isi->buffer());
}
}
}

bool saveMxl(Score* score, IODevice* device)
Expand Down
Loading