2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2007-2012 Werner Schweer
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "image.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "mscore.h"
|
|
|
|
#include "imageStore.h"
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// propertyList
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-07-16 21:56:49 +02:00
|
|
|
static bool defaultAutoScale = false;
|
|
|
|
static bool defaultLockAspectRatio = true;
|
|
|
|
static bool defaultSizeIsSpatium = true;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Image
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2020-05-29 18:47:27 +02:00
|
|
|
Image::Image(Score* s)
|
|
|
|
: BSymbol(s, ElementFlag::MOVABLE)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-05-21 15:49:13 +02:00
|
|
|
imageType = ImageType::NONE;
|
2015-05-05 18:27:04 +02:00
|
|
|
rasterDoc = 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
_size = QSizeF(0, 0);
|
|
|
|
_storeItem = 0;
|
|
|
|
_dirty = false;
|
|
|
|
_lockAspectRatio = defaultLockAspectRatio;
|
|
|
|
_autoScale = defaultAutoScale;
|
|
|
|
_sizeIsSpatium = defaultSizeIsSpatium;
|
2012-07-16 21:56:49 +02:00
|
|
|
_linkIsValid = false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2020-05-29 18:47:27 +02:00
|
|
|
Image::Image(const Image& img)
|
|
|
|
: BSymbol(img)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
imageType = img.imageType;
|
2012-05-26 14:26:10 +02:00
|
|
|
buffer = img.buffer;
|
|
|
|
_size = img._size;
|
|
|
|
_lockAspectRatio = img._lockAspectRatio;
|
|
|
|
_autoScale = img._autoScale;
|
|
|
|
_dirty = img._dirty;
|
|
|
|
_storeItem = img._storeItem;
|
|
|
|
_sizeIsSpatium = img._sizeIsSpatium;
|
2013-01-11 18:10:18 +01:00
|
|
|
if (_storeItem) {
|
2012-10-05 11:30:00 +02:00
|
|
|
_storeItem->reference(this);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-07-20 01:25:12 +02:00
|
|
|
_linkPath = img._linkPath;
|
2012-07-16 21:56:49 +02:00
|
|
|
_linkIsValid = img._linkIsValid;
|
2015-05-05 18:27:04 +02:00
|
|
|
if (imageType == ImageType::RASTER) {
|
|
|
|
rasterDoc = img.rasterDoc ? new QImage(*img.rasterDoc) : 0;
|
|
|
|
} else if (imageType == ImageType::SVG) {
|
2017-08-15 22:10:56 +02:00
|
|
|
svgDoc = img.svgDoc ? new QSvgRenderer(_storeItem->buffer()) : 0;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2014-07-22 01:00:49 +02:00
|
|
|
setZ(img.z());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Image
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Image::~Image()
|
|
|
|
{
|
|
|
|
if (_storeItem) {
|
|
|
|
_storeItem->dereference(this);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2014-05-21 15:49:13 +02:00
|
|
|
if (imageType == ImageType::SVG) {
|
2013-01-11 18:10:18 +01:00
|
|
|
delete svgDoc;
|
2014-05-21 15:49:13 +02:00
|
|
|
} else if (imageType == ImageType::RASTER) {
|
2013-01-11 18:10:18 +01:00
|
|
|
delete rasterDoc;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setImageType
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Image::setImageType(ImageType t)
|
|
|
|
{
|
|
|
|
imageType = t;
|
2014-05-21 15:49:13 +02:00
|
|
|
if (imageType == ImageType::SVG) {
|
2013-01-11 18:10:18 +01:00
|
|
|
svgDoc = 0;
|
2014-05-21 15:49:13 +02:00
|
|
|
} else if (imageType == ImageType::RASTER) {
|
2013-01-11 18:10:18 +01:00
|
|
|
rasterDoc = 0;
|
|
|
|
} else {
|
|
|
|
qDebug("illegal image type");
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// imageSize
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QSizeF Image::imageSize() const
|
|
|
|
{
|
2017-03-10 17:12:38 +01:00
|
|
|
if (!isValid()) {
|
2013-08-31 13:42:45 +02:00
|
|
|
return QSizeF();
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2017-03-10 17:12:38 +01:00
|
|
|
return imageType == ImageType::RASTER ? rasterDoc->size() : svgDoc->defaultSize();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// draw
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void Image::draw(QPainter* painter) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
bool emptyImage = false;
|
2014-05-21 15:49:13 +02:00
|
|
|
if (imageType == ImageType::SVG) {
|
2013-01-11 18:10:18 +01:00
|
|
|
if (!svgDoc) {
|
|
|
|
emptyImage = true;
|
|
|
|
} else {
|
|
|
|
svgDoc->render(painter, bbox());
|
|
|
|
}
|
2014-05-21 15:49:13 +02:00
|
|
|
} else if (imageType == ImageType::RASTER) {
|
2013-12-10 17:16:38 +01:00
|
|
|
if (rasterDoc == nullptr) {
|
|
|
|
emptyImage = true;
|
|
|
|
} else {
|
|
|
|
painter->save();
|
|
|
|
QSizeF s;
|
2012-05-26 14:26:10 +02:00
|
|
|
if (_sizeIsSpatium) {
|
2013-12-10 17:16:38 +01:00
|
|
|
s = _size * spatium();
|
2013-01-11 18:10:18 +01:00
|
|
|
} else {
|
2015-11-16 14:24:47 +01:00
|
|
|
s = _size * DPMM;
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
|
|
|
if (score() && score()->printing() && !MScore::svgPrinting) {
|
2012-05-26 14:26:10 +02:00
|
|
|
// use original image size for printing, but not for svg for reasonable file size.
|
2013-01-11 18:10:18 +01:00
|
|
|
painter->scale(s.width() / rasterDoc->width(), s.height() / rasterDoc->height());
|
|
|
|
painter->drawPixmap(QPointF(0, 0), QPixmap::fromImage(*rasterDoc));
|
2020-05-26 15:54:26 +02:00
|
|
|
} else {
|
2013-12-10 17:16:38 +01:00
|
|
|
QTransform t = painter->transform();
|
2013-01-11 18:10:18 +01:00
|
|
|
QSize ss = QSizeF(s.width() * t.m11(), s.height() * t.m22()).toSize();
|
|
|
|
t.setMatrix(1.0, t.m12(), t.m13(), t.m21(), 1.0, t.m23(), t.m31(), t.m32(), t.m33());
|
2013-12-10 17:16:38 +01:00
|
|
|
painter->setWorldTransform(t);
|
|
|
|
if ((buffer.size() != ss || _dirty) && rasterDoc && !rasterDoc->isNull()) {
|
|
|
|
buffer = QPixmap::fromImage(rasterDoc->scaled(ss, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
|
|
|
_dirty = false;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
if (buffer.isNull()) {
|
2013-12-10 17:16:38 +01:00
|
|
|
emptyImage = true;
|
2020-05-26 15:54:26 +02:00
|
|
|
} else {
|
2013-01-11 18:10:18 +01:00
|
|
|
painter->drawPixmap(QPointF(0.0, 0.0), buffer);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-12-10 17:16:38 +01:00
|
|
|
painter->restore();
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
2013-10-05 15:09:03 +02:00
|
|
|
if (emptyImage) {
|
2012-05-26 14:26:10 +02:00
|
|
|
painter->setBrush(Qt::NoBrush);
|
|
|
|
painter->setPen(Qt::black);
|
2013-01-11 18:10:18 +01:00
|
|
|
painter->drawRect(bbox());
|
2013-12-10 17:16:38 +01:00
|
|
|
painter->drawLine(0.0, 0.0, bbox().width(), bbox().height());
|
|
|
|
painter->drawLine(bbox().width(), 0.0, 0.0, bbox().height());
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (selected() && !(score() && score()->printing())) {
|
|
|
|
painter->setBrush(Qt::NoBrush);
|
2013-07-04 21:07:38 +02:00
|
|
|
painter->setPen(MScore::selectColor[0]);
|
2013-01-11 18:10:18 +01:00
|
|
|
painter->drawRect(bbox());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2020-05-26 11:30:01 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// isImageFramed
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Image::isImageFramed() const
|
|
|
|
{
|
|
|
|
if (!parent())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return parent()->isBox();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// imageAspectRatio
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
qreal Image::imageAspectRatio() const
|
|
|
|
{
|
|
|
|
return _size.width() / _size.height();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setImageHeight
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Image::updateImageHeight(const qreal& height)
|
|
|
|
{
|
|
|
|
qreal aspectRatio = imageAspectRatio();
|
|
|
|
|
|
|
|
_size.setHeight(height);
|
|
|
|
|
|
|
|
if (_lockAspectRatio)
|
|
|
|
_size.setWidth(height * aspectRatio);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setImageWidth
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Image::updateImageWidth(const qreal& width)
|
|
|
|
{
|
|
|
|
qreal aspectRatio = imageAspectRatio();
|
|
|
|
|
|
|
|
_size.setWidth(width);
|
|
|
|
|
|
|
|
if (_lockAspectRatio)
|
|
|
|
_size.setHeight(width / aspectRatio);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// imageHeight
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
qreal Image::imageHeight() const
|
|
|
|
{
|
|
|
|
return _size.height();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// imageWidth
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
qreal Image::imageWidth() const
|
|
|
|
{
|
|
|
|
return _size.width();
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// write
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-11-19 11:51:21 +01:00
|
|
|
void Image::write(XmlWriter& xml) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-07-16 21:56:49 +02:00
|
|
|
// attempt to convert the _linkPath to a path relative to the score
|
|
|
|
//
|
2016-03-10 10:41:31 +01:00
|
|
|
// TODO : on Save As, score()->fileInfo() still contains the old path and fname
|
2012-07-16 21:56:49 +02:00
|
|
|
// if the Save As path is different, image relative path will be wrong!
|
|
|
|
//
|
|
|
|
QString relativeFilePath= QString();
|
2013-01-23 14:14:09 +01:00
|
|
|
if (!_linkPath.isEmpty() && _linkIsValid) {
|
2012-07-16 21:56:49 +02:00
|
|
|
QFileInfo fi(_linkPath);
|
2016-03-10 10:41:31 +01:00
|
|
|
// score()->fileInfo()->canonicalPath() would be better
|
2012-07-16 21:56:49 +02:00
|
|
|
// but we are saving under a temp file name and the 'final' file
|
|
|
|
// might not exist yet, so canonicalFilePath() may return only "/"
|
|
|
|
// OTOH, the score 'final' file name is practically always canonical, at this point
|
2016-03-10 10:41:31 +01:00
|
|
|
QString scorePath = score()->masterScore()->fileInfo()->absolutePath();
|
2012-07-16 21:56:49 +02:00
|
|
|
QString imgFPath = fi.canonicalFilePath();
|
|
|
|
// if imgFPath is in (or below) the directory of scorePath
|
2013-01-23 14:14:09 +01:00
|
|
|
if (imgFPath.startsWith(scorePath, Qt::CaseSensitive)) {
|
2012-07-16 21:56:49 +02:00
|
|
|
// relative img path is the part exceeding scorePath
|
|
|
|
imgFPath.remove(0, scorePath.size());
|
2013-01-23 14:14:09 +01:00
|
|
|
if (imgFPath.startsWith('/')) {
|
2012-07-16 21:56:49 +02:00
|
|
|
imgFPath.remove(0, 1);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-07-16 21:56:49 +02:00
|
|
|
relativeFilePath = imgFPath;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-07-16 21:56:49 +02:00
|
|
|
// try 1 level up
|
2020-05-26 15:54:26 +02:00
|
|
|
else {
|
2012-07-16 21:56:49 +02:00
|
|
|
// reduce scorePath by one path level
|
|
|
|
fi.setFile(scorePath);
|
|
|
|
scorePath = fi.path();
|
|
|
|
// if imgFPath is in (or below) the directory up the score directory
|
2013-01-23 14:14:09 +01:00
|
|
|
if (imgFPath.startsWith(scorePath, Qt::CaseSensitive)) {
|
2012-07-16 21:56:49 +02:00
|
|
|
// relative img path is the part exceeding new scorePath plus "../"
|
|
|
|
imgFPath.remove(0, scorePath.size());
|
2013-01-23 14:14:09 +01:00
|
|
|
if (!imgFPath.startsWith('/')) {
|
2012-07-16 21:56:49 +02:00
|
|
|
imgFPath.prepend('/');
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-07-16 21:56:49 +02:00
|
|
|
imgFPath.prepend("..");
|
|
|
|
relativeFilePath = imgFPath;
|
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
2012-07-16 21:56:49 +02:00
|
|
|
// if no match, use full _linkPath
|
2013-01-23 14:14:09 +01:00
|
|
|
if (relativeFilePath.isEmpty()) {
|
2012-07-16 21:56:49 +02:00
|
|
|
relativeFilePath = _linkPath;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
|
2018-09-26 12:20:00 +02:00
|
|
|
xml.stag(this);
|
2013-01-23 14:14:09 +01:00
|
|
|
BSymbol::writeProperties(xml);
|
2012-07-16 21:56:49 +02:00
|
|
|
// keep old "path" tag, for backward compatibility and because it is used elsewhere
|
|
|
|
// (for instance by Box:read(), Measure:read(), Note:read(), ...)
|
|
|
|
xml.tag("path", _storeItem ? _storeItem->hashName() : relativeFilePath);
|
|
|
|
xml.tag("linkPath", relativeFilePath);
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
writeProperty(xml, Pid::AUTOSCALE);
|
|
|
|
writeProperty(xml, Pid::SIZE);
|
|
|
|
writeProperty(xml, Pid::LOCK_ASPECT_RATIO);
|
|
|
|
writeProperty(xml, Pid::SIZE_IS_SPATIUM);
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void Image::read(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-05-13 06:55:03 +02:00
|
|
|
if (score()->mscVersion() <= 114) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_sizeIsSpatium = false;
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tag == "autoScale") {
|
2018-10-26 10:41:07 +02:00
|
|
|
readProperty(e, Pid::AUTOSCALE);
|
2012-05-26 14:26:10 +02:00
|
|
|
} else if (tag == "size") {
|
2018-10-26 10:41:07 +02:00
|
|
|
readProperty(e, Pid::SIZE);
|
2012-05-26 14:26:10 +02:00
|
|
|
} else if (tag == "lockAspectRatio") {
|
2018-10-26 10:41:07 +02:00
|
|
|
readProperty(e, Pid::LOCK_ASPECT_RATIO);
|
2012-05-26 14:26:10 +02:00
|
|
|
} else if (tag == "sizeIsSpatium") {
|
2019-01-13 18:18:57 +01:00
|
|
|
// setting this using the property Pid::SIZE_IS_SPATIUM breaks, because the
|
|
|
|
// property setter attempts to maintain a constant size. If we're reading, we
|
|
|
|
// don't want to do that, because the stored size will be in:
|
|
|
|
// mm if size isn't spatium
|
|
|
|
// sp if size is spatium
|
|
|
|
_sizeIsSpatium = e.readBool();
|
2012-07-16 21:56:49 +02:00
|
|
|
} else if (tag == "path") {
|
2013-01-11 18:10:18 +01:00
|
|
|
_storePath = e.readElementText();
|
|
|
|
} else if (tag == "linkPath") {
|
|
|
|
_linkPath = e.readElementText();
|
|
|
|
} else if (tag == "subtype") { // obsolete
|
|
|
|
e.skipCurrentElement();
|
2013-01-23 14:14:09 +01:00
|
|
|
} else if (!BSymbol::readProperties(e)) {
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2012-07-16 21:56:49 +02:00
|
|
|
// once all paths are read, load img or retrieve it from store
|
|
|
|
// loading from file is tried first to update the stored image, if necessary
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
qDebug("linkPath <%s>", qPrintable(_linkPath));
|
|
|
|
qDebug("storePath <%s>", qPrintable(_storePath));
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
QString path;
|
2013-10-05 15:09:03 +02:00
|
|
|
bool loaded = false;
|
|
|
|
// if a store path is given, attempt to get the image from the store
|
|
|
|
if (!_storePath.isEmpty()) {
|
2012-07-16 21:56:49 +02:00
|
|
|
_storeItem = imageStore.getImage(_storePath);
|
2013-01-11 18:10:18 +01:00
|
|
|
if (_storeItem) {
|
2012-07-16 21:56:49 +02:00
|
|
|
_storeItem->reference(this);
|
2013-10-05 15:09:03 +02:00
|
|
|
loaded = true;
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
2013-10-05 15:09:03 +02:00
|
|
|
// if no image in store, attempt to load from path (for backward compatibility)
|
2012-07-16 21:56:49 +02:00
|
|
|
else {
|
2013-10-05 15:09:03 +02:00
|
|
|
loaded = load(_storePath);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
path = _storePath;
|
2012-07-16 21:56:49 +02:00
|
|
|
}
|
2018-02-14 20:20:21 +01:00
|
|
|
// if no success from store path, attempt loading from link path (for .mscx files)
|
2013-10-05 15:09:03 +02:00
|
|
|
if (!loaded) {
|
|
|
|
_linkIsValid = load(_linkPath);
|
2013-01-11 18:10:18 +01:00
|
|
|
path = _linkPath;
|
2013-10-05 15:09:03 +02:00
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
if (path.endsWith(".svg")) {
|
2014-05-21 15:49:13 +02:00
|
|
|
setImageType(ImageType::SVG);
|
2013-01-11 18:10:18 +01:00
|
|
|
} else {
|
2014-05-21 15:49:13 +02:00
|
|
|
setImageType(ImageType::RASTER);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// load
|
|
|
|
// load image from file and put into ImageStore
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Image::load(const QString& ss)
|
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
qDebug("Image::load <%s>", qPrintable(ss));
|
2012-07-16 21:56:49 +02:00
|
|
|
QString path(ss);
|
|
|
|
// if file path is relative, prepend score path
|
|
|
|
QFileInfo fi(path);
|
2013-01-11 18:10:18 +01:00
|
|
|
if (fi.isRelative()) {
|
2016-03-10 10:41:31 +01:00
|
|
|
path.prepend(score()->masterScore()->fileInfo()->absolutePath() + "/");
|
2012-07-16 21:56:49 +02:00
|
|
|
fi.setFile(path);
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2012-07-16 21:56:49 +02:00
|
|
|
_linkIsValid = false; // assume link fname is invalid
|
|
|
|
QFile f(path);
|
2013-01-11 18:10:18 +01:00
|
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
|
|
qDebug("Image::load<%s> failed", qPrintable(path));
|
2012-05-26 14:26:10 +02:00
|
|
|
return false;
|
2013-01-11 18:10:18 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
QByteArray ba = f.readAll();
|
|
|
|
f.close();
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2012-07-16 21:56:49 +02:00
|
|
|
_linkIsValid = true;
|
|
|
|
_linkPath = fi.canonicalFilePath();
|
|
|
|
_storeItem = imageStore.add(_linkPath, ba);
|
2012-11-01 00:40:48 +01:00
|
|
|
_storeItem->reference(this);
|
2013-07-04 09:45:21 +02:00
|
|
|
if (path.endsWith(".svg")) {
|
2014-05-21 15:49:13 +02:00
|
|
|
setImageType(ImageType::SVG);
|
2013-07-04 09:45:21 +02:00
|
|
|
} else {
|
2014-05-21 15:49:13 +02:00
|
|
|
setImageType(ImageType::RASTER);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-10-16 18:12:58 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// loadFromData
|
|
|
|
// load image from data and put into ImageStore
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Image::loadFromData(const QString& ss, const QByteArray& ba)
|
|
|
|
{
|
|
|
|
qDebug("Image::loadFromData <%s>", qPrintable(ss));
|
2020-05-26 15:54:26 +02:00
|
|
|
|
2014-10-16 18:12:58 +02:00
|
|
|
_linkIsValid = false;
|
|
|
|
_linkPath = "";
|
|
|
|
_storeItem = imageStore.add(ss, ba);
|
|
|
|
_storeItem->reference(this);
|
|
|
|
if (ss.endsWith(".svg")) {
|
|
|
|
setImageType(ImageType::SVG);
|
|
|
|
} else {
|
|
|
|
setImageType(ImageType::RASTER);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2014-10-16 18:12:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-10 17:12:38 +01:00
|
|
|
//---------------------------------------------------------
|
2017-03-31 13:03:15 +02:00
|
|
|
// startDrag
|
2017-03-10 17:12:38 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2019-01-28 20:27:14 +01:00
|
|
|
void Image::startEditDrag(EditData& data)
|
2017-03-10 17:12:38 +01:00
|
|
|
{
|
2020-01-10 13:55:21 +01:00
|
|
|
BSymbol::startEditDrag(data);
|
|
|
|
ElementEditData* eed = data.getData(this);
|
|
|
|
|
|
|
|
eed->pushProperty(Pid::SIZE);
|
2017-03-10 17:12:38 +01:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// editDrag
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-03-31 13:03:15 +02:00
|
|
|
void Image::editDrag(EditData& ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
qreal ratio = _size.width() / _size.height();
|
|
|
|
qreal dx = ed.delta.x();
|
|
|
|
qreal dy = ed.delta.y();
|
|
|
|
if (_sizeIsSpatium) {
|
|
|
|
qreal _spatium = spatium();
|
|
|
|
dx /= _spatium;
|
|
|
|
dy /= _spatium;
|
|
|
|
} else {
|
2015-11-16 14:24:47 +01:00
|
|
|
dx /= DPMM;
|
|
|
|
dy /= DPMM;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2015-01-19 12:37:17 +01:00
|
|
|
if (ed.curGrip == Grip::START) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_size.setWidth(_size.width() + dx);
|
|
|
|
if (_lockAspectRatio) {
|
|
|
|
_size.setHeight(_size.width() / ratio);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_size.setHeight(_size.height() + dy);
|
|
|
|
if (_lockAspectRatio) {
|
|
|
|
_size.setWidth(_size.height() * ratio);
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
layout();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2019-12-13 14:04:22 +01:00
|
|
|
// gripsPositions
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2019-12-13 14:04:22 +01:00
|
|
|
std::vector<QPointF> Image::gripsPositions(const EditData&) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QRectF r(pageBoundingRect());
|
2019-12-13 14:04:22 +01:00
|
|
|
return {
|
|
|
|
QPointF(r.x() + r.width(), r.y() + r.height() * .5),
|
|
|
|
QPointF(r.x() + r.width() * .5, r.y() + r.height())
|
|
|
|
};
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2017-03-10 17:12:38 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// pixel2Size
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QSizeF Image::pixel2size(const QSizeF& s) const
|
|
|
|
{
|
|
|
|
return s / (_sizeIsSpatium ? spatium() : DPMM);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// size2pixel
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QSizeF Image::size2pixel(const QSizeF& s) const
|
|
|
|
{
|
|
|
|
return s * (_sizeIsSpatium ? spatium() : DPMM);
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layout
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void Image::layout()
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-11-01 14:03:03 +01:00
|
|
|
setPos(0.0, 0.0);
|
2014-05-21 15:49:13 +02:00
|
|
|
if (imageType == ImageType::SVG && !svgDoc) {
|
2017-03-10 17:12:38 +01:00
|
|
|
if (_storeItem) {
|
2013-01-11 18:10:18 +01:00
|
|
|
svgDoc = new QSvgRenderer(_storeItem->buffer());
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2014-05-21 15:49:13 +02:00
|
|
|
} else if (imageType == ImageType::RASTER && !rasterDoc) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (_storeItem) {
|
2013-01-11 18:10:18 +01:00
|
|
|
rasterDoc = new QImage;
|
|
|
|
rasterDoc->loadFromData(_storeItem->buffer());
|
2017-03-10 17:12:38 +01:00
|
|
|
if (!rasterDoc->isNull()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_dirty = true;
|
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2017-03-10 17:12:38 +01:00
|
|
|
if (_size.isNull()) {
|
|
|
|
_size = pixel2size(imageSize());
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
// if autoscale && inside a box, scale to box relevant size
|
2017-03-10 17:12:38 +01:00
|
|
|
if (autoScale() && parent() && ((parent()->isHBox() || parent()->isVBox()))) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (_lockAspectRatio) {
|
2017-03-10 17:12:38 +01:00
|
|
|
qreal f = _sizeIsSpatium ? spatium() : DPMM;
|
2012-05-26 14:26:10 +02:00
|
|
|
QSizeF size(imageSize());
|
|
|
|
qreal ratio = size.width() / size.height();
|
|
|
|
qreal w = parent()->width();
|
|
|
|
qreal h = parent()->height();
|
|
|
|
if ((w / h) < ratio) {
|
|
|
|
_size.setWidth(w / f);
|
|
|
|
_size.setHeight((w / ratio) / f);
|
|
|
|
} else {
|
|
|
|
_size.setHeight(h / f);
|
|
|
|
_size.setWidth(h * ratio / f);
|
|
|
|
}
|
2020-05-26 15:54:26 +02:00
|
|
|
} else {
|
2017-03-10 17:12:38 +01:00
|
|
|
_size = pixel2size(parent()->bbox().size());
|
2020-05-26 15:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// in any case, adjust position relative to parent
|
2017-03-10 17:12:38 +01:00
|
|
|
setbbox(QRectF(QPointF(), size2pixel(_size)));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// getProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
QVariant Image::getProperty(Pid propertyId) const
|
2017-03-10 17:12:38 +01:00
|
|
|
{
|
2020-05-26 11:30:01 +02:00
|
|
|
switch(propertyId) {
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::AUTOSCALE:
|
2017-03-10 17:12:38 +01:00
|
|
|
return autoScale();
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::SIZE:
|
2017-03-10 17:12:38 +01:00
|
|
|
return size();
|
2020-05-26 11:30:01 +02:00
|
|
|
case Pid::IMAGE_HEIGHT:
|
|
|
|
return imageHeight();
|
|
|
|
case Pid::IMAGE_WIDTH:
|
|
|
|
return imageWidth();
|
|
|
|
case Pid::IMAGE_FRAMED:
|
|
|
|
return isImageFramed();
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::LOCK_ASPECT_RATIO:
|
2017-03-10 17:12:38 +01:00
|
|
|
return lockAspectRatio();
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::SIZE_IS_SPATIUM:
|
2017-03-10 17:12:38 +01:00
|
|
|
return sizeIsSpatium();
|
|
|
|
default:
|
|
|
|
return Element::getProperty(propertyId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
bool Image::setProperty(Pid propertyId, const QVariant& v)
|
2017-03-10 17:12:38 +01:00
|
|
|
{
|
|
|
|
bool rv = true;
|
|
|
|
score()->addRefresh(canvasBoundingRect());
|
2020-05-26 11:30:01 +02:00
|
|
|
switch(propertyId) {
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::AUTOSCALE:
|
2017-03-10 17:12:38 +01:00
|
|
|
setAutoScale(v.toBool());
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::SIZE:
|
2017-03-10 17:12:38 +01:00
|
|
|
setSize(v.toSizeF());
|
|
|
|
break;
|
2020-05-26 11:30:01 +02:00
|
|
|
case Pid::IMAGE_HEIGHT:
|
|
|
|
updateImageHeight(v.toDouble());
|
|
|
|
break;
|
|
|
|
case Pid::IMAGE_WIDTH:
|
|
|
|
updateImageWidth(v.toDouble());
|
|
|
|
break;
|
|
|
|
case Pid::IMAGE_FRAMED:
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::LOCK_ASPECT_RATIO:
|
2017-03-10 17:12:38 +01:00
|
|
|
setLockAspectRatio(v.toBool());
|
|
|
|
break;
|
2020-05-26 11:30:01 +02:00
|
|
|
case Pid::SIZE_IS_SPATIUM: {
|
2017-03-10 17:12:38 +01:00
|
|
|
QSizeF s = size2pixel(_size);
|
|
|
|
setSizeIsSpatium(v.toBool());
|
|
|
|
_size = pixel2size(s);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rv = Element::setProperty(propertyId, v);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
setGenerated(false);
|
|
|
|
_dirty = true;
|
|
|
|
triggerLayout();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// propertyDefault
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
QVariant Image::propertyDefault(Pid id) const
|
2017-03-10 17:12:38 +01:00
|
|
|
{
|
2020-05-26 11:30:01 +02:00
|
|
|
switch(id) {
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::AUTOSCALE:
|
2017-03-10 17:12:38 +01:00
|
|
|
return defaultAutoScale;
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::SIZE:
|
2017-03-10 17:12:38 +01:00
|
|
|
return pixel2size(imageSize());
|
2020-05-26 11:30:01 +02:00
|
|
|
case Pid::IMAGE_HEIGHT:
|
|
|
|
return pixel2size(imageSize()).height();
|
|
|
|
case Pid::IMAGE_WIDTH:
|
|
|
|
return pixel2size(imageSize()).width();
|
|
|
|
case Pid::IMAGE_FRAMED:
|
|
|
|
return isImageFramed();
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::LOCK_ASPECT_RATIO:
|
2017-03-10 17:12:38 +01:00
|
|
|
return defaultLockAspectRatio;
|
2018-03-27 15:36:00 +02:00
|
|
|
case Pid::SIZE_IS_SPATIUM:
|
2017-03-10 17:12:38 +01:00
|
|
|
return defaultSizeIsSpatium;
|
|
|
|
default:
|
|
|
|
return Element::propertyDefault(id);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|