]> git.sesse.net Git - kdenlive/blobdiff - src/titledocument.cpp
When adding an existing kdenlive title clip to the project , detach embedded images:
[kdenlive] / src / titledocument.cpp
index ed9bc0b2815d9f6ce85e485a0d7d6464272ea913..8c360d7d4002bdca0220440c8eb661a266a7ba77 100644 (file)
@@ -21,6 +21,7 @@
 #include <KTemporaryFile>
 #include <kio/netaccess.h>
 #include <KApplication>
+#include <KStandardDirs>
 #include <KLocale>
 #include <KMessageBox>
 
@@ -30,6 +31,8 @@
 #include <QGraphicsRectItem>
 #include <QGraphicsTextItem>
 #include <QGraphicsSvgItem>
+#include <QCryptographicHash>
+#include <QSvgRenderer>
 #include <QFontInfo>
 #include <QFile>
 #include <QTextCursor>
 #include <QGraphicsDropShadowEffect>
 #endif
 
+QByteArray fileToByteArray(const QString& filename)
+{
+    QByteArray ret;
+    QFile file(filename);
+    if (file.open(QIODevice::ReadOnly)) {
+        while (!file.atEnd()) {
+            ret.append(file.readLine());
+        }
+    }
+    return ret;
+}
+
 TitleDocument::TitleDocument()
 {
     m_scene = NULL;
@@ -52,7 +67,54 @@ void TitleDocument::setScene(QGraphicsScene* _scene, int width, int height)
     m_height = height;
 }
 
-QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* endv)
+int TitleDocument::base64ToUrl(QGraphicsItem* item, QDomElement& content, bool embed)
+{
+    if (embed) {
+        if (!item->data(Qt::UserRole + 1).toString().isEmpty()) {
+            content.setAttribute("base64", item->data(Qt::UserRole + 1).toString());
+        } else if (!item->data(Qt::UserRole).toString().isEmpty()) {
+            content.setAttribute("base64", fileToByteArray(item->data(Qt::UserRole).toString()).toBase64().data());
+        }
+        content.removeAttribute("url");
+    } else {
+        // save for project files to disk
+        QString base64 = item->data(Qt::UserRole + 1).toString();
+        if (!base64.isEmpty()) {
+            QString titlePath;
+            if (!m_projectPath.isEmpty()) {
+                titlePath = m_projectPath;
+            } else {
+                titlePath = "/tmp/titles";
+            }
+            QString filename = extractBase64Image(titlePath, base64);
+            if (!filename.isEmpty()) {
+                content.setAttribute("url", filename);
+                content.removeAttribute("base64");
+            }
+
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+//static
+const QString TitleDocument::extractBase64Image(const QString &titlePath, const QString &data)
+{
+    QString filename = titlePath + QString(QCryptographicHash::hash(data.toAscii(), QCryptographicHash::Md5).toHex().append(".titlepart"));
+    KStandardDirs::makeDir(titlePath);
+    QFile f(filename);
+    if (f.open(QIODevice::WriteOnly)) {
+        f.write(QByteArray::fromBase64(data.toAscii())) ;
+        f.close();
+        return filename;
+    }
+    return QString();
+}
+
+QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* endv, bool embed)
 {
     QDomDocument doc;
 
@@ -61,7 +123,7 @@ QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* en
     main.setAttribute("height", m_height);
     doc.appendChild(main);
 
-    foreach(QGraphicsItem* item, m_scene->items()) {
+    foreach(QGraphicsItem * item, m_scene->items()) {
         QDomElement e = doc.createElement("item");
         QDomElement content = doc.createElement("content");
         QFont font;
@@ -71,10 +133,12 @@ QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* en
         case 7:
             e.setAttribute("type", "QGraphicsPixmapItem");
             content.setAttribute("url", item->data(Qt::UserRole).toString());
+            base64ToUrl(item, content, embed);
             break;
         case 13:
             e.setAttribute("type", "QGraphicsSvgItem");
             content.setAttribute("url", item->data(Qt::UserRole).toString());
+            base64ToUrl(item, content, embed);
             break;
         case 3:
             e.setAttribute("type", "QGraphicsRectItem");
@@ -209,12 +273,12 @@ QColor TitleDocument::getBackgroundColor()
 }
 
 
-bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out)
+bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out, bool embed)
 {
     if (!m_scene)
         return false;
 
-    QDomDocument doc = xml(startv, endv);
+    QDomDocument doc = xml(startv, endv, embed);
     doc.documentElement().setAttribute("out", out);
     KTemporaryFile tmpfile;
     if (!tmpfile.open()) {
@@ -232,8 +296,9 @@ bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGr
     return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
 }
 
-int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out)
+int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out, const QString& projectpath)
 {
+    m_projectPath = projectpath;
     QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
     //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
     if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
@@ -245,6 +310,16 @@ int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGra
             m_width = doc_width;
             m_height = doc_height;
         }
+    } else {
+        // Document has no size info, it is likely an old version title, so ignore viewport data
+        QDomNodeList viewportlist = doc.documentElement().elementsByTagName("startviewport");
+        if (!viewportlist.isEmpty()) {
+            doc.documentElement().removeChild(viewportlist.at(0));
+        }
+        viewportlist = doc.documentElement().elementsByTagName("endviewport");
+        if (!viewportlist.isEmpty()) {
+            doc.documentElement().removeChild(viewportlist.at(0));
+        }
     }
     //TODO: get default title duration instead of hardcoded one
     if (doc.documentElement().hasAttribute("out"))
@@ -333,20 +408,44 @@ int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGra
                     QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
                     QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
                     double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
-                    QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
+                    QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin), QBrush(stringToColor(br_str)));
                     gitem = rec;
                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
-                    QPixmap pix(url);
+                    QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue();
+                    QPixmap pix;
+                    if (base64.isEmpty()) {
+                        pix.load(url);
+                    } else {
+                        pix.loadFromData(QByteArray::fromBase64(base64.toAscii()));
+                    }
                     QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
                     rec->setData(Qt::UserRole, url);
+                    if (!base64.isEmpty()) {
+                        rec->setData(Qt::UserRole + 1, base64);
+                    }
                     gitem = rec;
                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
-                    QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
-                    m_scene->addItem(rec);
-                    rec->setData(Qt::UserRole, url);
-                    gitem = rec;
+                    QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue();
+                    QGraphicsSvgItem *rec = NULL;
+                    if (base64.isEmpty()) {
+                        rec = new QGraphicsSvgItem(url);
+                    } else {
+                        rec = new QGraphicsSvgItem();
+                        QSvgRenderer *renderer = new QSvgRenderer(QByteArray::fromBase64(base64.toAscii()), rec);
+                        rec->setSharedRenderer(renderer);
+                        //QString elem=rec->elementId();
+                        //QRectF bounds = renderer->boundsOnElement(elem);
+                    }
+                    if (rec) {
+                        m_scene->addItem(rec);
+                        rec->setData(Qt::UserRole, url);
+                        if (!base64.isEmpty()) {
+                            rec->setData(Qt::UserRole + 1, base64);
+                        }
+                        gitem = rec;
+                    }
                 }
             }
             //pos and transform