1*ddde725dSArmin Le Grand /************************************************************** 2*ddde725dSArmin Le Grand * 3*ddde725dSArmin Le Grand * Licensed to the Apache Software Foundation (ASF) under one 4*ddde725dSArmin Le Grand * or more contributor license agreements. See the NOTICE file 5*ddde725dSArmin Le Grand * distributed with this work for additional information 6*ddde725dSArmin Le Grand * regarding copyright ownership. The ASF licenses this file 7*ddde725dSArmin Le Grand * to you under the Apache License, Version 2.0 (the 8*ddde725dSArmin Le Grand * "License"); you may not use this file except in compliance 9*ddde725dSArmin Le Grand * with the License. You may obtain a copy of the License at 10*ddde725dSArmin Le Grand * 11*ddde725dSArmin Le Grand * http://www.apache.org/licenses/LICENSE-2.0 12*ddde725dSArmin Le Grand * 13*ddde725dSArmin Le Grand * Unless required by applicable law or agreed to in writing, 14*ddde725dSArmin Le Grand * software distributed under the License is distributed on an 15*ddde725dSArmin Le Grand * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*ddde725dSArmin Le Grand * KIND, either express or implied. See the License for the 17*ddde725dSArmin Le Grand * specific language governing permissions and limitations 18*ddde725dSArmin Le Grand * under the License. 19*ddde725dSArmin Le Grand * 20*ddde725dSArmin Le Grand *************************************************************/ 21*ddde725dSArmin Le Grand 22*ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove 23*ddde725dSArmin Le Grand #include "precompiled_svgio.hxx" 24*ddde725dSArmin Le Grand 25*ddde725dSArmin Le Grand #include <svgio/svgreader/svgimagenode.hxx> 26*ddde725dSArmin Le Grand #include <svgio/svgreader/svgdocument.hxx> 27*ddde725dSArmin Le Grand #include <sax/tools/converter.hxx> 28*ddde725dSArmin Le Grand #include <tools/stream.hxx> 29*ddde725dSArmin Le Grand #include <vcl/bitmapex.hxx> 30*ddde725dSArmin Le Grand #include <svtools/filter.hxx> 31*ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx> 32*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 33*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/groupprimitive2d.hxx> 34*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 35*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 36*ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx> 37*ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx> 38*ddde725dSArmin Le Grand #include <rtl/uri.hxx> 39*ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx> 40*ddde725dSArmin Le Grand 41*ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 42*ddde725dSArmin Le Grand 43*ddde725dSArmin Le Grand namespace svgio 44*ddde725dSArmin Le Grand { 45*ddde725dSArmin Le Grand namespace svgreader 46*ddde725dSArmin Le Grand { 47*ddde725dSArmin Le Grand SvgImageNode::SvgImageNode( 48*ddde725dSArmin Le Grand SvgDocument& rDocument, 49*ddde725dSArmin Le Grand SvgNode* pParent) 50*ddde725dSArmin Le Grand : SvgNode(SVGTokenRect, rDocument, pParent), 51*ddde725dSArmin Le Grand maSvgStyleAttributes(*this), 52*ddde725dSArmin Le Grand maSvgAspectRatio(), 53*ddde725dSArmin Le Grand mpaTransform(0), 54*ddde725dSArmin Le Grand maX(0), 55*ddde725dSArmin Le Grand maY(0), 56*ddde725dSArmin Le Grand maWidth(0), 57*ddde725dSArmin Le Grand maHeight(0), 58*ddde725dSArmin Le Grand maXLink(), 59*ddde725dSArmin Le Grand maUrl(), 60*ddde725dSArmin Le Grand maMimeType(), 61*ddde725dSArmin Le Grand maData() 62*ddde725dSArmin Le Grand { 63*ddde725dSArmin Le Grand } 64*ddde725dSArmin Le Grand 65*ddde725dSArmin Le Grand SvgImageNode::~SvgImageNode() 66*ddde725dSArmin Le Grand { 67*ddde725dSArmin Le Grand if(mpaTransform) delete mpaTransform; 68*ddde725dSArmin Le Grand } 69*ddde725dSArmin Le Grand 70*ddde725dSArmin Le Grand const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const 71*ddde725dSArmin Le Grand { 72*ddde725dSArmin Le Grand static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image")); 73*ddde725dSArmin Le Grand maSvgStyleAttributes.checkForCssStyle(aClassStr); 74*ddde725dSArmin Le Grand 75*ddde725dSArmin Le Grand return &maSvgStyleAttributes; 76*ddde725dSArmin Le Grand } 77*ddde725dSArmin Le Grand 78*ddde725dSArmin Le Grand void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 79*ddde725dSArmin Le Grand { 80*ddde725dSArmin Le Grand // call parent 81*ddde725dSArmin Le Grand SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 82*ddde725dSArmin Le Grand 83*ddde725dSArmin Le Grand // read style attributes 84*ddde725dSArmin Le Grand maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 85*ddde725dSArmin Le Grand 86*ddde725dSArmin Le Grand // parse own 87*ddde725dSArmin Le Grand switch(aSVGToken) 88*ddde725dSArmin Le Grand { 89*ddde725dSArmin Le Grand case SVGTokenStyle: 90*ddde725dSArmin Le Grand { 91*ddde725dSArmin Le Grand maSvgStyleAttributes.readStyle(aContent); 92*ddde725dSArmin Le Grand break; 93*ddde725dSArmin Le Grand } 94*ddde725dSArmin Le Grand case SVGTokenPreserveAspectRatio: 95*ddde725dSArmin Le Grand { 96*ddde725dSArmin Le Grand setSvgAspectRatio(readSvgAspectRatio(aContent)); 97*ddde725dSArmin Le Grand break; 98*ddde725dSArmin Le Grand } 99*ddde725dSArmin Le Grand case SVGTokenTransform: 100*ddde725dSArmin Le Grand { 101*ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); 102*ddde725dSArmin Le Grand 103*ddde725dSArmin Le Grand if(!aMatrix.isIdentity()) 104*ddde725dSArmin Le Grand { 105*ddde725dSArmin Le Grand setTransform(&aMatrix); 106*ddde725dSArmin Le Grand } 107*ddde725dSArmin Le Grand break; 108*ddde725dSArmin Le Grand } 109*ddde725dSArmin Le Grand case SVGTokenX: 110*ddde725dSArmin Le Grand { 111*ddde725dSArmin Le Grand SvgNumber aNum; 112*ddde725dSArmin Le Grand 113*ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 114*ddde725dSArmin Le Grand { 115*ddde725dSArmin Le Grand setX(aNum); 116*ddde725dSArmin Le Grand } 117*ddde725dSArmin Le Grand break; 118*ddde725dSArmin Le Grand } 119*ddde725dSArmin Le Grand case SVGTokenY: 120*ddde725dSArmin Le Grand { 121*ddde725dSArmin Le Grand SvgNumber aNum; 122*ddde725dSArmin Le Grand 123*ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 124*ddde725dSArmin Le Grand { 125*ddde725dSArmin Le Grand setY(aNum); 126*ddde725dSArmin Le Grand } 127*ddde725dSArmin Le Grand break; 128*ddde725dSArmin Le Grand } 129*ddde725dSArmin Le Grand case SVGTokenWidth: 130*ddde725dSArmin Le Grand { 131*ddde725dSArmin Le Grand SvgNumber aNum; 132*ddde725dSArmin Le Grand 133*ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 134*ddde725dSArmin Le Grand { 135*ddde725dSArmin Le Grand if(aNum.isPositive()) 136*ddde725dSArmin Le Grand { 137*ddde725dSArmin Le Grand setWidth(aNum); 138*ddde725dSArmin Le Grand } 139*ddde725dSArmin Le Grand } 140*ddde725dSArmin Le Grand break; 141*ddde725dSArmin Le Grand } 142*ddde725dSArmin Le Grand case SVGTokenHeight: 143*ddde725dSArmin Le Grand { 144*ddde725dSArmin Le Grand SvgNumber aNum; 145*ddde725dSArmin Le Grand 146*ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 147*ddde725dSArmin Le Grand { 148*ddde725dSArmin Le Grand if(aNum.isPositive()) 149*ddde725dSArmin Le Grand { 150*ddde725dSArmin Le Grand setHeight(aNum); 151*ddde725dSArmin Le Grand } 152*ddde725dSArmin Le Grand } 153*ddde725dSArmin Le Grand break; 154*ddde725dSArmin Le Grand } 155*ddde725dSArmin Le Grand case SVGTokenXlinkHref: 156*ddde725dSArmin Le Grand { 157*ddde725dSArmin Le Grand const sal_Int32 nLen(aContent.getLength()); 158*ddde725dSArmin Le Grand 159*ddde725dSArmin Le Grand if(nLen) 160*ddde725dSArmin Le Grand { 161*ddde725dSArmin Le Grand readImageLink(aContent, maXLink, maUrl, maMimeType, maData); 162*ddde725dSArmin Le Grand } 163*ddde725dSArmin Le Grand break; 164*ddde725dSArmin Le Grand } 165*ddde725dSArmin Le Grand } 166*ddde725dSArmin Le Grand } 167*ddde725dSArmin Le Grand 168*ddde725dSArmin Le Grand void extractFromGraphic( 169*ddde725dSArmin Le Grand const Graphic& rGraphic, 170*ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence& rEmbedded, 171*ddde725dSArmin Le Grand basegfx::B2DRange& rViewBox, 172*ddde725dSArmin Le Grand BitmapEx& rBitmapEx) 173*ddde725dSArmin Le Grand { 174*ddde725dSArmin Le Grand if(GRAPHIC_BITMAP == rGraphic.GetType()) 175*ddde725dSArmin Le Grand { 176*ddde725dSArmin Le Grand if(rGraphic.getSvgData().get()) 177*ddde725dSArmin Le Grand { 178*ddde725dSArmin Le Grand // embedded Svg 179*ddde725dSArmin Le Grand rEmbedded = rGraphic.getSvgData()->getPrimitive2DSequence(); 180*ddde725dSArmin Le Grand 181*ddde725dSArmin Le Grand // fill aViewBox 182*ddde725dSArmin Le Grand rViewBox = rGraphic.getSvgData()->getRange(); 183*ddde725dSArmin Le Grand } 184*ddde725dSArmin Le Grand else 185*ddde725dSArmin Le Grand { 186*ddde725dSArmin Le Grand // get bitmap 187*ddde725dSArmin Le Grand rBitmapEx = rGraphic.GetBitmapEx(); 188*ddde725dSArmin Le Grand } 189*ddde725dSArmin Le Grand } 190*ddde725dSArmin Le Grand else 191*ddde725dSArmin Le Grand { 192*ddde725dSArmin Le Grand // evtl. convert to bitmap 193*ddde725dSArmin Le Grand rBitmapEx = rGraphic.GetBitmapEx(); 194*ddde725dSArmin Le Grand } 195*ddde725dSArmin Le Grand } 196*ddde725dSArmin Le Grand 197*ddde725dSArmin Le Grand void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 198*ddde725dSArmin Le Grand { 199*ddde725dSArmin Le Grand // get size range and create path 200*ddde725dSArmin Le Grand const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); 201*ddde725dSArmin Le Grand 202*ddde725dSArmin Le Grand if(pStyle && getWidth().isSet() && getHeight().isSet()) 203*ddde725dSArmin Le Grand { 204*ddde725dSArmin Le Grand const double fWidth(getWidth().solve(*this, xcoordinate)); 205*ddde725dSArmin Le Grand const double fHeight(getHeight().solve(*this, ycoordinate)); 206*ddde725dSArmin Le Grand 207*ddde725dSArmin Le Grand if(fWidth > 0.0 && fHeight > 0.0) 208*ddde725dSArmin Le Grand { 209*ddde725dSArmin Le Grand BitmapEx aBitmapEx; 210*ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 211*ddde725dSArmin Le Grand 212*ddde725dSArmin Le Grand // prepare Target and ViewBox for evtl. AspectRatio mappings 213*ddde725dSArmin Le Grand const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); 214*ddde725dSArmin Le Grand const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); 215*ddde725dSArmin Le Grand const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight); 216*ddde725dSArmin Le Grand basegfx::B2DRange aViewBox(aTarget); 217*ddde725dSArmin Le Grand 218*ddde725dSArmin Le Grand if(maMimeType.getLength() && maData.getLength()) 219*ddde725dSArmin Le Grand { 220*ddde725dSArmin Le Grand // use embedded base64 encoded data 221*ddde725dSArmin Le Grand ::com::sun::star::uno::Sequence< sal_Int8 > aPass; 222*ddde725dSArmin Le Grand ::sax::Converter::decodeBase64(aPass, maData); 223*ddde725dSArmin Le Grand 224*ddde725dSArmin Le Grand if(aPass.hasElements()) 225*ddde725dSArmin Le Grand { 226*ddde725dSArmin Le Grand SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), STREAM_READ); 227*ddde725dSArmin Le Grand Graphic aGraphic; 228*ddde725dSArmin Le Grand 229*ddde725dSArmin Le Grand if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic( 230*ddde725dSArmin Le Grand aGraphic, 231*ddde725dSArmin Le Grand String(), 232*ddde725dSArmin Le Grand aStream)) 233*ddde725dSArmin Le Grand { 234*ddde725dSArmin Le Grand extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); 235*ddde725dSArmin Le Grand } 236*ddde725dSArmin Le Grand } 237*ddde725dSArmin Le Grand } 238*ddde725dSArmin Le Grand else if(maUrl.getLength()) 239*ddde725dSArmin Le Grand { 240*ddde725dSArmin Le Grand const rtl::OUString& rPath = getDocument().getAbsolutePath(); 241*ddde725dSArmin Le Grand const rtl::OUString aAbsUrl(rtl::Uri::convertRelToAbs(rPath, maUrl)); 242*ddde725dSArmin Le Grand 243*ddde725dSArmin Le Grand if(aAbsUrl.getLength()) 244*ddde725dSArmin Le Grand { 245*ddde725dSArmin Le Grand SvFileStream aStream(aAbsUrl, STREAM_STD_READ); 246*ddde725dSArmin Le Grand Graphic aGraphic; 247*ddde725dSArmin Le Grand 248*ddde725dSArmin Le Grand if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic( 249*ddde725dSArmin Le Grand aGraphic, 250*ddde725dSArmin Le Grand aAbsUrl, 251*ddde725dSArmin Le Grand aStream)) 252*ddde725dSArmin Le Grand { 253*ddde725dSArmin Le Grand extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); 254*ddde725dSArmin Le Grand } 255*ddde725dSArmin Le Grand } 256*ddde725dSArmin Le Grand } 257*ddde725dSArmin Le Grand else if(maXLink.getLength()) 258*ddde725dSArmin Le Grand { 259*ddde725dSArmin Le Grand const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink); 260*ddde725dSArmin Le Grand 261*ddde725dSArmin Le Grand if(mpXLink) 262*ddde725dSArmin Le Grand { 263*ddde725dSArmin Le Grand mpXLink->decomposeSvgNode(aNewTarget, true); 264*ddde725dSArmin Le Grand 265*ddde725dSArmin Le Grand if(aNewTarget.hasElements()) 266*ddde725dSArmin Le Grand { 267*ddde725dSArmin Le Grand aViewBox = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 268*ddde725dSArmin Le Grand aNewTarget, 269*ddde725dSArmin Le Grand drawinglayer::geometry::ViewInformation2D()); 270*ddde725dSArmin Le Grand } 271*ddde725dSArmin Le Grand } 272*ddde725dSArmin Le Grand } 273*ddde725dSArmin Le Grand 274*ddde725dSArmin Le Grand if(!aBitmapEx.IsEmpty()) 275*ddde725dSArmin Le Grand { 276*ddde725dSArmin Le Grand // create content from created bitmap 277*ddde725dSArmin Le Grand aNewTarget.realloc(1); 278*ddde725dSArmin Le Grand aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D( 279*ddde725dSArmin Le Grand aBitmapEx, 280*ddde725dSArmin Le Grand basegfx::B2DHomMatrix()); 281*ddde725dSArmin Le Grand 282*ddde725dSArmin Le Grand // fill aViewBox. No size set yet, use unit size 283*ddde725dSArmin Le Grand aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); 284*ddde725dSArmin Le Grand } 285*ddde725dSArmin Le Grand 286*ddde725dSArmin Le Grand if(aNewTarget.hasElements()) 287*ddde725dSArmin Le Grand { 288*ddde725dSArmin Le Grand if(aTarget.equal(aViewBox)) 289*ddde725dSArmin Le Grand { 290*ddde725dSArmin Le Grand // just add to rTarget 291*ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); 292*ddde725dSArmin Le Grand } 293*ddde725dSArmin Le Grand else 294*ddde725dSArmin Le Grand { 295*ddde725dSArmin Le Grand // create mapping 296*ddde725dSArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio(); 297*ddde725dSArmin Le Grand 298*ddde725dSArmin Le Grand if(rRatio.isSet()) 299*ddde725dSArmin Le Grand { 300*ddde725dSArmin Le Grand // let mapping be created from SvgAspectRatio 301*ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox)); 302*ddde725dSArmin Le Grand 303*ddde725dSArmin Le Grand if(!aEmbeddingTransform.isIdentity()) 304*ddde725dSArmin Le Grand { 305*ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 306*ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 307*ddde725dSArmin Le Grand aEmbeddingTransform, 308*ddde725dSArmin Le Grand aNewTarget)); 309*ddde725dSArmin Le Grand 310*ddde725dSArmin Le Grand aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 311*ddde725dSArmin Le Grand } 312*ddde725dSArmin Le Grand 313*ddde725dSArmin Le Grand if(!rRatio.isMeetOrSlice()) 314*ddde725dSArmin Le Grand { 315*ddde725dSArmin Le Grand // need to embed in MaskPrimitive2D to ensure clipping 316*ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 317*ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 318*ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 319*ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect(aTarget)), 320*ddde725dSArmin Le Grand aNewTarget)); 321*ddde725dSArmin Le Grand 322*ddde725dSArmin Le Grand aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); 323*ddde725dSArmin Le Grand } 324*ddde725dSArmin Le Grand } 325*ddde725dSArmin Le Grand else 326*ddde725dSArmin Le Grand { 327*ddde725dSArmin Le Grand // choose default mapping 328*ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createLinearMapping(aTarget, aViewBox)); 329*ddde725dSArmin Le Grand 330*ddde725dSArmin Le Grand if(!aEmbeddingTransform.isIdentity()) 331*ddde725dSArmin Le Grand { 332*ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 333*ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 334*ddde725dSArmin Le Grand aEmbeddingTransform, 335*ddde725dSArmin Le Grand aNewTarget)); 336*ddde725dSArmin Le Grand 337*ddde725dSArmin Le Grand aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 338*ddde725dSArmin Le Grand } 339*ddde725dSArmin Le Grand } 340*ddde725dSArmin Le Grand 341*ddde725dSArmin Le Grand // embed and add to rTarget, take local extra-transform into account 342*ddde725dSArmin Le Grand pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); 343*ddde725dSArmin Le Grand } 344*ddde725dSArmin Le Grand } 345*ddde725dSArmin Le Grand } 346*ddde725dSArmin Le Grand } 347*ddde725dSArmin Le Grand } 348*ddde725dSArmin Le Grand 349*ddde725dSArmin Le Grand } // end of namespace svgreader 350*ddde725dSArmin Le Grand } // end of namespace svgio 351*ddde725dSArmin Le Grand 352*ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 353*ddde725dSArmin Le Grand // eof 354