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>
46 #include <fmtfsize.hxx>
47 #include <fmtornt.hxx>
49 #include "sprmids.hxx"
52 #include "writerhelper.hxx"
53 #include "writerwordglue.hxx"
54 #include "ww8struc.hxx"
59 #include "ww8attributeoutput.hxx"
62 #include <IDocumentDrawModelAccess.hxx>
63 #include <drawdoc.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 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 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
, OUString(), *pGraphicStream
) == ERRCODE_NONE
)
177 ::utl::UcbStreamHelper::CreateStream( aCnt
.GetGraphicStream( pRet
->GetObjRef() ) );
178 if( pGraphicStream
&& rGF
.ImportGraphic( aGr2
, OUString(), *pGraphicStream
) == ERRCODE_NONE
)
181 bGraphicNeeded
= false;
187 // always use SdrObject::Free(...) for SdrObjects (!)
188 SdrObject
* pTemp(pRet
);
189 SdrObject::Free(pTemp
);
193 bGraphicNeeded
= true;
194 return bGraphicNeeded
;
197 void WW8Export::OutputOLENode( const SwOLENode
& rOLENode
)
199 SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
203 static sal_uInt8 aSpecOLE_WW8
[] = {
204 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
205 0x0a, 0x08, 1, // sprmCFOLE2
206 0x56, 0x08, 1 // sprmCFObj
209 pSpecOLE
= aSpecOLE_WW8
;
210 nSize
= sizeof( aSpecOLE_WW8
);
211 pDataAdr
= pSpecOLE
+ 2; //WW6 sprm is 1 but has 1 byte len as well.
213 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
218 uno::Reference
< embed::XEmbeddedObject
> xObj(const_cast<SwOLENode
&>(rOLENode
).GetOLEObj().GetOleRef());
222 const embed::XEmbeddedObject
*pObj
= xObj
.get();
223 //Don't want to use pointer ids, as is traditional, because we need
224 //to put this into a 32bit value, and on 64bit the bottom bits
225 //might collide and two unrelated ole objects end up considered the
226 //same. Don't want to simply start at 0 which is a special value
227 sal_Int32 nPictureId
= SAL_MAX_INT32
- m_aOleMap
.size();
228 WW8OleMap::value_type entry
= std::make_pair(pObj
, nPictureId
);
229 std::pair
<WW8OleMap::iterator
, bool> aRes
= m_aOleMap
.insert(entry
);
230 bool bIsNotDuplicate
= aRes
.second
; //.second is false when element already existed
231 nPictureId
= aRes
.first
->second
;
232 Set_UInt32(pDataAdr
, nPictureId
);
233 OUString sStorageName
= "_" + OUString::number( nPictureId
);
234 tools::SvRef
<SotStorage
> xOleStg
= xObjStg
->OpenSotStorage( sStorageName
);
239 If this object storage has been written already don't
240 waste time rewriting it
244 sal_Int64 nAspect
= rOLENode
.GetAspect();
245 svt::EmbeddedObjectRef
aObjRef( xObj
, nAspect
);
246 m_pOLEExp
->ExportOLEObject( aObjRef
, *xOleStg
);
247 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
249 OUString
aObjInfo( "\3ObjInfo" );
250 if ( !xOleStg
->IsStream( aObjInfo
) )
252 const sal_uInt8 pObjInfoData
[] = { 0x40, 0x00, 0x03, 0x00 };
253 tools::SvRef
<SotStorageStream
> rObjInfoStream
= xOleStg
->OpenSotStream( aObjInfo
);
254 if ( rObjInfoStream
.is() && !rObjInfoStream
->GetError() )
256 rObjInfoStream
->WriteBytes(pObjInfoData
, sizeof(pObjInfoData
));
263 // write as embedded field - the other things will be done
264 // in the escher export
265 OUString sServer
= FieldString(ww::eEMBED
) + xOleStg
->GetUserName() + " ";
267 OutputField(nullptr, ww::eEMBED
, sServer
, FieldFlags::Start
|
268 FieldFlags::CmdStart
| FieldFlags::CmdEnd
);
270 m_pChpPlc
->AppendFkpEntry( Strm().Tell(),
275 In the word filter we only need a preview image for
276 floating images, and then only (the usual case) if the
277 object doesn't contain enough information to reconstruct
280 We don't need a graphic for inline objects, so we don't
281 even need the overhead of a graphic in that case.
283 bool bGraphicNeeded
= false;
287 bGraphicNeeded
= true;
289 if (m_pParentFrame
->IsInline())
291 const SwAttrSet
& rSet
=
292 m_pParentFrame
->GetFrameFormat().GetAttrSet();
294 bGraphicNeeded
= TestOleNeedsGraphic(rSet
,
295 xOleStg
, xObjStg
, sStorageName
, const_cast<SwOLENode
*>(&rOLENode
));
305 We need to insert the graphic representation of
306 this object for the inline case, otherwise word
307 has no place to find the dimensions of the ole
308 object, and will not be able to draw it
310 OutGrf(*m_pParentFrame
);
313 OutputField(nullptr, ww::eEMBED
, OUString(),
314 FieldFlags::End
| FieldFlags::Close
);
316 if (bEndCR
) //No newline in inline case
320 void WW8Export::OutputLinkedOLE( const OUString
& rOleId
)
322 uno::Reference
< embed::XStorage
> xDocStg
= m_rDoc
.GetDocStorage();
323 uno::Reference
< embed::XStorage
> xOleStg
= xDocStg
->openStorageElement( "OLELinks", embed::ElementModes::READ
);
324 tools::SvRef
<SotStorage
> xObjSrc
= SotStorage::OpenOLEStorage( xOleStg
, rOleId
, StreamMode::READ
);
326 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
328 if( !(xObjStg
.is() && xObjSrc
.is()) )
331 tools::SvRef
<SotStorage
> xOleDst
= xObjStg
->OpenSotStorage( rOleId
);
333 xObjSrc
->CopyTo( xOleDst
.get() );
335 if ( xOleDst
->GetError( ) )
340 // Output the cPicLocation attribute
341 std::unique_ptr
<ww::bytes
> pBuf( new ww::bytes
);
342 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CPicLocation::val
);
343 SwWW8Writer::InsUInt32( *pBuf
, rOleId
.copy( 1 ).toInt32() );
345 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFOle2::val
);
346 pBuf
->push_back( 1 );
348 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFSpec::val
);
349 pBuf
->push_back( 1 );
351 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::CFObj::val
);
352 pBuf
->push_back( 1 );
354 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pBuf
->size(), pBuf
->data() );
357 void WW8Export::OutGrf(const ww8::Frame
&rFrame
)
359 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
360 //will be exported to ensure the fidelity
361 const SwFormatURL
& rURL
= rFrame
.GetFrameFormat().GetAttrSet().GetURL();
362 bool bURLStarted
= false;
363 if( !rURL
.GetURL().isEmpty() && rFrame
.GetWriterType() == ww8::Frame::eGraphic
)
366 m_pAttrOutput
->StartURL( rURL
.GetURL(), rURL
.GetTargetFrameName() );
369 // Store the graphic settings in GrfNode so they may be written-out later
370 m_pGrf
->Insert(rFrame
);
372 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pO
->size(), pO
->data() );
376 // linked, as-character anchored graphics have to be exported as fields.
377 const SwGrfNode
* pGrfNd
= rFrame
.IsInline() && rFrame
.GetContent()
378 ? rFrame
.GetContent()->GetGrfNode() : nullptr;
379 if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
382 pGrfNd
->GetFileFilterNms(&sStr
, nullptr);
383 sStr
= FieldString(ww::eINCLUDEPICTURE
) + " \"" + sStr
+ "\" \\d";
385 OutputField( nullptr, ww::eINCLUDEPICTURE
, sStr
,
386 FieldFlags::Start
| FieldFlags::CmdStart
| FieldFlags::CmdEnd
);
389 WriteChar( char(1) ); // paste graphic symbols in the main text
391 sal_uInt8 aArr
[ 18 ];
392 sal_uInt8
* pArr
= aArr
;
394 const SwFrameFormat
&rFlyFormat
= rFrame
.GetFrameFormat();
395 const RndStdIds eAn
= rFlyFormat
.GetAttrSet().GetAnchor(false).GetAnchorId();
396 if (eAn
== RndStdIds::FLY_AS_CHAR
)
398 sal_Int16 eVert
= rFlyFormat
.GetVertOrient().GetVertOrient();
399 if ((eVert
== text::VertOrientation::CHAR_CENTER
) || (eVert
== text::VertOrientation::LINE_CENTER
))
402 //The default for word in vertical text mode is to center,
403 //otherwise a sub/super script hack is employed
404 if (auto pTextNd
= dynamic_cast< const SwContentNode
*>( m_pOutFormatNode
) )
406 SwPosition
aPos(*pTextNd
);
407 bVert
= m_rDoc
.IsInVerticalText(aPos
);
411 SwTwips nHeight
= rFlyFormat
.GetFrameSize().GetHeight();
412 nHeight
/=20; //nHeight was in twips, want it in half points, but
413 //then half of total height.
414 tools::Long nFontHeight
= GetItem(RES_CHRATR_FONTSIZE
).GetHeight();
415 nHeight
-=nFontHeight
/20;
417 Set_UInt16( pArr
, NS_sprm::CHpsPos::val
);
418 Set_UInt16( pArr
, - static_cast<sal_Int16
>(nHeight
));
424 Set_UInt16( pArr
, 0x855 );
425 Set_UInt8( pArr
, 1 );
428 Set_UInt16( pArr
, NS_sprm::CPicLocation::val
);
429 Set_UInt32( pArr
, GRF_MAGIC_321
);
431 // vary Magic, so that different graphic attributes will not be merged
432 static sal_uInt8 nAttrMagicIdx
= 0;
434 Set_UInt8( pArr
, nAttrMagicIdx
++ );
435 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
438 // Check, if graphic isn't exported as-character anchored.
439 // Otherwise, an additional paragraph is exported for a graphic, which is
440 // forced to be treated as inline, because it's anchored inside another frame.
441 if ( !rFrame
.IsInline() &&
442 ( (eAn
== RndStdIds::FLY_AT_PARA
) ||
443 (eAn
== RndStdIds::FLY_AT_PAGE
) ) )
445 WriteChar( char(0x0d) ); // close the surrounding frame with CR
447 static sal_uInt8 nSty
[2] = { 0, 0 };
448 pO
->insert( pO
->end(), nSty
, nSty
+2 ); // Style #0
449 bool bOldGrf
= m_bOutGrf
;
452 OutputFormat( rFrame
.GetFrameFormat(), false, false, true ); // Fly-Attrs
455 m_pPapPlc
->AppendFkpEntry( Strm().Tell(), pO
->size(), pO
->data() );
459 // linked, as-character anchored graphics have to be exported as fields.
460 else if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
462 OutputField( nullptr, ww::eINCLUDEPICTURE
, OUString(), FieldFlags::Close
);
464 //Added for i120568,the hyperlink info within a graphic whose anchor type is
465 //"As character" will be exported to ensure the fidelity
467 m_pAttrOutput
->EndURL(false);
470 void SwWW8WrGrf::Insert(const ww8::Frame
&rFly
)
472 const Size
aSize( rFly
.GetLayoutSize() );
473 const sal_uInt16 nWidth
= static_cast< sal_uInt16
>(aSize
.Width());
474 const sal_uInt16 nHeight
= static_cast< sal_uInt16
>(aSize
.Height());
475 maDetails
.emplace_back(rFly
, nWidth
, nHeight
);
478 void SwWW8WrGrf::WritePICFHeader(SvStream
& rStrm
, const ww8::Frame
&rFly
,
479 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
, const SwAttrSet
* pAttrSet
)
481 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
482 sal_Int16 nCropL
= 0, nCropR
= 0, nCropT
= 0, nCropB
= 0;
484 // write Crop-Attribute content in Header ( if available )
485 const SfxPoolItem
* pItem
;
486 if (pAttrSet
&& (SfxItemState::SET
487 == pAttrSet
->GetItemState(RES_GRFATR_CROPGRF
, false, &pItem
)))
489 const SwCropGrf
& rCr
= *static_cast<const SwCropGrf
*>(pItem
);
490 nCropL
= static_cast<sal_Int16
>(rCr
.GetLeft());
491 nCropR
= static_cast<sal_Int16
>(rCr
.GetRight());
492 nCropT
= static_cast<sal_Int16
>(rCr
.GetTop());
493 nCropB
= static_cast<sal_Int16
>(rCr
.GetBottom());
494 nXSizeAdd
= nXSizeAdd
- static_cast<sal_Int16
>( rCr
.GetLeft() + rCr
.GetRight() );
495 nYSizeAdd
= nYSizeAdd
- static_cast<sal_Int16
>( rCr
.GetTop() + rCr
.GetBottom() );
498 Size
aGrTwipSz(rFly
.GetSize());
499 sal_uInt16 nHdrLen
= 0x44;
501 sal_uInt8 aArr
[ 0x44 ] = { 0 };
503 sal_uInt8
* pArr
= aArr
+ 0x2E; // Do borders first
505 const SwAttrSet
& rAttrSet
= rFly
.GetFrameFormat().GetAttrSet();
506 if (SfxItemState::SET
== rAttrSet
.GetItemState(RES_BOX
, false, &pItem
))
508 const SvxBoxItem
* pBox
= static_cast<const SvxBoxItem
*>(pItem
);
511 bool bShadow
= false; // Shadow ?
512 if (const SvxShadowItem
* pSI
= rAttrSet
.GetItem
<SvxShadowItem
>(RES_SHADOW
))
514 bShadow
= (pSI
->GetLocation() != SvxShadowLocation::NONE
) &&
515 (pSI
->GetWidth() != 0);
518 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
519 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
520 for(const SvxBoxItemLine
& i
: aLnArr
)
522 const ::editeng::SvxBorderLine
* pLn
= pBox
->GetLine( i
);
526 WW8_BRCVer9 aBrc90
= WW8Export::TranslateBorderLine( *pLn
,
527 pBox
->GetDistance( i
), bShadow
);
528 sal_uInt8 ico
= msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
530 aBrc
= WW8_BRC(aBrc90
.dptLineWidth(), aBrc90
.brcType(), ico
,
531 aBrc90
.dptSpace(), aBrc90
.fShadow(), aBrc90
.fFrame());
534 // use importer logic to determine how large the exported
535 // border will really be in word and adjust accordingly
537 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
540 case SvxBoxItemLine::TOP
:
541 case SvxBoxItemLine::BOTTOM
:
542 nHeight
-= bShadow
? nThick
*2 : nThick
;
543 nHeight
= nHeight
- nSpacing
;
545 case SvxBoxItemLine::LEFT
:
546 case SvxBoxItemLine::RIGHT
:
548 nWidth
-= bShadow
? nThick
*2 : nThick
;
549 nWidth
= nWidth
- nSpacing
;
552 memcpy( pArr
, &aBrc
.aBits1
, 2);
555 memcpy( pArr
, &aBrc
.aBits2
, 2);
561 pArr
= aArr
+ 4; // skip lcb
562 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
564 Set_UInt16( pArr
, mm
); // set mm
567 Just in case our original size is too big to fit inside a ushort we can
568 substitute the final size and lose on retaining the scaling factor but
569 still keep the correct display size anyway.
571 const bool bIsSubstitutedSize
= (aGrTwipSz
.Width() > SHRT_MAX
) || (aGrTwipSz
.Height() > SHRT_MAX
) ||
573 if ( bIsSubstitutedSize
)
575 aGrTwipSz
.setWidth( nWidth
);
576 aGrTwipSz
.setHeight( nHeight
);
578 using namespace sw::types
;
580 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Width())));
581 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Height())));
583 // skip hMF & rcWinMF
584 // set dxaGoal & dyaGoal
585 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
586 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
588 if ( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
590 if ( !bIsSubstitutedSize
)
592 const double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
593 Set_UInt16( pArr
, static_cast<sal_uInt16
>(::rtl::math::round(fVal
)) );
597 Set_UInt16( pArr
, 1000 );
605 if ( aGrTwipSz
.Height() + nYSizeAdd
) // set my
607 if ( !bIsSubstitutedSize
)
609 const double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
610 Set_UInt16( pArr
, static_cast<sal_uInt16
>(::rtl::math::round(fVal
)) );
614 Set_UInt16( pArr
, 1000 );
622 if ( !bIsSubstitutedSize
)
624 Set_UInt16( pArr
, nCropL
); // set dxaCropLeft
625 Set_UInt16( pArr
, nCropT
); // set dyaCropTop
626 Set_UInt16( pArr
, nCropR
); // set dxaCropRight
627 Set_UInt16( pArr
, nCropB
); // set dyaCropBottom
630 rStrm
.WriteBytes(aArr
, nHdrLen
);
633 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream
& rStrm
, const SwGrfNode
&rGrfNd
,
634 const ww8::Frame
&rFly
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
636 if (rGrfNd
.IsLinkedFile()) // Linked File
639 rGrfNd
.GetFileFilterNms( &aFileN
, nullptr );
641 sal_uInt16
const mm
= 94; // 94 = BMP, GIF
643 WritePICFHeader(rStrm
, rFly
, mm
, nWidth
, nHeight
,
644 rGrfNd
.GetpSwAttrSet());
645 rStrm
.WriteUChar( aFileN
.getLength() ); // write Pascal-String
646 SwWW8Writer::WriteString8(rStrm
, aFileN
, false,
647 RTL_TEXTENCODING_MS_1252
);
649 else // Embedded File or DDE or something like that
651 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
652 rGrfNd
.GetpSwAttrSet());
653 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
654 aInlineEscher
.WriteGrfFlyFrame(rFly
.GetFrameFormat(), 0x401);
655 aInlineEscher
.WritePictures();
658 //For i120928,export graphic info of bullet
659 void SwWW8WrGrf::WritePICBulletFHeader(SvStream
& rStrm
, const Graphic
&rGrf
,
660 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
662 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
664 Size
aGrTwipSz(rGrf
.GetPrefSize());
665 sal_uInt16 nHdrLen
= 0x44;
667 sal_uInt8 aArr
[ 0x44 ] = { 0 };
669 sal_uInt8
* pArr
= aArr
+ 0x2E; //Do borders first
671 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
672 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
673 for(const SvxBoxItemLine
& i
: aLnArr
)
678 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
681 case SvxBoxItemLine::TOP
:
682 case SvxBoxItemLine::BOTTOM
:
684 nHeight
= nHeight
- nSpacing
;
686 case SvxBoxItemLine::LEFT
:
687 case SvxBoxItemLine::RIGHT
:
690 nWidth
= nWidth
- nSpacing
;
693 memcpy( pArr
, &aBrc
.aBits1
, 2);
696 memcpy(pArr
, &aBrc
.aBits2
, 2);
700 pArr
= aArr
+ 4; //skip lcb
701 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
703 Set_UInt16( pArr
, mm
); // set mm
705 if ( (convertTwipToMm100(aGrTwipSz
.Width()) > USHRT_MAX
) || ( convertTwipToMm100(aGrTwipSz
.Height()) > USHRT_MAX
)
706 || aGrTwipSz
.IsEmpty() )
708 aGrTwipSz
.setWidth( nWidth
);
709 aGrTwipSz
.setHeight( nHeight
);
711 using namespace sw::types
;
713 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Width())));
714 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(convertTwipToMm100(aGrTwipSz
.Height())));
716 // skip hMF & rcWinMF
717 // set dxaGoal & dyaGoal
718 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
719 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
721 if( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
723 double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
724 Set_UInt16( pArr
, static_cast<sal_uInt16
>(::rtl::math::round(fVal
)) );
729 if( aGrTwipSz
.Height() + nYSizeAdd
) // set my
731 double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
732 Set_UInt16( pArr
, static_cast<sal_uInt16
>(::rtl::math::round(fVal
)) );
737 Set_UInt16( pArr
, 0 ); // set dxaCropLeft
738 Set_UInt16( pArr
, 0 ); // set dyaCropTop
739 Set_UInt16( pArr
, 0 ); // set dxaCropRight
740 Set_UInt16( pArr
, 0 ); // set dyaCropBottom
742 rStrm
.WriteBytes(aArr
, nHdrLen
);
745 void SwWW8WrGrf::WriteGrfForBullet(SvStream
& rStrm
, const Graphic
&rGrf
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
747 WritePICBulletFHeader(rStrm
,rGrf
, 0x64,nWidth
,nHeight
);
748 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
749 aInlineEscher
.WriteGrfBullet(rGrf
);
750 aInlineEscher
.WritePictures();
753 void SwWW8WrGrf::WriteGraphicNode(SvStream
& rStrm
, const GraphicDetails
&rItem
)
755 sal_uInt16 nWidth
= rItem
.mnWid
;
756 sal_uInt16 nHeight
= rItem
.mnHei
;
757 sal_uInt32 nPos
= rStrm
.Tell(); // store start of graphic
759 const ww8::Frame
&rFly
= rItem
.maFly
;
760 switch (rFly
.GetWriterType())
762 case ww8::Frame::eGraphic
:
764 const SwNode
*pNode
= rItem
.maFly
.GetContent();
765 const SwGrfNode
*pNd
= pNode
? pNode
->GetGrfNode() : nullptr;
766 OSL_ENSURE(pNd
, "Impossible");
768 WriteGrfFromGrfNode(rStrm
, *pNd
, rItem
.maFly
, nWidth
, nHeight
);
771 //For i120928,add branch to export graphic of bullet
772 case ww8::Frame::eBulletGrf
:
774 if (rItem
.maFly
.HasGraphic())
776 const Graphic
& rGrf
= rItem
.maFly
.GetGraphic();
777 WriteGrfForBullet(rStrm
, rGrf
, nWidth
, nHeight
);
782 case ww8::Frame::eOle
:
784 const SwNode
*pNode
= rItem
.maFly
.GetContent();
785 const SwOLENode
*pNd
= pNode
? pNode
->GetOLENode() : nullptr;
786 OSL_ENSURE(pNd
, "Impossible");
789 #ifdef OLE_PREVIEW_AS_EMF
790 //Convert this ole2 preview in ww8+ to an EMF for better unicode
791 //support (note that at this moment this breaks StarSymbol
792 //using graphics because I need to embed starsymbol in exported
794 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
795 pNd
->GetpSwAttrSet());
796 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
797 aInlineEscher
.WriteOLEFlyFrame(rFly
.GetFrameFormat(), 0x401);
798 aInlineEscher
.WritePictures();
801 SwOLENode
*pOleNd
= const_cast<SwOLENode
*>(pNd
);
802 SwOLEObj
& rSObj
= pOleNd
->GetOLEObj();
804 // TODO/LATER: do we need to load object?
805 Graphic
* pGr
= SdrOle2Obj::GetGraphicFromObject( pOleNd
->GetDoc()->GetDocStorage(), rObj
);
807 //TODO/LATER: do we really want to use GDIMetafile?!
810 aMtf
= pGr
->GetGDIMetaFile();
812 Size
aS(aMtf
.GetPrefSize());
814 aMtf
.Play(Application::GetDefaultDevice(), Point(0, 0),
817 WritePICFHeader(rStrm
, rFly
, 8, nWidth
, nHeight
,
818 pNd
->GetpSwAttrSet());
819 WriteWindowMetafileBits(rStrm
, aMtf
);
825 case ww8::Frame::eDrawing
:
826 case ww8::Frame::eTextBox
:
827 case ww8::Frame::eFormControl
:
829 #i3958# We only export an empty dummy picture frame here, this is
830 what word does the escher export should contain an anchored to
831 character element which is drawn over this dummy and the whole
832 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
836 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
);
837 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
838 aInlineEscher
.WriteEmptyFlyFrame(rFly
.GetFrameFormat(), 0x401);
842 OSL_ENSURE(false, "Some inline export not implemented");
846 sal_uInt32 nPos2
= rStrm
.Tell(); // store the end
848 rStrm
.WriteUInt32(nPos2
- nPos
); // patch graphic length in the header
849 rStrm
.Seek( nPos2
); // restore Pos
852 // SwWW8WrGrf::Write() is called after the text.
853 // It writes out all the graphics and remembers the file locations of the graphics,
854 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
855 // The search in the attributes for the Magic sal_uLong and patching
856 // happens when writing the attributes. Class SwWW8WrGrf provides with
857 // GetFPos() sequentially the positions
858 void SwWW8WrGrf::Write()
860 SvStream
& rStrm
= *rWrt
.pDataStrm
;
861 auto aEnd
= maDetails
.end();
862 for (auto aIter
= maDetails
.begin(); aIter
!= aEnd
; ++aIter
)
864 sal_uInt32 nPos
= rStrm
.Tell(); // align to 4 Bytes
866 SwWW8Writer::FillCount( rStrm
, 4 - ( nPos
& 0x3 ) );
868 auto aIter2
= std::find(maDetails
.begin(), aIter
, *aIter
);
871 aIter
->mnPos
= aIter2
->mnPos
;
875 aIter
->mnPos
= rStrm
.Tell();
876 WriteGraphicNode(rStrm
, *aIter
);
881 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */