[Libreoffice-commits] core.git: external/libepubgen writerperfect/qa writerperfect/source

Miklos Vajna vmiklos at collabora.co.uk
Wed Nov 29 16:49:52 UTC 2017


 external/libepubgen/libepubgen-epub3.patch.1                      |   82 ++++++++
 writerperfect/qa/unit/EPUBExportTest.cxx                          |    5 
 writerperfect/qa/unit/data/writer/epubexport/meta.cover-image.png |binary
 writerperfect/source/writer/EPUBExportFilter.cxx                  |    7 
 writerperfect/source/writer/exp/xmlimp.cxx                        |   92 +++++++++-
 writerperfect/source/writer/exp/xmlimp.hxx                        |    5 
 writerperfect/source/writer/exp/xmlmetai.cxx                      |    1 
 7 files changed, 189 insertions(+), 3 deletions(-)

New commits:
commit 389f7b9581ebd6420a8b9f815807d957608ce8a8
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Nov 29 11:44:55 2017 +0100

    EPUB export: add support for cover images
    
    Pick them up from <base directory>/<base name>.cover-image.<ext> as a
    start.
    
    Change-Id: Ie5ee7c02d6b3271e6e850ca9a2a10ed0bb4a598d
    Reviewed-on: https://gerrit.libreoffice.org/45483
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/external/libepubgen/libepubgen-epub3.patch.1 b/external/libepubgen/libepubgen-epub3.patch.1
index f0facbac64f9..af87b2644e8d 100644
--- a/external/libepubgen/libepubgen-epub3.patch.1
+++ b/external/libepubgen/libepubgen-epub3.patch.1
@@ -4385,3 +4385,85 @@ index d5e650c..a1ce33e 100644
      return false;
    }
    bool fixed = true;
+From 0d06b60d45b3e1465976eb027c3fde31fccdc025 Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos at collabora.co.uk>
+Date: Fri, 17 Nov 2017 15:45:12 +0100
+Subject: [PATCH] EPUBGenerator: add support for cover image metadata
+
+The librevenge:cover-images key can't have a property list as a value,
+so go with a list of cover images, though in practice more than one
+won't result in a valid EPUB3 file.
+---
+ src/lib/EPUBGenerator.cpp          | 18 ++++++++++++++++++
+ src/lib/EPUBImageManager.cpp       |  4 ++--
+ src/lib/EPUBImageManager.h         |  2 +-
+ src/test/EPUBTextGeneratorTest.cpp | 31 +++++++++++++++++++++++++++++++
+ 4 files changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/src/lib/EPUBGenerator.cpp b/src/lib/EPUBGenerator.cpp
+index 64707c5..62dac6e 100644
+--- a/src/lib/EPUBGenerator.cpp
++++ b/src/lib/EPUBGenerator.cpp
+@@ -86,6 +86,24 @@ void EPUBGenerator::endDocument()
+ void EPUBGenerator::setDocumentMetaData(const RVNGPropertyList &props)
+ {
+   m_metadata = props;
++
++  if (m_version == 30)
++  {
++    const librevenge::RVNGPropertyListVector *coverImages = props.child("librevenge:cover-images");
++    if (coverImages)
++    {
++      for (size_t i = 0; i < coverImages->count(); ++i)
++      {
++        librevenge::RVNGPropertyList const &propertyList = (*coverImages)[i];
++        if (propertyList["office:binary-data"] && propertyList["librevenge:mime-type"])
++        {
++          m_imageManager.insert(librevenge::RVNGBinaryData(propertyList["office:binary-data"]->getStr()),
++                                propertyList["librevenge:mime-type"]->getStr(),
++                                "cover-image");
++        }
++      }
++    }
++  }
+ }
+ 
+ void EPUBGenerator::startNewHtmlFile()
+diff --git a/src/lib/EPUBImageManager.cpp b/src/lib/EPUBImageManager.cpp
+index c4c9457..bdf3bf0 100644
+--- a/src/lib/EPUBImageManager.cpp
++++ b/src/lib/EPUBImageManager.cpp
+@@ -84,7 +84,7 @@ EPUBImageManager::EPUBImageManager(EPUBManifest &manifest)
+ {
+ }
+ 
+-const EPUBPath &EPUBImageManager::insert(const librevenge::RVNGBinaryData &data, const librevenge::RVNGString &mimetype)
++const EPUBPath &EPUBImageManager::insert(const librevenge::RVNGBinaryData &data, const librevenge::RVNGString &mimetype, const librevenge::RVNGString &properties)
+ {
+   MapType_t::const_iterator it = m_map.find(data);
+   if (m_map.end() == it)
+@@ -99,7 +99,7 @@ const EPUBPath &EPUBImageManager::insert(const librevenge::RVNGBinaryData &data,
+ 
+     const EPUBPath path(EPUBPath("OEBPS/images") / nameBuf.str());
+ 
+-    m_manifest.insert(path, mime, id, "");
++    m_manifest.insert(path, mime, id, properties.cstr());
+     it = m_map.insert(MapType_t::value_type(data, path)).first;
+   }
+ 
+diff --git a/src/lib/EPUBImageManager.h b/src/lib/EPUBImageManager.h
+index 3f4bf3c..cbb83b7 100644
+--- a/src/lib/EPUBImageManager.h
++++ b/src/lib/EPUBImageManager.h
+@@ -49,7 +49,7 @@ class EPUBImageManager
+ public:
+   explicit EPUBImageManager(EPUBManifest &manifest);
+ 
+-  const EPUBPath &insert(const librevenge::RVNGBinaryData &data, const librevenge::RVNGString &mimetype);
++  const EPUBPath &insert(const librevenge::RVNGBinaryData &data, const librevenge::RVNGString &mimetype, const librevenge::RVNGString &properties="");
+ 
+   void writeTo(EPUBPackage &package);
+ 
+-- 
+2.13.6
+
diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx
index c8fe9a3491bd..e038a7ef6135 100644
--- a/writerperfect/qa/unit/EPUBExportTest.cxx
+++ b/writerperfect/qa/unit/EPUBExportTest.cxx
@@ -326,6 +326,11 @@ void EPUBExportTest::testMeta()
     assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", "Title");
     assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:language", "hu");
     assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='dcterms:modified']", "2017-09-27T09:51:19Z");
+
+    // Make sure that cover image next to the source document is picked up.
+    assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']", "properties", "cover-image");
+    assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']", "media-type", "image/png");
+    CPPUNIT_ASSERT(mxZipFile->hasByName("OEBPS/images/image0001.png"));
 }
 
 void EPUBExportTest::testParaNamedstyle()
diff --git a/writerperfect/qa/unit/data/writer/epubexport/meta.cover-image.png b/writerperfect/qa/unit/data/writer/epubexport/meta.cover-image.png
new file mode 100644
index 000000000000..fdad35484e7c
Binary files /dev/null and b/writerperfect/qa/unit/data/writer/epubexport/meta.cover-image.png differ
diff --git a/writerperfect/source/writer/EPUBExportFilter.cxx b/writerperfect/source/writer/EPUBExportFilter.cxx
index b17c57aa784e..2454adddc781 100644
--- a/writerperfect/source/writer/EPUBExportFilter.cxx
+++ b/writerperfect/source/writer/EPUBExportFilter.cxx
@@ -14,6 +14,7 @@
 #include <libepubgen/EPUBTextGenerator.h>
 #include <libepubgen/libepubgen-decls.h>
 
+#include <com/sun/star/frame/XModel.hpp>
 #include <com/sun/star/lang/XInitialization.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
@@ -74,7 +75,11 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe
                                              , nVersion
 #endif
                                             );
