Commit b3e59c91 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Save shape selections as SVG as well

parent 3d796ce4
......@@ -356,21 +356,15 @@ void KisShapeLayer::setVisible(bool visible, bool isLoading)
#include "SvgParser.h"
#include <QXmlStreamReader>
bool KisShapeLayer::saveLayer(KoStore * store) const
bool KisShapeLayer::saveShapesToStore(KoStore *store, QList<KoShape *> shapes, const QSizeF &sizeInPt)
{
if (!store->open("content.svg")) {
return false;
}
// FIXME: we handle xRes() only!
const QSizeF sizeInPx = image()->bounds().size();
const QSizeF sizeInPt(sizeInPx.width() / image()->xRes(), sizeInPx.height() / image()->yRes());
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::WriteOnly);
QList<KoShape*> shapes = this->shapes();
qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
SvgWriter writer(shapes, sizeInPt);
......@@ -383,11 +377,7 @@ bool KisShapeLayer::saveLayer(KoStore * store) const
return true;
}
QList<KoShape *> KisShapeLayer::createShapesFromSvg(QIODevice *device, const QString &baseXmlDir,
const QRectF &rectInPixels,
qreal resolutionPPI,
KoDocumentResourceManager *resourceManager,
QSizeF *fragmentSize)
QList<KoShape *> KisShapeLayer::createShapesFromSvg(QIODevice *device, const QString &baseXmlDir, const QRectF &rectInPixels, qreal resolutionPPI, KoDocumentResourceManager *resourceManager, QSizeF *fragmentSize)
{
QXmlStreamReader reader(device);
reader.setNamespaceProcessing(false);
......@@ -412,6 +402,17 @@ QList<KoShape *> KisShapeLayer::createShapesFromSvg(QIODevice *device, const QSt
return parser.parseSvg(doc.documentElement(), fragmentSize);
}
bool KisShapeLayer::saveLayer(KoStore * store) const
{
// FIXME: we handle xRes() only!
const QSizeF sizeInPx = image()->bounds().size();
const QSizeF sizeInPt(sizeInPx.width() / image()->xRes(), sizeInPx.height() / image()->yRes());
return saveShapesToStore(store, this->shapes(), sizeInPt);
}
bool KisShapeLayer::loadSvg(QIODevice *device, const QString &baseXmlDir)
{
QSizeF fragmentSize; // unused!
......
......@@ -105,17 +105,20 @@ public:
KoShapeManager *shapeManager() const;
bool saveLayer(KoStore * store) const;
static bool saveShapesToStore(KoStore *store, QList<KoShape*> shapes, const QSizeF &sizeInPt);
bool loadSvg(QIODevice *device, const QString &baseXmlDir);
bool loadLayer(KoStore* store);
static QList<KoShape*> createShapesFromSvg(QIODevice *device, const QString &baseXmlDir,
const QRectF &rectInPixels, qreal resolutionPPI,
static QList<KoShape *> createShapesFromSvg(QIODevice *device,
const QString &baseXmlDir,
const QRectF &rectInPixels,
qreal resolutionPPI,
KoDocumentResourceManager *resourceManager,
QSizeF *fragmentSize);
bool saveLayer(KoStore * store) const;
bool loadLayer(KoStore* store);
KUndo2Command* crop(const QRect & rect) override;
KUndo2Command* transform(const QTransform &transform) override;
......@@ -125,6 +128,8 @@ public:
protected:
using KoShape::isVisible;
bool loadSvg(QIODevice *device, const QString &baseXmlDir);
friend class ShapeLayerContainerModel;
KoViewConverter* converter() const;
......
......@@ -61,6 +61,7 @@
#include "kis_shape_selection_canvas.h"
#include "kis_take_all_shapes_command.h"
#include "kis_image_view_converter.h"
#include "kis_shape_layer.h"
#include <kis_debug.h>
......@@ -109,100 +110,41 @@ KisSelectionComponent* KisShapeSelection::clone(KisSelection* selection)
bool KisShapeSelection::saveSelection(KoStore * store) const
{
const QSizeF sizeInPx = m_image->bounds().size();
const QSizeF sizeInPt(sizeInPx.width() / m_image->xRes(), sizeInPx.height() / m_image->yRes());
KoOdfWriteStore odfStore(store);
KoXmlWriter* manifestWriter = odfStore.manifestWriter("application/vnd.oasis.opendocument.graphics");
KoEmbeddedDocumentSaver embeddedSaver;
KisDocument::SavingContext documentContext(odfStore, embeddedSaver);
if (!store->open("content.xml"))
return false;
KoStoreDevice storeDev(store);
KoXmlWriter * docWriter = KoOdfWriteStore::createOasisXmlWriter(&storeDev, "office:document-content");
// for office:master-styles
QTemporaryFile masterStyles;
masterStyles.open();
KoXmlWriter masterStylesTmpWriter(&masterStyles, 1);
KoPageLayout page;
page.format = KoPageFormat::defaultFormat();
QRectF rc = boundingRect();
page.width = rc.width();
page.height = rc.height();
if (page.width > page.height) {
page.orientation = KoPageFormat::Landscape;
} else {
page.orientation = KoPageFormat::Portrait;
}
KoGenStyles mainStyles;
KoGenStyle pageLayout = page.saveOdf();
QString layoutName = mainStyles.insert(pageLayout, "PL");
KoGenStyle masterPage(KoGenStyle::MasterPageStyle);
masterPage.addAttribute("style:page-layout-name", layoutName);
mainStyles.insert(masterPage, "Default", KoGenStyles::DontAddNumberToName);
QTemporaryFile contentTmpFile;
contentTmpFile.open();
KoXmlWriter contentTmpWriter(&contentTmpFile, 1);
contentTmpWriter.startElement("office:body");
contentTmpWriter.startElement("office:drawing");
KoShapeSavingContext shapeContext(contentTmpWriter, mainStyles, documentContext.embeddedSaver);
shapeContext.xmlWriter().startElement("draw:page");
shapeContext.xmlWriter().addAttribute("draw:name", "");
KoElementReference elementRef;
elementRef.saveOdf(&shapeContext.xmlWriter(), KoElementReference::DrawId);
shapeContext.xmlWriter().addAttribute("draw:master-page-name", "Default");
saveOdf(shapeContext);
shapeContext.xmlWriter().endElement(); // draw:page
return KisShapeLayer::saveShapesToStore(store, this->shapes(), sizeInPt);
}
contentTmpWriter.endElement(); // office:drawing
contentTmpWriter.endElement(); // office:body
bool KisShapeSelection::loadSelection(KoStore* store)
{
QSizeF fragmentSize; // unused!
mainStyles.saveOdfStyles(KoGenStyles::DocumentAutomaticStyles, docWriter);
// FIXME: we handle xRes() only!
KIS_SAFE_ASSERT_RECOVER_NOOP(qFuzzyCompare(m_image->xRes(), m_image->yRes()));
const qreal resolutionPPI = 72.0 * m_image->xRes();
// And now we can copy over the contents from the tempfile to the real one
contentTmpFile.seek(0);
docWriter->addCompleteElement(&contentTmpFile);
QList<KoShape*> shapes;
docWriter->endElement(); // Root element
docWriter->endDocument();
delete docWriter;
if (store->open("content.svg")) {
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::ReadOnly);
if (!store->close())
return false;
shapes = KisShapeLayer::createShapesFromSvg(&storeDev,
"", m_image->bounds(),
resolutionPPI, m_canvas->shapeController()->resourceManager(),
&fragmentSize);
manifestWriter->addManifestEntry("content.xml", "text/xml");
store->close();
if (! mainStyles.saveOdfStylesDotXml(store, manifestWriter)) {
return false;
Q_FOREACH (KoShape *shape, shapes) {
addShape(shape);
}
manifestWriter->addManifestEntry("settings.xml", "text/xml");
if (! shapeContext.saveDataCenter(documentContext.odfStore.store(), documentContext.odfStore.manifestWriter()))
return false;
// Write out manifest file
if (!odfStore.closeManifestWriter()) {
dbgImage << "closing manifestWriter failed";
return false;
return true;
}
return true;
}
bool KisShapeSelection::loadSelection(KoStore* store)
{
KoOdfReadStore odfStore(store);
QString errorMessage;
......@@ -281,7 +223,6 @@ bool KisShapeSelection::loadSelection(KoStore* store)
}
return true;
}
void KisShapeSelection::setUpdatesEnabled(bool enabled)
......
......@@ -583,7 +583,9 @@ bool KisKraLoadVisitor::loadSelection(const QString& location, KisSelectionSP ds
// Shape selection
QString shapeSelectionLocation = location + DOT_SHAPE_SELECTION;
if (m_store->hasFile(shapeSelectionLocation + "/content.xml")) {
if (m_store->hasFile(shapeSelectionLocation + "/content.svg") ||
m_store->hasFile(shapeSelectionLocation + "/content.xml")) {
m_store->pushDirectory();
m_store->enterDirectory(shapeSelectionLocation) ;
......
......@@ -480,4 +480,70 @@ void KisKraSaverTest::testRoundTripShapeLayer()
QVERIFY(chk.testPassed());
}
void KisKraSaverTest::testRoundTripShapeSelection()
{
TestUtil::ExternalImageChecker chk("kra_saver_test", "shape_selection");
QRect refRect(0,0,512,512);
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
TestUtil::MaskParent p(refRect);
const qreal resolution = 144.0 / 72.0;
p.image->setResolution(resolution, resolution);
doc->setCurrentImage(p.image);
doc->documentInfo()->setAboutInfo("title", p.image->objectName());
p.layer->paintDevice()->setDefaultPixel(KoColor(Qt::green, p.layer->colorSpace()));
KisSelectionSP selection = new KisSelection(p.layer->paintDevice()->defaultBounds());
KisShapeSelection *shapeSelection = new KisShapeSelection(p.image, selection);
selection->setShapeSelection(shapeSelection);
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF( 10, 110));
path->lineTo(QPointF(110, 110));
path->lineTo(QPointF(110, 10));
path->close();
path->normalize();
path->setBackground(toQShared(new KoColorBackground(Qt::red)));
path->setName("my_precious_shape");
shapeSelection->addShape(path);
KisTransparencyMaskSP tmask = new KisTransparencyMask();
tmask->setSelection(selection);
p.image->addNode(tmask, p.layer);
tmask->setDirty(p.image->bounds());
qApp->processEvents();
p.image->waitForDone();
chk.checkImage(p.image, "00_initial_shape_selection");
doc->exportDocument(QUrl::fromLocalFile("roundtrip_shapeselection_test.kra"));
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_shapeselection_test.kra");
qApp->processEvents();
doc2->image()->waitForDone();
QCOMPARE(doc2->image()->xRes(), resolution);
QCOMPARE(doc2->image()->yRes(), resolution);
chk.checkImage(doc2->image(), "00_initial_shape_selection");
KisNodeSP node = doc2->image()->root()->firstChild()->firstChild();
KisTransparencyMask *newMask = dynamic_cast<KisTransparencyMask*>(node.data());
QVERIFY(newMask);
QVERIFY(newMask->selection()->hasShapeSelection());
QVERIFY(chk.testPassed());
}
QTEST_MAIN(KisKraSaverTest)
......@@ -44,6 +44,7 @@ private Q_SLOTS:
void testRoundTripColorizeMask();
void testRoundTripShapeLayer();
void testRoundTripShapeSelection();
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment