summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacobo Aragunde Pérez <jaragunde@igalia.com>2014-05-22 13:54:42 +0200
committerJacobo Aragunde Pérez <jaragunde@igalia.com>2014-05-23 10:04:00 +0200
commit2e68a1468c035fc3bb4d02ad0b3187872fe1e67b (patch)
tree0bd5ccdee8253233ca7f919a70c5bd337b3b5a37
parent642a252cf1a2f1d08c4bbfcae15527bb82c7664d (diff)
ooxml: Preserve the original picture in artistic effects
When Word applies an artistic effect, it creates two embedded files; one contains the bitmap with the effect and the other one contains the original bitmap to be able to undo the effect. This patch reads the original bitmap, stores it in the shape grab bag and saves it back to the docx file. Added unit tests too. TODO: right now, if two effects point to the same original bitmap it is stored twice, we should improve this. Change-Id: Ia72034a257739abe4ffafa0f42b2a912e4bf9436
-rw-r--r--include/oox/drawingml/fillproperties.hxx2
-rw-r--r--include/oox/export/drawingml.hxx2
-rw-r--r--oox/source/drawingml/fillproperties.cxx8
-rw-r--r--oox/source/drawingml/fillpropertiesgroupcontext.cxx13
-rw-r--r--oox/source/export/drawingml.cxx30
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx48
6 files changed, 98 insertions, 5 deletions
diff --git a/include/oox/drawingml/fillproperties.hxx b/include/oox/drawingml/fillproperties.hxx
index c588deec8faa..dcf3afbfd230 100644
--- a/include/oox/drawingml/fillproperties.hxx
+++ b/include/oox/drawingml/fillproperties.hxx
@@ -26,6 +26,7 @@
#include <oox/drawingml/color.hxx>
#include <oox/helper/helper.hxx>
#include <oox/drawingml/embeddedwavaudiofile.hxx>
+#include <oox/ole/oleobjecthelper.hxx>
namespace oox {
class GraphicHelper;
@@ -70,6 +71,7 @@ struct ArtisticEffectProperties
OUString msName;
std::map< OUString, css::uno::Any >
maAttribs;
+ ::oox::ole::OleObjectInfo mrOleObjectInfo; /// The original graphic as embedded object.
bool isEmpty() const;
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 98cc0dfb38a0..77d54b48b014 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -82,6 +82,7 @@ public:
private:
static int mnImageCounter;
+ static int mnWdpImageCounter;
/// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC).
DocumentType meDocumentType;
@@ -177,6 +178,7 @@ public:
void WriteShapeEffect( const OUString& sName, const css::uno::Sequence< css::beans::PropertyValue >& aEffectProps );
void WriteShape3DEffects( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
void WriteArtisticEffect( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
+ OString WriteWdpPicture( const ::com::sun::star::uno::Sequence< sal_Int8 >& rPictureData );
static void ResetCounters();
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx
index a9ca0db37546..7d816758f459 100644
--- a/oox/source/drawingml/fillproperties.cxx
+++ b/oox/source/drawingml/fillproperties.cxx
@@ -608,7 +608,7 @@ css::beans::PropertyValue ArtisticEffectProperties::getEffect()
if( msName.isEmpty() )
return pRet;
- css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() );
+ css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() + 1 );
sal_uInt32 i = 0;
for( std::map< OUString, css::uno::Any >::iterator it = maAttribs.begin(); it != maAttribs.end(); ++it )
{
@@ -617,6 +617,12 @@ css::beans::PropertyValue ArtisticEffectProperties::getEffect()
i++;
}
+ if( mrOleObjectInfo.maEmbeddedData.hasElements() )
+ {
+ aSeq[i].Name = "OriginalGraphic";
+ aSeq[i].Value = uno::makeAny( mrOleObjectInfo.maEmbeddedData );
+ }
+
pRet.Name = msName;
pRet.Value = css::uno::Any( aSeq );
diff --git a/oox/source/drawingml/fillpropertiesgroupcontext.cxx b/oox/source/drawingml/fillpropertiesgroupcontext.cxx
index e7e414277906..ac8f215a9d03 100644
--- a/oox/source/drawingml/fillpropertiesgroupcontext.cxx
+++ b/oox/source/drawingml/fillpropertiesgroupcontext.cxx
@@ -333,9 +333,18 @@ ContextHandlerRef ArtisticEffectContext::onCreateContext(
sal_Int32 nElement, const AttributeList& rAttribs )
{
// containers
- if( nElement == OOX_TOKEN( a14, imgLayer ) || nElement == OOX_TOKEN( a14, imgEffect ) )
+ if( nElement == OOX_TOKEN( a14, imgLayer ) )
+ {
+ if( rAttribs.hasAttribute( R_TOKEN( embed ) ) )
+ {
+ OUString aFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( embed ), OUString() ) );
+ if( !aFragmentPath.isEmpty() )
+ getFilter().importBinaryData( maEffect.mrOleObjectInfo.maEmbeddedData, aFragmentPath );
+ }
+ return new ArtisticEffectContext( *this, maEffect );
+ }
+ if( nElement == OOX_TOKEN( a14, imgEffect ) )
return new ArtisticEffectContext( *this, maEffect );
- // TODO: manage r:embed attribute in a14:imgLayer
// effects
maEffect.msName = ArtisticEffectProperties::getEffectString( nElement );
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 0364764f1d3d..141455452809 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -119,10 +119,12 @@ namespace drawingml {
// not thread safe
int DrawingML::mnImageCounter = 1;
+int DrawingML::mnWdpImageCounter = 1;
void DrawingML::ResetCounters()
{
mnImageCounter = 1;
+ mnWdpImageCounter = 1;
}
bool DrawingML::GetProperty( Reference< XPropertySet > rXPropSet, const OUString& aName )
@@ -2590,6 +2592,7 @@ void DrawingML::WriteArtisticEffect( Reference< XPropertySet > rXPropSet )
Sequence< PropertyValue > aAttrs;
aEffect.Value >>= aAttrs;
sax_fastparser::FastAttributeList *aAttrList = mpFS->createAttrList();
+ OString sRelId;
for( sal_Int32 i=0; i < aAttrs.getLength(); ++i )
{
sal_Int32 nToken = ArtisticEffectProperties::getEffectToken( aAttrs[i].Name );
@@ -2599,6 +2602,12 @@ void DrawingML::WriteArtisticEffect( Reference< XPropertySet > rXPropSet )
aAttrs[i].Value >>= nVal;
aAttrList->add( nToken, OString::number( nVal ).getStr() );
}
+ else if( aAttrs[i].Name == "OriginalGraphic" )
+ {
+ Sequence< sal_Int8 > aGraphicData;
+ aAttrs[i].Value >>= aGraphicData;
+ sRelId = WriteWdpPicture( aGraphicData );
+ }
}
mpFS->startElementNS( XML_a, XML_extLst, FSEND );
@@ -2608,7 +2617,9 @@ void DrawingML::WriteArtisticEffect( Reference< XPropertySet > rXPropSet )
mpFS->startElementNS( XML_a14, XML_imgProps,
FSNS( XML_xmlns, XML_a14 ), "http://schemas.microsoft.com/office/drawing/2010/main",
FSEND );
- mpFS->startElementNS( XML_a14, XML_imgLayer, FSEND );
+ mpFS->startElementNS( XML_a14, XML_imgLayer,
+ FSNS( XML_r, XML_embed), sRelId.getStr(),
+ FSEND );
mpFS->startElementNS( XML_a14, XML_imgEffect, FSEND );
sax_fastparser::XFastAttributeListRef xAttrList( aAttrList );
@@ -2621,6 +2632,23 @@ void DrawingML::WriteArtisticEffect( Reference< XPropertySet > rXPropSet )
mpFS->endElementNS( XML_a, XML_extLst );
}
+OString DrawingML::WriteWdpPicture( const Sequence< sal_Int8 >& rPictureData )
+{
+ OUString sFileName = "media/hdphoto" + OUString::number( mnWdpImageCounter++ ) + ".wdp";
+ uno::Reference< io::XOutputStream > xOutStream =
+ mpFB->openFragmentStream( "word/" + sFileName,
+ "image/vnd.ms-photo" );
+ OUString sId;
+ xOutStream->writeBytes( rPictureData );
+ xOutStream->closeOutput();
+
+ sId = mpFB->addRelation( mpFS->getOutputStream(),
+ "http://schemas.microsoft.com/office/2007/relationships/hdphoto",
+ sFileName, false );
+
+ return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
+}
+
}
}
diff --git a/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
index 43f5b6e7751d..0284347daa86 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
@@ -1341,9 +1341,13 @@ DECLARE_OOXMLEXPORT_TEST(testPictureEffectPreservation, "picture-effects-preserv
DECLARE_OOXMLEXPORT_TEST(testPictureArtisticEffectPreservation, "picture-artistic-effects-preservation.docx")
{
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
- if (!pXmlDoc)
+ xmlDocPtr pRelsDoc = parseExport("word/_rels/document.xml.rels");
+ if (!pXmlDoc || !pRelsDoc)
return;
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(
+ comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL());
+
// 1st picture: marker effect
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
@@ -1354,6 +1358,13 @@ DECLARE_OOXMLEXPORT_TEST(testPictureArtisticEffectPreservation, "picture-artisti
"a14:artisticMarker",
"size", "80");
+ OUString sEmbedId1 = getXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ OUString sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId1 + "']";
+ OUString sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
+
// 2nd picture: pencil grayscale
assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
@@ -1364,6 +1375,13 @@ DECLARE_OOXMLEXPORT_TEST(testPictureArtisticEffectPreservation, "picture-artisti
"a14:artisticPencilGrayscale",
"pencilSize", "66");
+ OUString sEmbedId2 = getXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId2 + "']";
+ sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
+
// 3rd picture: pencil sketch
assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
@@ -1374,6 +1392,13 @@ DECLARE_OOXMLEXPORT_TEST(testPictureArtisticEffectPreservation, "picture-artisti
"a14:artisticPencilSketch",
"pressure", "17");
+ OUString sEmbedId3 = getXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId3 + "']";
+ sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
+
// 4th picture: light screen
assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
@@ -1384,16 +1409,37 @@ DECLARE_OOXMLEXPORT_TEST(testPictureArtisticEffectPreservation, "picture-artisti
"a14:artisticLightScreen",
"gridSize", "1");
+ OUString sEmbedId4 = getXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId4 + "']";
+ sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
+
// 5th picture: watercolor sponge
assertXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
"a14:artisticWatercolorSponge",
"brushSize", "4");
+ OUString sEmbedId5 = getXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId5 + "']";
+ sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
+
// 6th picture: photocopy (no attributes)
assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:inline/a:graphic/"
"a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer/a14:imgEffect/"
"a14:artisticPhotocopy", 1);
+
+ OUString sEmbedId6 = getXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
+ "wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/a:extLst/a:ext/a14:imgProps/a14:imgLayer",
+ "embed");
+ sXmlPath = "/rels:Relationships/rels:Relationship[@Id='" + sEmbedId6 + "']";
+ sFile = getXPath(pRelsDoc, OUStringToOString( sXmlPath, RTL_TEXTENCODING_UTF8 ), "Target");
+ CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/" + sFile)));
}
DECLARE_OOXMLEXPORT_TEST(fdo77719, "fdo77719.docx")