-    uno::Reference<xml::sax::XDocumentHandler> xExportHandler(new exp::XMLImport(aGenerator));
+    OUString aSourceURL;
+    uno::Reference<frame::XModel> xSourceModel(mxSourceDocument, uno::UNO_QUERY);
+    if (xSourceModel.is())
+        aSourceURL = xSourceModel->getURL();
+    uno::Reference<xml::sax::XDocumentHandler> xExportHandler(new exp::XMLImport(aGenerator, aSourceURL, rDescriptor));
 
     uno::Reference<lang::XInitialization> xInitialization(mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.Writer.XMLOasisExporter", mxContext), uno::UNO_QUERY);
     xInitialization->initialize({uno::makeAny(xExportHandler)});
diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx
index 30a7ee03d404..3d7f99cc399e 100644
--- a/writerperfect/source/writer/exp/xmlimp.cxx
+++ b/writerperfect/source/writer/exp/xmlimp.cxx
@@ -9,6 +9,13 @@
 
 #include "xmlimp.hxx"
 
+#include <initializer_list>
+#include <unordered_map>
+
+#include <rtl/uri.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+
 #include "xmlfmt.hxx"
 #include "xmlictxt.hxx"
 #include "xmlmetai.hxx"
@@ -21,6 +28,70 @@ namespace writerperfect
 namespace exp
 {
 
+namespace
+{
+/// Looks up mime type for a given image extension.
+OUString GetMimeType(const OUString &rExtension)
+{
+    static const std::unordered_map<OUString, OUString> vMimeTypes =
+    {
+        {"gif", "image/gif"},
+        {"jpg", "image/jpeg"},
+        {"png", "image/png"},
+        {"svg", "image/svg+xml"},
+    };
+
+    auto it = vMimeTypes.find(rExtension);
+    return it == vMimeTypes.end() ? OUString() : it->second;
+}
+
+/// Picks up a cover image from the base directory.
+OUString FindCoverImage(const OUString &rDocumentBaseURL, OUString &rMimeType)
+{
+    OUString aRet;
+
+    if (rDocumentBaseURL.isEmpty())
+        return aRet;
+
+    INetURLObject aDocumentBaseURL(rDocumentBaseURL);
+
+    static const std::initializer_list<OUStringLiteral> vExtensions =
+    {
+        "gif",
+        "jpg",
+        "png",
+        "svg"
+    };
+
+    for (const auto &rExtension : vExtensions)
+    {
+        try
+        {
+            aRet = rtl::Uri::convertRelToAbs(rDocumentBaseURL, aDocumentBaseURL.GetBase() + ".cover-image." + rExtension);
+        }
+        catch (const rtl::MalformedUriException &rException)
+        {
+            SAL_WARN("writerfilter", "FindCoverImage: convertRelToAbs() failed:" << rException.getMessage());
+        }
+
+        if (!aRet.isEmpty())
+        {
+            SvFileStream aStream(aRet, StreamMode::READ);
+            if (aStream.IsOpen())
+            {
+                rMimeType = GetMimeType(rExtension);
+                // File exists.
+                return aRet;
+            }
+            else
+                aRet.clear();
+        }
+    }
+
+    return aRet;
+}
+}
+
 /// Handler for <office:body>.
 class XMLBodyContext : public XMLImportContext
 {
@@ -71,9 +142,28 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O
     return nullptr;
 }
 
-XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator)
+XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &/*rDescriptor*/)
     : mrGenerator(rGenerator)
 {
+    OUString aMimeType;
+    OUString aCoverImage = FindCoverImage(rURL, aMimeType);
+    if (!aCoverImage.isEmpty())
+    {
+        librevenge::RVNGBinaryData aBinaryData;
+        SvFileStream aStream(aCoverImage, StreamMode::READ);
+        SvMemoryStream aMemoryStream;
+        aMemoryStream.WriteStream(aStream);
+        aBinaryData.append(static_cast<const unsigned char *>(aMemoryStream.GetBuffer()), aMemoryStream.GetSize());
+        librevenge::RVNGPropertyList aCoverImageProperties;
+        aCoverImageProperties.insert("office:binary-data", aBinaryData);
+        aCoverImageProperties.insert("librevenge:mime-type", aMimeType.toUtf8().getStr());
+        maCoverImages.append(aCoverImageProperties);
+    }
+}
+
+const librevenge::RVNGPropertyListVector &XMLImport::GetCoverImages()
+{
+    return maCoverImages;
 }
 
 rtl::Reference<XMLImportContext> XMLImport::CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx
index e1b80571d278..b1008f00dbf0 100644
--- a/writerperfect/source/writer/exp/xmlimp.hxx
+++ b/writerperfect/source/writer/exp/xmlimp.hxx
@@ -15,6 +15,7 @@
 
 #include <librevenge/librevenge.h>
 
+#include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
 
 #include <cppuhelper/implbase.hxx>
@@ -49,9 +50,10 @@ class XMLImport : public cppu::WeakImplHelper
     std::map<OUString, librevenge::RVNGPropertyList> maTableStyles;
     std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles;
     std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles;
+    librevenge::RVNGPropertyListVector maCoverImages;
 
 public:
-    XMLImport(librevenge::RVNGTextInterface &rGenerator);
+    XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const css::uno::Sequence<css::beans::PropertyValue> &rDescriptor);
 
     rtl::Reference<XMLImportContext> CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs);
 
@@ -70,6 +72,7 @@ public:
     std::map<OUString, librevenge::RVNGPropertyList> &GetRowStyles();
     std::map<OUString, librevenge::RVNGPropertyList> &GetTableStyles();
     std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles();
+    const librevenge::RVNGPropertyListVector &GetCoverImages();
 
     // XDocumentHandler
     void SAL_CALL startDocument() override;
diff --git a/writerperfect/source/writer/exp/xmlmetai.cxx b/writerperfect/source/writer/exp/xmlmetai.cxx
index 0d804833bc7a..ad39aa8c39f1 100644
--- a/writerperfect/source/writer/exp/xmlmetai.cxx
+++ b/writerperfect/source/writer/exp/xmlmetai.cxx
@@ -131,6 +131,7 @@ void XMLMetaInitialCreatorContext::characters(const OUString &rChars)
 XMLMetaDocumentContext::XMLMetaDocumentContext(XMLImport &rImport)
     : XMLImportContext(rImport)
 {
+    m_aPropertyList.insert("librevenge:cover-images", mrImport.GetCoverImages());
 }
 
 rtl::Reference<XMLImportContext> XMLMetaDocumentContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)


More information about the Libreoffice-commits mailing list