1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/embed/XEmbedPersist.hpp>
22 #include <com/sun/star/embed/Aspects.hpp>
23 #include <com/sun/star/embed/ElementModes.hpp>
24 #include <sal/log.hxx>
25 #include <vcl/graphicfilter.hxx>
26 #include <vcl/gdimtf.hxx>
27 #include <svl/itemiter.hxx>
28 #include <tools/UnitConversion.hxx>
30 #include <svtools/embedhlp.hxx>
32 #include <hintids.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/shaditem.hxx>
35 #include <filter/msfilter/msoleexp.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <svx/svdoole2.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <fmtanchr.hxx>
45 #include <fmtfsize.hxx>
46 #include <fmtornt.hxx>
48 #include "sprmids.hxx"
51 #include "writerhelper.hxx"
52 #include "writerwordglue.hxx"
53 #include "ww8struc.hxx"
58 #include "ww8attributeoutput.hxx"
61 #include <IDocumentDrawModelAccess.hxx>
62 #include <drawdoc.hxx>
63 #include <o3tl/string_view.hxx>
65 using namespace ::com::sun::star
;
68 // 5. convert the MapModes that Widows can't handle
70 // OutGrf () is called for every GrfNode in the document. A PicLocFc-Sprm
71 // will be inserted, which contains a magic number instead of an address.
72 // The GrfNode-Ptr is saved in Graf-Class (used later for output of
73 // the graphic and patching of the PicLocFc attributes)
75 void WW8Export::OutputGrfNode( const SwGrfNode
& /*rNode*/ )
77 SAL_INFO("sw", "WW8Export::OutputGrfNode( const SwGrfNode& )" );
78 OSL_ENSURE( m_pParentFrame
, "frame not set!" );
81 OutGrf( *m_pParentFrame
);
82 m_pFib
->m_fHasPic
= true;
86 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet
& rSet
, tools::SvRef
<SotStorage
> const& xOleStg
,
87 const tools::SvRef
<SotStorage
>& xObjStg
,
88 OUString
const& rStorageName
, SwOLENode
* pOLENd
)
90 bool bGraphicNeeded
= false;
91 SfxItemIter
aIter( rSet
);
92 for (auto pItem
= aIter
.GetCurItem(); !bGraphicNeeded
&& pItem
; pItem
= aIter
.NextItem())
94 switch (pItem
->Which())
97 For an inline object these properties are irrelevant because they
98 will be the same as the defaults that msword applies in their
99 absence, so if that is all that there is for these inline objects
100 then if there turns out to be enough information in the object
101 itself to regenerate the correct size and preview of the object
102 then we will not need to provide an additional graphics preview in
103 the data stream, which can save a lot of disk space.
107 case RES_VERT_ORIENT
:
111 bGraphicNeeded
= true;
116 Now we must see if the object contains a preview itself which is equal to
117 the preview that we are currently using. If the graphics are equal then we
118 don't need to store another preview
121 tools::Long nX
=0,nY
=0;
122 if (!bGraphicNeeded
&& SwWW8ImplReader::ImportOleWMF(xOleStg
,aWMF
,nX
,nY
))
124 // bGraphicNeeded set to true is right / fixes #i51670#.
125 bGraphicNeeded
= true;
126 tools::Rectangle
aRect( Point(), Size( nX
, nY
) );
127 Graphic
aGraph(aWMF
);
129 ErrCode nErr
= ERRCODE_NONE
;
130 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
132 nAspect
= pOLENd
->GetAspect();
133 rtl::Reference
<SdrOle2Obj
> pRet
= SvxMSDffManager::CreateSdrOLEFromStorage(
134 *m_rDoc
.getIDocumentDrawModelAccess().GetOrCreateDrawModel(),
137 m_rDoc
.GetDocStorage(),
145 m_pWriter
->GetBaseURL());
149 uno::Reference
< embed::XEmbeddedObject
> xObj
= pOLENd
->GetOLEObj().GetOleRef();
152 std::unique_ptr
<SvStream
> pGraphicStream
;
153 comphelper::EmbeddedObjectContainer
aCnt( m_rDoc
.GetDocStorage() );
156 uno::Reference
< embed::XEmbedPersist
> xPersist(
158 uno::UNO_QUERY_THROW
);
160 // it makes no sense to search the object in the container by reference since the object was created
161 // outside of the container and was not inserted there, only the name makes sense
163 ::utl::UcbStreamHelper::CreateStream( aCnt
.GetGraphicStream( xPersist
->getEntryName() ) );
165 catch( const uno::Exception
& )
168 OSL_ENSURE( pGraphicStream
&& !pGraphicStream
->GetError(), "No graphic stream available!" );
169 if ( pGraphicStream
&& !pGraphicStream
->GetError() )
172 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
173 if( rGF
.ImportGraphic( aGr1
, u
"", *pGraphicStream
) == ERRCODE_NONE
)
177 ::utl::UcbStreamHelper::CreateStream( aCnt
.GetGraphicStream( pRet
->GetObjRef() ) );
178 if( pGraphicStream
&& rGF
.ImportGraphic( aGr2
, u
"", *pGraphicStream
) == ERRCODE_NONE
)
181 bGraphicNeeded
= false;
189 bGraphicNeeded
= true;
190 return bGraphicNeeded
;
193 void WW8Export::OutputOLENode( const SwOLENode
& rOLENode
)
195 SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
199 static sal_uInt8 aSpecOLE_WW8
[] = {
200 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
201 0x0a, 0x08, 1, // sprmCFOLE2
202 0x56, 0x08, 1 // sprmCFObj
205 pSpecOLE
= aSpecOLE_WW8
;
206 nSize
= sizeof( aSpecOLE_WW8
);
207 pDataAdr
= pSpecOLE
+ 2; //WW6 sprm is 1 but has 1 byte len as well.
209 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
214 uno::Reference
< embed::XEmbeddedObject
> xObj(const_cast<SwOLENode
&>(rOLENode
).GetOLEObj().GetOleRef());
218 const embed::XEmbeddedObject
*pObj
= xObj
.get();
219 //Don't want to use pointer ids, as is traditional, because we need
220 //to put this into a 32bit value, and on 64bit the bottom bits
221 //might collide and two unrelated ole objects end up considered the
222 //same. Don't want to simply start at 0 which is a special value
223 sal_Int32 nPictureId
= SAL_MAX_INT32
- m_aOleMap
.size();
224 WW8OleMap::value_type entry
= std::make_pair(pObj
, nPictureId
);
225 std::pair
<WW8OleMap::iterator
, bool> aRes
= m_aOleMap
.insert(entry
);
226 bool bIsNotDuplicate
= aRes
.second
; //.second is false when element already existed
227 nPictureId
= aRes
.first
->second
;
228 Set_UInt32(pDataAdr
, nPictureId
);
229 OUString sStorageName
= "_" + OUString::number( nPictureId
);
230 tools::SvRef
<SotStorage
> xOleStg
= xObjStg
->OpenSotStorage( sStorageName
);
235 If this object storage has been written already don't
236 waste time rewriting it
240 sal_Int64 nAspect
= rOLENode
.GetAspect();
241 svt::EmbeddedObjectRef
aObjRef( xObj
, nAspect
);
242 m_oOLEExp
->ExportOLEObject( aObjRef
, *xOleStg
);
243 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
245 OUString
aObjInfo( "\3ObjInfo" );
246 if ( !xOleStg
->IsStream( aObjInfo
) )
248 const sal_uInt8 pObjInfoData
[] = { 0x40, 0x00, 0x03, 0x00 };
249 tools::SvRef
<SotStorageStream
> rObjInfoStream
= xOleStg
->OpenSotStream( aObjInfo
);
250 if ( rObjInfoStream
.is() && !rObjInfoStream
->GetError() )
252 rObjInfoStream
->WriteBytes(pObjInfoData
, sizeof(pObjInfoData
));
259 // write as embedded field - the other things will be done
260 // in the escher export
261 OUString sServer
= FieldString(ww::eEMBED
) + xOleStg
->GetUserName() + " ";
263 OutputField(nullptr, ww::eEMBED
, sServer
, FieldFlags::Start
|
264 FieldFlags::CmdStart
| FieldFlags::CmdEnd
);
266 m_pChpPlc
->AppendFkpEntry( Strm().Tell(),
271 In the word filter we only need a preview image for
272 floating images, and then only (the usual case) if the
273 object doesn't contain enough information to reconstruct
276 We don't need a graphic for inline objects, so we don't
277 even need the overhead of a graphic in that case.
279 bool bGraphicNeeded
= false;
283 bGraphicNeeded
= true;
285 if (m_pParentFrame
->IsInline())
287 const SwAttrSet
& rSet
=
288 m_pParentFrame
->GetFrameFormat().GetAttrSet();
290 bGraphicNeeded
= TestOleNeedsGraphic(rSet
,
291 xOleStg
, xObjStg
, sStorageName
, const_cast<SwOLENode
*>(&rOLENode
));
301 We need to insert the graphic representation of
302 this object for the inline case, otherwise word
303 has no place to find the dimensions of the ole
304 object, and will not be able to draw it
306 OutGrf(*m_pParentFrame
);
309 OutputField(nullptr, ww::eEMBED
, OUString(),
310 FieldFlags::End
| FieldFlags::Close
);
312 if (bEndCR
) //No newline in inline case
316 void WW8Export::OutputLinkedOLE( const OUString
& rOleId
)
318 uno::Reference
< embed::XStorage
> xDocStg
= m_rDoc
.GetDocStorage();
319 uno::Reference
< embed::XStorage
> xOleStg
= xDocStg
->openStorageElement( "OLELinks", embed::ElementModes::READ
);
320 tools::SvRef
<SotStorage
> xObjSrc
= SotStorage::OpenOLEStorage( xOleStg
, rOleId
, StreamMode::READ
);
322 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
324 if( !(xObjStg
.is() && xObjSrc
.is()) )
327 tools::SvRef
<SotStorage
> xOleDst
= xObjStg
->OpenSotStorage( rOleId
);
329 xObjSrc
->CopyTo( xOleDst
.get() );
331 if ( xOleDst
->GetError( ) )
336 // Output the cPicLocation attribute
337 std::unique_ptr
<ww::bytes
> pBuf( new ww::bytes
);
338 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CPicLocation::val
);
339 SwWW8Writer::InsUInt32( *pBuf
, o3tl::toInt32(rOleId
.subView( 1 )) );
341 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFOle2::val
);
342 pBuf
->push_back( 1 );
344 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFSpec::val
);
345 pBuf
->push_back( 1 );
347 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFObj::val
);
348 pBuf
->push_back( 1 );
350 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pBuf
->size(), pBuf
->data() );
353 void WW8Export::OutGrf(const ww8::Frame
&rFrame
)
355 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
356 //will be exported to ensure the fidelity
357 const SwFormatURL
& rURL
= rFrame
.GetFrameFormat().GetAttrSet().GetURL();
358 bool bURLStarted
= false;
359 if( !rURL
.GetURL().isEmpty() && rFrame
.GetWriterType() == ww8::Frame::eGraphic
)
362 m_pAttrOutput
->StartURL( rURL
.GetURL(), rURL
.GetTargetFrameName() );
365 // Store the graphic settings in GrfNode so they may be written-out later
366 m_pGrf
->Insert(rFrame
);
368 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), m_pO
->size(), m_pO
->data() );
372 // linked, as-character anchored graphics have to be exported as fields.
373 const SwGrfNode
* pGrfNd
= rFrame
.IsInline() && rFrame
.GetContent()
374 ? rFrame
.GetContent()->GetGrfNode() : nullptr;
375 if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
378 pGrfNd
->GetFileFilterNms(&sStr
, nullptr);
379 sStr
= FieldString(ww::eINCLUDEPICTURE
) + " \"" + sStr
+ "\" \\d";
381 OutputField( nullptr, ww::eINCLUDEPICTURE
, sStr
,
382 FieldFlags::Start
| FieldFlags::CmdStart
| FieldFlags::CmdEnd
);
385 WriteChar( char(1) ); // paste graphic symbols in the main text
387 sal_uInt8 aArr
[ 18 ];
388 sal_uInt8
* pArr
= aArr
;
390 const SwFrameFormat
&rFlyFormat
= rFrame
.GetFrameFormat();
391 const RndStdIds eAn
= rFlyFormat
.GetAttrSet().GetAnchor(false).GetAnchorId();
392 if (eAn
== RndStdIds::FLY_AS_CHAR
)
394 sal_Int16 eVert
= rFlyFormat
.GetVertOrient().GetVertOrient();
395 if ((eVert
== text::VertOrientation::CHAR_CENTER
) || (eVert
== text::VertOrientation::LINE_CENTER
))
398 //The default for word in vertical text mode is to center,
399 //otherwise a sub/super script hack is employed
400 if (auto pTextNd
= dynamic_cast< const SwContentNode
*>( m_pOutFormatNode
) )
402 SwPosition
aPos(*pTextNd
);
403 bVert
= m_rDoc
.IsInVerticalText(aPos
);
407 SwTwips nHeight
= rFlyFormat
.GetFrameSize().GetHeight();
408 nHeight
/=20; //nHeight was in twips, want it in half points, but
409 //then half of total height.
410 tools::Long nFontHeight
= GetItem(RES_CHRATR_FONTSIZE
).GetHeight();
411 nHeight
-=nFontHeight
/20;
413 Set_UInt16( pArr
, NS_sprm::CHpsPos::val
);
414 Set_UInt16( pArr
, - static_cast<sal_Int16
>(nHeight
));
420 Set_UInt16( pArr
, 0x855 );
421 Set_UInt8( pArr
, 1 );
424 Set_UInt16( pArr
, NS_sprm::CPicLocation::val
);
425 Set_UInt32( pArr
, GRF_MAGIC_321
);
427 // vary Magic, so that different graphic attributes will not be merged
428 static sal_uInt8 nAttrMagicIdx
= 0;
430 Set_UInt8( pArr
, nAttrMagicIdx
++ );
431 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
434 // Check, if graphic isn't exported as-character anchored.
435 // Otherwise, an additional paragraph is exported for a graphic, which is
436 // forced to be treated as inline, because it's anchored inside another frame.
437 if ( !rFrame
.IsInline() &&
438 ( (eAn
== RndStdIds::FLY_AT_PARA
) ||
439 (eAn
== RndStdIds::FLY_AT_PAGE
) ) )
441 WriteChar( char(0x0d) ); // close the surrounding frame with CR
443 static sal_uInt8 nSty
[2] = { 0, 0 };
444 m_pO
->insert( m_pO
->end(), nSty
, nSty
+2 ); // Style #0
445 bool bOldGrf
= m_bOutGrf
;
448 OutputFormat( rFrame
.GetFrameFormat(), false, false, true ); // Fly-Attrs
451 m_pPapPlc
->AppendFkpEntry( Strm().Tell(), m_pO
->size(), m_pO
->data() );
455 // linked, as-character anchored graphics have to be exported as fields.
456 else if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
458 OutputField( nullptr, ww::eINCLUDEPICTURE
, OUString(), FieldFlags::Close
);
460 //Added for i120568,the hyperlink info within a graphic whose anchor type is
461 //"As character" will be exported to ensure the fidelity
463 m_pAttrOutput
->EndURL(false);
466 void SwWW8WrGrf::Insert(const ww8::Frame
&rFly
)
468 const Size
aSize( rFly
.GetLayoutSize() );
469 const sal_uInt16 nWidth
= static_cast< sal_uInt16
>(aSize
.Width());
470 const sal_uInt16 nHeight
= static_cast< sal_uInt16
>(aSize
.Height());
471 maDetails
.emplace_back(rFly
, nWidth
, nHeight
);
474 void SwWW8WrGrf::WritePICFHeader(SvStream
& rStrm
, const ww8::Frame
&rFly
,
475 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
, const SwAttrSet
* pAttrSet
)
477 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
478 sal_Int16 nCropL
= 0, nCropR
= 0, nCropT
= 0, nCropB
= 0;
480 // write Crop-Attribute content in Header ( if available )
481 const SwCropGrf
* pCropItem
;
482 if (pAttrSet
&& (pCropItem
483 = pAttrSet
->GetItemIfSet(RES_GRFATR_CROPGRF
, false)))
485 nCropL
= static_cast<sal_Int16
>(pCropItem
->GetLeft());
486 nCropR
= static_cast<sal_Int16
>(pCropItem
->GetRight());
487 nCropT
= static_cast<sal_Int16
>(pCropItem
->GetTop());
488 nCropB
= static_cast<sal_Int16
>(pCropItem
->GetBottom());
489 nXSizeAdd
= nXSizeAdd
- static_cast<sal_Int16
>( pCropItem
->GetLeft() + pCropItem
->GetRight() );
490 nYSizeAdd
= nYSizeAdd
- static_cast<sal_Int16
>( pCropItem
->GetTop() + pCropItem
->GetBottom() );
493 Size
aGrTwipSz(rFly
.GetSize());
494 sal_uInt16 nHdrLen
= 0x44;
496 sal_uInt8 aArr
[ 0x44 ] = { 0 };
498 sal_uInt8
* pArr
= aArr
+ 0x2E; // Do borders first
500 const SwAttrSet
& rAttrSet
= rFly
.GetFrameFormat().GetAttrSet();
501 if (const SvxBoxItem
* pBox
= rAttrSet
.GetItemIfSet(RES_BOX
, false))
503 bool bShadow
= false; // Shadow ?
504 if (const SvxShadowItem
* pSI
= rAttrSet
.GetItem
<SvxShadowItem
>(RES_SHADOW
))
506 bShadow
= (pSI
->GetLocation() != SvxShadowLocation::NONE
) &&
507 (pSI
->GetWidth() != 0);
510 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
511 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
512 for(const SvxBoxItemLine
& i
: aLnArr
)
514 const ::editeng::SvxBorderLine
* pLn
= pBox
->GetLine( i
);
518 WW8_BRCVer9 aBrc90
= WW8Export::TranslateBorderLine( *pLn
,
519 pBox
->GetDistance( i
), bShadow
);
520 sal_uInt8 ico
= msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
522 aBrc
= WW8_BRC(aBrc90
.dptLineWidth(), aBrc90
.brcType(), ico
,
523 aBrc90
.dptSpace(), aBrc90
.fShadow(), aBrc90
.fFrame());
526 // use importer logic to determine how large the exported
527 // border will really be in word and adjust accordingly
529 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
532 case SvxBoxItemLine::TOP
:
533 case SvxBoxItemLine::BOTTOM
:
534 nHeight
-= bShadow
? nThick
*2 : nThick
;
535 nHeight
= nHeight
- nSpacing
;
537 case SvxBoxItemLine::LEFT
:
538 case SvxBoxItemLine::RIGHT
:
540 nWidth
-= bShadow
? nThick
*2 : nThick
;
541 nWidth
= nWidth
- nSpacing
;
544 memcpy( pArr
, &aBrc
.aBits1
, 2);
547 memcpy( pArr
, &aBrc
.aBits2
, 2);
552 pArr
= aArr
+ 4; // skip lcb
553 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
555 Set_UInt16( pArr
, mm
); // set mm
558 Just in case our original size is too big to fit inside a ushort we can
559 substitute the final size and lose on retaining the scaling factor but
560 still keep the correct display size anyway.
562 const bool bIsSubstitutedSize
= (aGrTwipSz
.Width() > SHRT_MAX
) || (aGrTwipSz
.Height() > SHRT_MAX
) ||
564 if ( bIsSubstitutedSize
)
566 aGrTwipSz
.setWidth( nWidth
);
567 aGrTwipSz
.setHeight( nHeight
);
569 using namespace sw::types
;
571 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Width())));
572 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Height())));
574 // skip hMF & rcWinMF
575 // set dxaGoal & dyaGoal
576 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
577 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
579 if ( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
581 if ( !bIsSubstitutedSize
)
583 const double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
584 Set_UInt16( pArr
, o3tl::narrowing
<sal_uInt16
>(::rtl::math::round(fVal
)) );
588 Set_UInt16( pArr
, 1000 );
596 if ( aGrTwipSz
.Height() + nYSizeAdd
) // set my
598 if ( !bIsSubstitutedSize
)
600 const double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
601 Set_UInt16( pArr
, o3tl::narrowing
<sal_uInt16
>(::rtl::math::round(fVal
)) );
605 Set_UInt16( pArr
, 1000 );
613 if ( !bIsSubstitutedSize
)
615 Set_UInt16( pArr
, nCropL
); // set dxaCropLeft
616 Set_UInt16( pArr
, nCropT
); // set dyaCropTop
617 Set_UInt16( pArr
, nCropR
); // set dxaCropRight
618 Set_UInt16( pArr
, nCropB
); // set dyaCropBottom
621 rStrm
.WriteBytes(aArr
, nHdrLen
);
624 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream
& rStrm
, const SwGrfNode
&rGrfNd
,
625 const ww8::Frame
&rFly
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
627 if (rGrfNd
.IsLinkedFile()) // Linked File
630 rGrfNd
.GetFileFilterNms( &aFileN
, nullptr );
632 sal_uInt16
const mm
= 94; // 94 = BMP, GIF
634 WritePICFHeader(rStrm
, rFly
, mm
, nWidth
, nHeight
,
635 rGrfNd
.GetpSwAttrSet());
636 rStrm
.WriteUChar( aFileN
.getLength() ); // write Pascal-String
637 SwWW8Writer::WriteString8(rStrm
, aFileN
, false,
638 RTL_TEXTENCODING_MS_1252
);
640 else // Embedded File or DDE or something like that
642 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
643 rGrfNd
.GetpSwAttrSet());
644 SwBasicEscherEx
aInlineEscher(&rStrm
, m_rWrt
);
645 aInlineEscher
.WriteGrfFlyFrame(rFly
.GetFrameFormat(), 0x401);
646 aInlineEscher
.WritePictures();
649 //For i120928,export graphic info of bullet
650 void SwWW8WrGrf::WritePICBulletFHeader(SvStream
& rStrm
, const Graphic
&rGrf
,
651 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
653 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
655 Size
aGrTwipSz(rGrf
.GetPrefSize());
656 sal_uInt16 nHdrLen
= 0x44;
658 sal_uInt8 aArr
[ 0x44 ] = { 0 };
660 sal_uInt8
* pArr
= aArr
+ 0x2E; //Do borders first
662 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
663 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
664 for(const SvxBoxItemLine
& i
: aLnArr
)
669 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
672 case SvxBoxItemLine::TOP
:
673 case SvxBoxItemLine::BOTTOM
:
675 nHeight
= nHeight
- nSpacing
;
677 case SvxBoxItemLine::LEFT
:
678 case SvxBoxItemLine::RIGHT
:
681 nWidth
= nWidth
- nSpacing
;
684 memcpy( pArr
, &aBrc
.aBits1
, 2);
687 memcpy(pArr
, &aBrc
.aBits2
, 2);
691 pArr
= aArr
+ 4; //skip lcb
692 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
694 Set_UInt16( pArr
, mm
); // set mm
696 if ( (convertTwipToMm100(aGrTwipSz
.Width()) > USHRT_MAX
) || ( convertTwipToMm100(aGrTwipSz
.Height()) > USHRT_MAX
)
697 || aGrTwipSz
.IsEmpty() )
699 aGrTwipSz
.setWidth( nWidth
);
700 aGrTwipSz
.setHeight( nHeight
);
702 using namespace sw::types
;
704 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Width())));
705 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Height())));
707 // skip hMF & rcWinMF
708 // set dxaGoal & dyaGoal
709 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
710 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
712 if( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
714 double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
715 Set_UInt16( pArr
, o3tl::narrowing
<sal_uInt16
>(::rtl::math::round(fVal
)) );
720 if( aGrTwipSz
.Height() + nYSizeAdd
) // set my
722 double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
723 Set_UInt16( pArr
, o3tl::narrowing
<sal_uInt16
>(::rtl::math::round(fVal
)) );
728 Set_UInt16( pArr
, 0 ); // set dxaCropLeft
729 Set_UInt16( pArr
, 0 ); // set dyaCropTop
730 Set_UInt16( pArr
, 0 ); // set dxaCropRight
731 Set_UInt16( pArr
, 0 ); // set dyaCropBottom
733 rStrm
.WriteBytes(aArr
, nHdrLen
);
736 void SwWW8WrGrf::WriteGrfForBullet(SvStream
& rStrm
, const Graphic
&rGrf
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
738 WritePICBulletFHeader(rStrm
,rGrf
, 0x64,nWidth
,nHeight
);
739 SwBasicEscherEx
aInlineEscher(&rStrm
, m_rWrt
);
740 aInlineEscher
.WriteGrfBullet(rGrf
);
741 aInlineEscher
.WritePictures();
744 void SwWW8WrGrf::WriteGraphicNode(SvStream
& rStrm
, const GraphicDetails
&rItem
)
746 sal_uInt16 nWidth
= rItem
.mnWid
;
747 sal_uInt16 nHeight
= rItem
.mnHei
;
748 sal_uInt32 nPos
= rStrm
.Tell(); // store start of graphic
750 const ww8::Frame
&rFly
= rItem
.maFly
;
751 switch (rFly
.GetWriterType())
753 case ww8::Frame::eGraphic
:
755 const SwNode
*pNode
= rItem
.maFly
.GetContent();
756 const SwGrfNode
*pNd
= pNode
? pNode
->GetGrfNode() : nullptr;
757 OSL_ENSURE(pNd
, "Impossible");
759 WriteGrfFromGrfNode(rStrm
, *pNd
, rItem
.maFly
, nWidth
, nHeight
);
762 //For i120928,add branch to export graphic of bullet
763 case ww8::Frame::eBulletGrf
:
765 if (rItem
.maFly
.HasGraphic())
767 const Graphic
& rGrf
= rItem
.maFly
.GetGraphic();
768 WriteGrfForBullet(rStrm
, rGrf
, nWidth
, nHeight
);
773 case ww8::Frame::eOle
:
775 const SwNode
*pNode
= rItem
.maFly
.GetContent();
776 const SwOLENode
*pNd
= pNode
? pNode
->GetOLENode() : nullptr;
777 OSL_ENSURE(pNd
, "Impossible");
780 #ifdef OLE_PREVIEW_AS_EMF
781 //Convert this ole2 preview in ww8+ to an EMF for better unicode
782 //support (note that at this moment this breaks StarSymbol
783 //using graphics because I need to embed starsymbol in exported
785 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
786 pNd
->GetpSwAttrSet());
787 SwBasicEscherEx
aInlineEscher(&rStrm
, m_rWrt
);
788 aInlineEscher
.WriteOLEFlyFrame(rFly
.GetFrameFormat(), 0x401);
789 aInlineEscher
.WritePictures();
792 SwOLENode
*pOleNd
= const_cast<SwOLENode
*>(pNd
);
793 SwOLEObj
& rSObj
= pOleNd
->GetOLEObj();
795 // TODO/LATER: do we need to load object?
796 Graphic
* pGr
= SdrOle2Obj::GetGraphicFromObject( pOleNd
->GetDoc()->GetDocStorage(), rObj
);
798 //TODO/LATER: do we really want to use GDIMetafile?!
801 aMtf
= pGr
->GetGDIMetaFile();
803 Size
aS(aMtf
.GetPrefSize());
805 aMtf
.Play(Application::GetDefaultDevice(), Point(0, 0),
808 WritePICFHeader(rStrm
, rFly
, 8, nWidth
, nHeight
,
809 pNd
->GetpSwAttrSet());
810 WriteWindowMetafileBits(rStrm
, aMtf
);
816 case ww8::Frame::eDrawing
:
817 case ww8::Frame::eTextBox
:
818 case ww8::Frame::eFormControl
:
820 #i3958# We only export an empty dummy picture frame here, this is
821 what word does the escher export should contain an anchored to
822 character element which is drawn over this dummy and the whole
823 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
827 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
);
828 SwBasicEscherEx
aInlineEscher(&rStrm
, m_rWrt
);
829 aInlineEscher
.WriteEmptyFlyFrame(rFly
.GetFrameFormat(), 0x401);
833 OSL_ENSURE(false, "Some inline export not implemented");
837 sal_uInt32 nPos2
= rStrm
.Tell(); // store the end
839 rStrm
.WriteUInt32(nPos2
- nPos
); // patch graphic length in the header
840 rStrm
.Seek( nPos2
); // restore Pos
843 // SwWW8WrGrf::Write() is called after the text.
844 // It writes out all the graphics and remembers the file locations of the graphics,
845 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
846 // The search in the attributes for the Magic sal_uLong and patching
847 // happens when writing the attributes. Class SwWW8WrGrf provides with
848 // GetFPos() sequentially the positions
849 void SwWW8WrGrf::Write()
851 SvStream
& rStrm
= *m_rWrt
.m_pDataStrm
;
852 auto aEnd
= maDetails
.end();
853 for (auto aIter
= maDetails
.begin(); aIter
!= aEnd
; ++aIter
)
855 sal_uInt32 nPos
= rStrm
.Tell(); // align to 4 Bytes
857 SwWW8Writer::FillCount( rStrm
, 4 - ( nPos
& 0x3 ) );
859 auto aIter2
= std::find(maDetails
.begin(), aIter
, *aIter
);
862 aIter
->mnPos
= aIter2
->mnPos
;
866 aIter
->mnPos
= rStrm
.Tell();
867 WriteGraphicNode(rStrm
, *aIter
);
872 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */