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