Kaydet (Commit) 389f7b95 authored tarafından Miklos Vajna's avatar Miklos Vajna

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/45483Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
üst 67eeab17
...@@ -4385,3 +4385,85 @@ index d5e650c..a1ce33e 100644 ...@@ -4385,3 +4385,85 @@ index d5e650c..a1ce33e 100644
return false; return false;
} }
bool fixed = true; bool fixed = true;
From 0d06b60d45b3e1465976eb027c3fde31fccdc025 Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@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
...@@ -326,6 +326,11 @@ void EPUBExportTest::testMeta() ...@@ -326,6 +326,11 @@ void EPUBExportTest::testMeta()
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", "Title"); assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", "Title");
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:language", "hu"); 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"); 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() void EPUBExportTest::testParaNamedstyle()
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <libepubgen/EPUBTextGenerator.h> #include <libepubgen/EPUBTextGenerator.h>
#include <libepubgen/libepubgen-decls.h> #include <libepubgen/libepubgen-decls.h>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/lang/XInitialization.hpp> #include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp> #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
...@@ -74,7 +75,11 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe ...@@ -74,7 +75,11 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe
, nVersion , nVersion
#endif #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); uno::Reference<lang::XInitialization> xInitialization(mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.Writer.XMLOasisExporter", mxContext), uno::UNO_QUERY);
xInitialization->initialize({uno::makeAny(xExportHandler)}); xInitialization->initialize({uno::makeAny(xExportHandler)});
......
...@@ -9,6 +9,13 @@ ...@@ -9,6 +9,13 @@
#include "xmlimp.hxx" #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 "xmlfmt.hxx"
#include "xmlictxt.hxx" #include "xmlictxt.hxx"
#include "xmlmetai.hxx" #include "xmlmetai.hxx"
...@@ -21,6 +28,70 @@ namespace writerperfect ...@@ -21,6 +28,70 @@ namespace writerperfect
namespace exp 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>. /// Handler for <office:body>.
class XMLBodyContext : public XMLImportContext class XMLBodyContext : public XMLImportContext
{ {
...@@ -71,9 +142,28 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O ...@@ -71,9 +142,28 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O
return nullptr; return nullptr;
} }
XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator) XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &/*rDescriptor*/)
: mrGenerator(rGenerator) : 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*/) rtl::Reference<XMLImportContext> XMLImport::CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <librevenge/librevenge.h> #include <librevenge/librevenge.h>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp> #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <cppuhelper/implbase.hxx> #include <cppuhelper/implbase.hxx>
...@@ -49,9 +50,10 @@ class XMLImport : public cppu::WeakImplHelper ...@@ -49,9 +50,10 @@ class XMLImport : public cppu::WeakImplHelper
std::map<OUString, librevenge::RVNGPropertyList> maTableStyles; std::map<OUString, librevenge::RVNGPropertyList> maTableStyles;
std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles; std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles;
std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles; std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles;
librevenge::RVNGPropertyListVector maCoverImages;
public: 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); rtl::Reference<XMLImportContext> CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs);
...@@ -70,6 +72,7 @@ public: ...@@ -70,6 +72,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList> &GetRowStyles(); std::map<OUString, librevenge::RVNGPropertyList> &GetRowStyles();
std::map<OUString, librevenge::RVNGPropertyList> &GetTableStyles(); std::map<OUString, librevenge::RVNGPropertyList> &GetTableStyles();
std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles(); std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles();
const librevenge::RVNGPropertyListVector &GetCoverImages();
// XDocumentHandler // XDocumentHandler
void SAL_CALL startDocument() override; void SAL_CALL startDocument() override;
......
...@@ -131,6 +131,7 @@ void XMLMetaInitialCreatorContext::characters(const OUString &rChars) ...@@ -131,6 +131,7 @@ void XMLMetaInitialCreatorContext::characters(const OUString &rChars)
XMLMetaDocumentContext::XMLMetaDocumentContext(XMLImport &rImport) XMLMetaDocumentContext::XMLMetaDocumentContext(XMLImport &rImport)
: XMLImportContext(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*/) rtl::Reference<XMLImportContext> XMLMetaDocumentContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
......
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