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 .
20 #include <com/sun/star/embed/XEmbedPersist.hpp>
21 #include <com/sun/star/embed/Aspects.hpp>
22 #include <com/sun/star/embed/ElementModes.hpp>
23 #include <rtl/math.hxx>
24 #include <vcl/graphicfilter.hxx>
25 #include <vcl/wmf.hxx>
26 #include <svl/itemiter.hxx>
27 #include <svl/urihelper.hxx>
29 #include <svtools/embedhlp.hxx>
31 #include <vcl/virdev.hxx>
32 #include <vcl/svapp.hxx>
34 #include <hintids.hxx>
35 #include <editeng/boxitem.hxx>
36 #include <editeng/shaditem.hxx>
37 #include <filter/msfilter/msoleexp.hxx>
38 #include <editeng/lrspitem.hxx>
39 #include <editeng/ulspitem.hxx>
40 #include <editeng/fhgtitem.hxx>
41 #include <svx/svdoole2.hxx>
43 #include <unotools/ucbstreamhelper.hxx>
44 #include <fmtanchr.hxx>
50 #include <fmtfsize.hxx>
51 #include <fmtornt.hxx>
53 #include <sprmids.hxx>
56 #include "writerhelper.hxx"
57 #include "writerwordglue.hxx"
58 #include "ww8struc.hxx"
63 #include "ww8attributeoutput.hxx"
68 #include <o3tl/enumrange.hxx>
70 using namespace ::com::sun::star
;
71 using namespace nsFieldFlags
;
74 // 5. convert the MapModes that Widows can't handle
76 // OutGrf () is called for every GrafNode in the document. Es wird ein PicLocFc-Sprm
77 // eingefuegt, der statt Adresse ein Magic sal_uLong enthaelt. Ausserdem wird
78 // in der Graf-Klasse der GrfNode-Ptr gemerkt ( fuers spaetere Ausgeben der
79 // Grafiken und Patchen der PicLocFc-Attribute )
81 void WW8Export::OutputGrfNode( const SwGrfNode
& /*rNode*/ )
83 OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )" );
84 OSL_ENSURE( m_pParentFrame
, "frame not set!" );
87 OutGrf( *m_pParentFrame
);
88 pFib
->m_fHasPic
= true;
92 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet
& rSet
,
93 tools::SvRef
<SotStorage
> const & xOleStg
, tools::SvRef
<SotStorage
> xObjStg
, OUString
&rStorageName
,
96 bool bGraphicNeeded
= false;
97 SfxItemIter
aIter( rSet
);
98 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
101 switch (pItem
->Which())
104 For an inline object these properties are irrelevant because they
105 will be the same as the defaults that msword applies in their
106 absence, so if that is all that there is for these inline objects
107 then if there turns out to be enough information in the object
108 itself to regenerate the correct size and preview of the object
109 then we will not need to provide an additional graphics preview in
110 the data stream, which can save a lot of disk space.
114 case RES_VERT_ORIENT
:
118 bGraphicNeeded
= true;
120 } while( !bGraphicNeeded
&& !aIter
.IsAtEnd() &&
121 nullptr != ( pItem
= aIter
.NextItem() ) );
124 Now we must see if the object contains a preview itself which is equal to
125 the preview that we are currently using. If the graphics are equal then we
126 don't need to store another preview
130 if (!bGraphicNeeded
&& SwWW8ImplReader::ImportOleWMF(xOleStg
,aWMF
,nX
,nY
))
132 // bGraphicNeeded set to true is right / fixes #i51670#.
133 bGraphicNeeded
= true;
135 Rectangle
aRect( aTmpPoint
, Size( nX
, nY
) );
136 Graphic
aGraph(aWMF
);
138 ErrCode nErr
= ERRCODE_NONE
;
140 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
142 nAspect
= pOLENd
->GetAspect();
143 SdrOle2Obj
*pRet
= SvxMSDffManager::CreateSdrOLEFromStorage(
144 rStorageName
,xObjStg
,m_pDoc
->GetDocStorage(),aGraph
,aRect
,aVisArea
,nullptr,nErr
,0,nAspect
, m_pWriter
->GetBaseURL());
148 uno::Reference
< embed::XEmbeddedObject
> xObj
= pOLENd
->GetOLEObj().GetOleRef();
151 SvStream
* pGraphicStream
= nullptr;
152 comphelper::EmbeddedObjectContainer
aCnt( m_pDoc
->GetDocStorage() );
155 uno::Reference
< embed::XEmbedPersist
> xPersist(
157 uno::UNO_QUERY_THROW
);
159 // it makes no sense to search the object in the container by reference since the object was created
160 // outside of the container and was not inserted there, only the name makes sense
162 ::utl::UcbStreamHelper::CreateStream( aCnt
.GetGraphicStream( xPersist
->getEntryName() ) );
164 catch( const uno::Exception
& )
167 OSL_ENSURE( pGraphicStream
&& !pGraphicStream
->GetError(), "No graphic stream available!" );
168 if ( pGraphicStream
&& !pGraphicStream
->GetError() )
171 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
172 if( rGF
.ImportGraphic( aGr1
, OUString(), *pGraphicStream
) == GRFILTER_OK
)
175 delete pGraphicStream
;
177 ::utl::UcbStreamHelper::CreateStream( aCnt
.GetGraphicStream( pRet
->GetObjRef() ) );
178 if( pGraphicStream
&& rGF
.ImportGraphic( aGr2
, OUString(), *pGraphicStream
) == GRFILTER_OK
)
181 bGraphicNeeded
= false;
185 delete pGraphicStream
;
192 bGraphicNeeded
= true;
193 return bGraphicNeeded
;
196 void WW8Export::OutputOLENode( const SwOLENode
& rOLENode
)
198 OSL_TRACE("WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
202 static sal_uInt8 aSpecOLE_WW8
[] = {
203 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
204 0x0a, 0x08, 1, // sprmCFOLE2
205 0x56, 0x08, 1 // sprmCFObj
208 pSpecOLE
= aSpecOLE_WW8
;
209 nSize
= sizeof( aSpecOLE_WW8
);
210 pDataAdr
= pSpecOLE
+ 2; //WW6 sprm is 1 but has 1 byte len as well.
212 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(
213 OUString(SL::aObjectPool
) );
217 uno::Reference
< embed::XEmbeddedObject
> xObj(const_cast<SwOLENode
&>(rOLENode
).GetOLEObj().GetOleRef());
220 const embed::XEmbeddedObject
*pObj
= xObj
.get();
221 //Don't want to use pointer ids, as is traditional, because we need
222 //to put this into a 32bit value, and on 64bit the bottom bits
223 //might collide and two unrelated ole objects end up considered the
224 //same. Don't want to simply start at 0 which is a special value
225 sal_Int32 nPictureId
= SAL_MAX_INT32
- m_aOleMap
.size();
226 WW8OleMap::value_type entry
= std::make_pair(pObj
, nPictureId
);
227 std::pair
<WW8OleMap::iterator
, bool> aRes
= m_aOleMap
.insert(entry
);
228 bool bIsNotDuplicate
= aRes
.second
; //.second is false when element already existed
229 nPictureId
= aRes
.first
->second
;
230 Set_UInt32(pDataAdr
, nPictureId
);
231 OUString
sStorageName('_');
232 sStorageName
+= OUString::number( nPictureId
);
233 tools::SvRef
<SotStorage
> xOleStg
= xObjStg
->OpenSotStorage( sStorageName
);
237 If this object storage has been written already don't
238 waste time rewriting it
242 sal_Int64 nAspect
= rOLENode
.GetAspect();
243 svt::EmbeddedObjectRef
aObjRef( xObj
, nAspect
);
244 GetOLEExp().ExportOLEObject( aObjRef
, *xOleStg
);
245 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
247 OUString
aObjInfo( "\3ObjInfo" );
248 if ( !xOleStg
->IsStream( aObjInfo
) )
250 const sal_uInt8 pObjInfoData
[] = { 0x40, 0x00, 0x03, 0x00 };
251 tools::SvRef
<SotStorageStream
> rObjInfoStream
= xOleStg
->OpenSotStream( aObjInfo
);
252 if ( rObjInfoStream
.Is() && !rObjInfoStream
->GetError() )
254 rObjInfoStream
->WriteBytes(pObjInfoData
, sizeof(pObjInfoData
));
261 // write as embedded field - the other things will be done
262 // in the escher export
263 OUString sServer
= FieldString(ww::eEMBED
) + xOleStg
->GetUserName() + " ";
265 OutputField(nullptr, ww::eEMBED
, sServer
, WRITEFIELD_START
|
266 WRITEFIELD_CMD_START
| WRITEFIELD_CMD_END
);
268 m_pChpPlc
->AppendFkpEntry( Strm().Tell(),
273 In the word filter we only need a preview image for
274 floating images, and then only (the usual case) if the
275 object doesn't contain enough information to reconstruct
278 We don't need a graphic for inline objects, so we don't
279 even need the overhead of a graphic in that case.
281 bool bGraphicNeeded
= false;
285 bGraphicNeeded
= true;
287 if (m_pParentFrame
->IsInline())
289 const SwAttrSet
& rSet
=
290 m_pParentFrame
->GetFrameFormat().GetAttrSet();
292 bGraphicNeeded
= TestOleNeedsGraphic(rSet
,
293 xOleStg
, xObjStg
, sStorageName
, const_cast<SwOLENode
*>(&rOLENode
));
303 We need to insert the graphic representation of
304 this object for the inline case, otherwise word
305 has no place to find the dimensions of the ole
306 object, and will not be able to draw it
308 OutGrf(*m_pParentFrame
);
311 OutputField(nullptr, ww::eEMBED
, OUString(),
312 WRITEFIELD_END
| WRITEFIELD_CLOSE
);
314 if (bEndCR
) //No newline in inline case
321 void WW8Export::OutputLinkedOLE( const OUString
& rOleId
)
323 uno::Reference
< embed::XStorage
> xDocStg
= m_pDoc
->GetDocStorage();
324 uno::Reference
< embed::XStorage
> xOleStg
= xDocStg
->openStorageElement( "OLELinks", embed::ElementModes::READ
);
325 tools::SvRef
<SotStorage
> xObjSrc
= SotStorage::OpenOLEStorage( xOleStg
, rOleId
, StreamMode::READ
);
327 tools::SvRef
<SotStorage
> xObjStg
= GetWriter().GetStorage().OpenSotStorage(
328 OUString(SL::aObjectPool
) );
330 if( xObjStg
.Is() && xObjSrc
.Is() )
332 tools::SvRef
<SotStorage
> xOleDst
= xObjStg
->OpenSotStorage( rOleId
);
334 xObjSrc
->CopyTo( xOleDst
.get() );
336 if ( !xOleDst
->GetError( ) )
340 // Ouput the cPicLocation attribute
341 std::unique_ptr
<ww::bytes
> pBuf( new ww::bytes
);
342 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::LN_CPicLocation
);
343 SwWW8Writer::InsUInt32( *pBuf
, rOleId
.copy( 1 ).toInt32() );
345 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::LN_CFOle2
);
346 pBuf
->push_back( 1 );
348 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::LN_CFSpec
);
349 pBuf
->push_back( 1 );
351 SwWW8Writer::InsUInt16( *pBuf
, NS_sprm::LN_CFObj
);
352 pBuf
->push_back( 1 );
354 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pBuf
->size(), pBuf
->data() );
359 void WW8Export::OutGrf(const ww8::Frame
&rFrame
)
361 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
362 //will be exported to ensure the fidelity
363 const SwFormatURL
& rURL
= rFrame
.GetFrameFormat().GetAttrSet().GetURL();
364 bool bURLStarted
= false;
365 if( !rURL
.GetURL().isEmpty() && rFrame
.GetWriterType() == ww8::Frame::eGraphic
)
368 m_pAttrOutput
->StartURL( rURL
.GetURL(), rURL
.GetTargetFrameName() );
371 // Store the graphic settings in GrfNode so they may be written-out later
372 m_pGrf
->Insert(rFrame
);
374 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pO
->size(), pO
->data() );
378 // linked, as-character anchored graphics have to be exported as fields.
379 const SwGrfNode
* pGrfNd
= rFrame
.IsInline() && rFrame
.GetContent()
380 ? rFrame
.GetContent()->GetGrfNode() : nullptr;
381 if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
383 OUString
sStr( FieldString(ww::eINCLUDEPICTURE
) );
389 pGrfNd
->GetFileFilterNms( &aFileURL
, nullptr );
395 OutputField( nullptr, ww::eINCLUDEPICTURE
, sStr
,
396 WRITEFIELD_START
| WRITEFIELD_CMD_START
| WRITEFIELD_CMD_END
);
399 WriteChar( (char)1 ); // paste graphic symbols in the main text
401 sal_uInt8 aArr
[ 18 ];
402 sal_uInt8
* pArr
= aArr
;
404 const SwFrameFormat
&rFlyFormat
= rFrame
.GetFrameFormat();
405 const RndStdIds eAn
= rFlyFormat
.GetAttrSet().GetAnchor(false).GetAnchorId();
406 if (eAn
== FLY_AS_CHAR
)
408 sal_Int16 eVert
= rFlyFormat
.GetVertOrient().GetVertOrient();
409 if ((eVert
== text::VertOrientation::CHAR_CENTER
) || (eVert
== text::VertOrientation::LINE_CENTER
))
412 //The default for word in vertical text mode is to center,
413 //otherwise a sub/super script hack is employed
414 if (m_pOutFormatNode
&& dynamic_cast< const SwContentNode
*>( m_pOutFormatNode
) != nullptr )
416 const SwTextNode
* pTextNd
= static_cast<const SwTextNode
*>(m_pOutFormatNode
);
417 SwPosition
aPos(*pTextNd
);
418 bVert
= m_pDoc
->IsInVerticalText(aPos
);
422 SwTwips nHeight
= rFlyFormat
.GetFrameSize().GetHeight();
423 nHeight
/=20; //nHeight was in twips, want it in half points, but
424 //then half of total height.
425 long nFontHeight
= static_cast<const SvxFontHeightItem
&>(
426 GetItem(RES_CHRATR_FONTSIZE
)).GetHeight();
427 nHeight
-=nFontHeight
/20;
429 Set_UInt16( pArr
, NS_sprm::LN_CHpsPos
);
430 Set_UInt16( pArr
, -((sal_Int16
)nHeight
));
436 Set_UInt16( pArr
, 0x855 );
437 Set_UInt8( pArr
, 1 );
440 Set_UInt16( pArr
, NS_sprm::LN_CPicLocation
);
441 Set_UInt32( pArr
, GRF_MAGIC_321
);
443 // vary Magic, so that different graphic attributes will not be merged
444 static sal_uInt8 nAttrMagicIdx
= 0;
446 Set_UInt8( pArr
, nAttrMagicIdx
++ );
447 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
450 // Check, if graphic isn't exported as-character anchored.
451 // Otherwise, an additional paragraph is exported for a graphic, which is
452 // forced to be treated as inline, because it's anchored inside another frame.
453 if ( !rFrame
.IsInline() &&
454 ( ((eAn
== FLY_AT_PARA
)) ||
455 (eAn
== FLY_AT_PAGE
)) )
457 WriteChar( (char)0x0d ); // close the surrounding frame with CR
459 static sal_uInt8 nSty
[2] = { 0, 0 };
460 pO
->insert( pO
->end(), nSty
, nSty
+2 ); // Style #0
461 bool bOldGrf
= m_bOutGrf
;
464 OutputFormat( rFrame
.GetFrameFormat(), false, false, true ); // Fly-Attrs
467 m_pPapPlc
->AppendFkpEntry( Strm().Tell(), pO
->size(), pO
->data() );
471 // linked, as-character anchored graphics have to be exported as fields.
472 else if ( pGrfNd
&& pGrfNd
->IsLinkedFile() )
474 OutputField( nullptr, ww::eINCLUDEPICTURE
, OUString(), WRITEFIELD_CLOSE
);
476 //Added for i120568,the hyperlink info within a graphic whose anchor type is
477 //"As character" will be exported to ensure the fidelity
479 m_pAttrOutput
->EndURL(false);
482 GraphicDetails
& GraphicDetails::operator=(const GraphicDetails
&rOther
)
484 maFly
= rOther
.maFly
;
485 mnPos
= rOther
.mnPos
;
486 mnWid
= rOther
.mnWid
;
487 mnHei
= rOther
.mnHei
;
491 void SwWW8WrGrf::Insert(const ww8::Frame
&rFly
)
493 const Size
aSize( rFly
.GetLayoutSize() );
494 const sal_uInt16 nWidth
= static_cast< sal_uInt16
>(aSize
.Width());
495 const sal_uInt16 nHeight
= static_cast< sal_uInt16
>(aSize
.Height());
496 maDetails
.push_back(GraphicDetails(rFly
, nWidth
, nHeight
));
499 void SwWW8WrGrf::WritePICFHeader(SvStream
& rStrm
, const ww8::Frame
&rFly
,
500 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
, const SwAttrSet
* pAttrSet
)
502 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
503 sal_Int16 nCropL
= 0, nCropR
= 0, nCropT
= 0, nCropB
= 0;
505 // write Crop-Attribut content in Header ( if available )
506 const SfxPoolItem
* pItem
;
507 if (pAttrSet
&& (SfxItemState::SET
508 == pAttrSet
->GetItemState(RES_GRFATR_CROPGRF
, false, &pItem
)))
510 const SwCropGrf
& rCr
= *static_cast<const SwCropGrf
*>(pItem
);
511 nCropL
= (sal_Int16
)rCr
.GetLeft();
512 nCropR
= (sal_Int16
)rCr
.GetRight();
513 nCropT
= (sal_Int16
)rCr
.GetTop();
514 nCropB
= (sal_Int16
)rCr
.GetBottom();
515 nXSizeAdd
= nXSizeAdd
- (sal_Int16
)( rCr
.GetLeft() + rCr
.GetRight() );
516 nYSizeAdd
= nYSizeAdd
- (sal_Int16
)( rCr
.GetTop() + rCr
.GetBottom() );
519 Size
aGrTwipSz(rFly
.GetSize());
520 sal_uInt16 nHdrLen
= 0x44;
522 sal_uInt8 aArr
[ 0x44 ] = { 0 };
524 sal_uInt8
* pArr
= aArr
+ 0x2E; // Do borders first
526 const SwAttrSet
& rAttrSet
= rFly
.GetFrameFormat().GetAttrSet();
527 if (SfxItemState::SET
== rAttrSet
.GetItemState(RES_BOX
, false, &pItem
))
529 const SvxBoxItem
* pBox
= static_cast<const SvxBoxItem
*>(pItem
);
532 bool bShadow
= false; // Shadow ?
533 if (const SvxShadowItem
* pSI
= rAttrSet
.GetItem
<SvxShadowItem
>(RES_SHADOW
))
535 bShadow
= (pSI
->GetLocation() != SVX_SHADOW_NONE
) &&
536 (pSI
->GetWidth() != 0);
539 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
540 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
541 for(const SvxBoxItemLine
& i
: aLnArr
)
543 const ::editeng::SvxBorderLine
* pLn
= pBox
->GetLine( i
);
547 WW8_BRCVer9 aBrc90
= WW8Export::TranslateBorderLine( *pLn
,
548 pBox
->GetDistance( i
), bShadow
);
549 sal_uInt8 ico
= msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
551 aBrc
= WW8_BRC(aBrc90
.dptLineWidth(), aBrc90
.brcType(), ico
,
552 aBrc90
.dptSpace(), aBrc90
.fShadow(), aBrc90
.fFrame());
555 // use importer logic to determine how large the exported
556 // border will really be in word and adjust accordingly
558 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
561 case SvxBoxItemLine::TOP
:
562 case SvxBoxItemLine::BOTTOM
:
563 nHeight
-= bShadow
? nThick
*2 : nThick
;
564 nHeight
= nHeight
- nSpacing
;
566 case SvxBoxItemLine::LEFT
:
567 case SvxBoxItemLine::RIGHT
:
569 nWidth
-= bShadow
? nThick
*2 : nThick
;
570 nWidth
= nWidth
- nSpacing
;
573 memcpy( pArr
, &aBrc
.aBits1
, 2);
576 memcpy( pArr
, &aBrc
.aBits2
, 2);
582 pArr
= aArr
+ 4; // skip lcb
583 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
585 Set_UInt16( pArr
, mm
); // set mm
588 Just in case our original size is too big to fit inside a ushort we can
589 substitute the final size and lose on retaining the scaling factor but
590 still keep the correct display size anyway.
592 const bool bIsSubstitutedSize
= (aGrTwipSz
.Width() > SHRT_MAX
) || (aGrTwipSz
.Height() > SHRT_MAX
) ||
593 (aGrTwipSz
.Width() < 0 ) || (aGrTwipSz
.Height() < 0);
594 if ( bIsSubstitutedSize
)
596 aGrTwipSz
.Width() = nWidth
;
597 aGrTwipSz
.Height() = nHeight
;
599 using namespace sw::types
;
601 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width() * 254L / 144));
602 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height() * 254L / 144));
604 // skip hMF & rcWinMF
605 // set dxaGoal & dyaGoal
606 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
607 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
609 if ( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
611 if ( !bIsSubstitutedSize
)
613 const double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
614 Set_UInt16( pArr
, (sal_uInt16
)::rtl::math::round(fVal
) );
618 Set_UInt16( pArr
, 1000 );
626 if ( aGrTwipSz
.Height() + nYSizeAdd
) // set my
628 if ( !bIsSubstitutedSize
)
630 const double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
631 Set_UInt16( pArr
, (sal_uInt16
)::rtl::math::round(fVal
) );
635 Set_UInt16( pArr
, 1000 );
643 if ( !bIsSubstitutedSize
)
645 Set_UInt16( pArr
, nCropL
); // set dxaCropLeft
646 Set_UInt16( pArr
, nCropT
); // set dyaCropTop
647 Set_UInt16( pArr
, nCropR
); // set dxaCropRight
648 Set_UInt16( pArr
, nCropB
); // set dyaCropBottom
651 rStrm
.WriteBytes(aArr
, nHdrLen
);
654 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream
& rStrm
, const SwGrfNode
&rGrfNd
,
655 const ww8::Frame
&rFly
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
657 if (rGrfNd
.IsLinkedFile()) // Linked File
660 rGrfNd
.GetFileFilterNms( &aFileN
, nullptr );
662 sal_uInt16 mm
= 94; // 94 = BMP, GIF
664 WritePICFHeader(rStrm
, rFly
, mm
, nWidth
, nHeight
,
665 rGrfNd
.GetpSwAttrSet());
666 rStrm
.WriteUChar( aFileN
.getLength() ); // write Pascal-String
667 SwWW8Writer::WriteString8(rStrm
, aFileN
, false,
668 RTL_TEXTENCODING_MS_1252
);
670 else // Embedded File or DDE or something like that
672 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
673 rGrfNd
.GetpSwAttrSet());
674 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
675 aInlineEscher
.WriteGrfFlyFrame(rFly
.GetFrameFormat(), 0x401);
676 aInlineEscher
.WritePictures();
679 //For i120928,export graphic info of bullet
680 void SwWW8WrGrf::WritePICBulletFHeader(SvStream
& rStrm
, const Graphic
&rGrf
,
681 sal_uInt16 mm
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
683 sal_Int16 nXSizeAdd
= 0, nYSizeAdd
= 0;
684 sal_Int16 nCropL
= 0, nCropR
= 0, nCropT
= 0, nCropB
= 0;
686 Size
aGrTwipSz(rGrf
.GetPrefSize());
687 sal_uInt16 nHdrLen
= 0x44;
689 sal_uInt8 aArr
[ 0x44 ] = { 0 };
691 sal_uInt8
* pArr
= aArr
+ 0x2E; //Do borders first
693 static const SvxBoxItemLine aLnArr
[4] = { SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
694 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
};
695 for(const SvxBoxItemLine
& i
: aLnArr
)
700 short nThick
= aBrc
.DetermineBorderProperties(&nSpacing
);
703 case SvxBoxItemLine::TOP
:
704 case SvxBoxItemLine::BOTTOM
:
706 nHeight
= nHeight
- nSpacing
;
708 case SvxBoxItemLine::LEFT
:
709 case SvxBoxItemLine::RIGHT
:
712 nWidth
= nWidth
- nSpacing
;
715 memcpy( pArr
, &aBrc
.aBits1
, 2);
718 memcpy(pArr
, &aBrc
.aBits2
, 2);
722 pArr
= aArr
+ 4; //skip lcb
723 Set_UInt16( pArr
, nHdrLen
); // set cbHeader
725 Set_UInt16( pArr
, mm
); // set mm
727 if ( (aGrTwipSz
.Width() * 254L / 144 > USHRT_MAX
) || (aGrTwipSz
.Height() * 254L / 144 > USHRT_MAX
)
728 || (aGrTwipSz
.Width() < 0 ) || (aGrTwipSz
.Height() < 0) )
730 aGrTwipSz
.Width() = nWidth
;
731 aGrTwipSz
.Height() = nHeight
;
733 using namespace sw::types
;
735 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width() * 254L / 144));
736 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height() * 254L / 144));
738 // skip hMF & rcWinMF
739 // set dxaGoal & dyaGoal
740 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Width()));
741 Set_UInt16(pArr
, msword_cast
<sal_uInt16
>(aGrTwipSz
.Height()));
743 if( aGrTwipSz
.Width() + nXSizeAdd
) // set mx
745 double fVal
= nWidth
* 1000.0 / (aGrTwipSz
.Width() + nXSizeAdd
);
746 Set_UInt16( pArr
, (sal_uInt16
)::rtl::math::round(fVal
) );
751 if( aGrTwipSz
.Height() + nYSizeAdd
) // set my
753 double fVal
= nHeight
* 1000.0 / (aGrTwipSz
.Height() + nYSizeAdd
);
754 Set_UInt16( pArr
, (sal_uInt16
)::rtl::math::round(fVal
) );
759 Set_UInt16( pArr
, nCropL
); // set dxaCropLeft
760 Set_UInt16( pArr
, nCropT
); // set dyaCropTop
761 Set_UInt16( pArr
, nCropR
); // set dxaCropRight
762 Set_UInt16( pArr
, nCropB
); // set dyaCropBottom
764 rStrm
.WriteBytes(aArr
, nHdrLen
);
767 void SwWW8WrGrf::WriteGrfForBullet(SvStream
& rStrm
, const Graphic
&rGrf
, sal_uInt16 nWidth
, sal_uInt16 nHeight
)
769 WritePICBulletFHeader(rStrm
,rGrf
, 0x64,nWidth
,nHeight
);
770 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
771 aInlineEscher
.WriteGrfBullet(rGrf
);
772 aInlineEscher
.WritePictures();
775 void SwWW8WrGrf::WriteGraphicNode(SvStream
& rStrm
, const GraphicDetails
&rItem
)
777 sal_uInt16 nWidth
= rItem
.mnWid
;
778 sal_uInt16 nHeight
= rItem
.mnHei
;
779 sal_uInt32 nPos
= rStrm
.Tell(); // store start of graphic
781 const ww8::Frame
&rFly
= rItem
.maFly
;
782 switch (rFly
.GetWriterType())
784 case ww8::Frame::eGraphic
:
786 const SwNode
*pNode
= rItem
.maFly
.GetContent();
787 const SwGrfNode
*pNd
= pNode
? pNode
->GetGrfNode() : nullptr;
788 OSL_ENSURE(pNd
, "Impossible");
790 WriteGrfFromGrfNode(rStrm
, *pNd
, rItem
.maFly
, nWidth
, nHeight
);
793 //For i120928,add branch to export graphic of bullet
794 case ww8::Frame::eBulletGrf
:
796 if (rItem
.maFly
.HasGraphic())
798 const Graphic
& rGrf
= rItem
.maFly
.GetGraphic();
799 WriteGrfForBullet(rStrm
, rGrf
, nWidth
, nHeight
);
804 case ww8::Frame::eOle
:
806 const SwNode
*pNode
= rItem
.maFly
.GetContent();
807 const SwOLENode
*pNd
= pNode
? pNode
->GetOLENode() : nullptr;
808 OSL_ENSURE(pNd
, "Impossible");
811 #ifdef OLE_PREVIEW_AS_EMF
812 //Convert this ole2 preview in ww8+ to an EMF for better unicode
813 //support (note that at this moment this breaks StarSymbol
814 //using graphics because I need to embed starsymbol in exported
816 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
,
817 pNd
->GetpSwAttrSet());
818 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
819 aInlineEscher
.WriteOLEFlyFrame(rFly
.GetFrameFormat(), 0x401);
820 aInlineEscher
.WritePictures();
823 SwOLENode
*pOleNd
= const_cast<SwOLENode
*>(pNd
);
824 SwOLEObj
& rSObj
= pOleNd
->GetOLEObj();
826 // TODO/LATER: do we need to load object?
827 Graphic
* pGr
= SdrOle2Obj::GetGraphicFromObject( pOleNd
->GetDoc()->GetDocStorage(), rObj
);
829 //TODO/LATER: do we really want to use GDIMetafile?!
832 aMtf
= pGr
->GetGDIMetaFile();
834 Size
aS(aMtf
.GetPrefSize());
836 aMtf
.Play(Application::GetDefaultDevice(), Point(0, 0),
839 WritePICFHeader(rStrm
, rFly
, 8, nWidth
, nHeight
,
840 pNd
->GetpSwAttrSet());
841 WriteWindowMetafileBits(rStrm
, aMtf
);
847 case ww8::Frame::eDrawing
:
848 case ww8::Frame::eTextBox
:
849 case ww8::Frame::eFormControl
:
851 #i3958# We only export an empty dummy picture frame here, this is
852 what word does the escher export should contain an anchored to
853 character element which is drawn over this dummy and the whole
854 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
858 WritePICFHeader(rStrm
, rFly
, 0x64, nWidth
, nHeight
);
859 SwBasicEscherEx
aInlineEscher(&rStrm
, rWrt
);
860 aInlineEscher
.WriteEmptyFlyFrame(rFly
.GetFrameFormat(), 0x401);
864 OSL_ENSURE(false, "Some inline export not implemented");
868 sal_uInt32 nPos2
= rStrm
.Tell(); // store the end
870 rStrm
.WriteUInt32(nPos2
- nPos
); // patch graphic length in the header
871 rStrm
.Seek( nPos2
); // restore Pos
874 // SwWW8WrGrf::Write() is called after the text.
875 // It writes out all the graphics and remembers the file locations of the graphics,
876 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
877 // The search in the attributes for the Magic sal_uLong and patching
878 // happens when writing the attributes. Class SwWW8WrGrf-Klasse provides with
879 // GetFPos() sequentially the positions
880 void SwWW8WrGrf::Write()
882 SvStream
& rStrm
= *rWrt
.pDataStrm
;
883 myiter aEnd
= maDetails
.end();
884 for (myiter aIter
= maDetails
.begin(); aIter
!= aEnd
; ++aIter
)
886 sal_uInt32 nPos
= rStrm
.Tell(); // align to 4 Bytes
888 SwWW8Writer::FillCount( rStrm
, 4 - ( nPos
& 0x3 ) );
890 bool bDuplicated
= false;
891 for (myiter aIter2
= maDetails
.begin(); aIter2
!= aIter
; ++aIter2
)
893 if (*aIter2
== *aIter
)
895 aIter
->mnPos
= aIter2
->mnPos
;
903 aIter
->mnPos
= rStrm
.Tell();
904 WriteGraphicNode(rStrm
, *aIter
);
909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */