/* This file is part of the KDE project Copyright (C) 2002, 2003 The Karbon Developers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "svgexport.h" #include "vcolor.h" #include "vcomposite.h" #include "vdashpattern.h" #include "vdocument.h" #include "vfill.h" #include "vgradient.h" #include "vgroup.h" #include "vimage.h" #include "vlayer.h" #include "vpath.h" #include "vpattern.h" #include "vsegment.h" #include "vselection.h" #include "vstroke.h" #include "vtext.h" #include #include TQString INDENT(" "); void printIndentation( TQTextStream *stream, unsigned int indent ) { for( unsigned int i = 0; i < indent;++i) *stream << INDENT; } typedef KGenericFactory SvgExportFactory; K_EXPORT_COMPONENT_FACTORY( libkarbonsvgexport, SvgExportFactory( "kofficefilters" ) ) SvgExport::SvgExport( KoFilter*, const char*, const TQStringList& ) : KoFilter(), m_indent( 0 ), m_indent2( 0 ), m_trans( 0L ) { m_gc.setAutoDelete( true ); } KoFilter::ConversionStatus SvgExport::convert( const TQCString& from, const TQCString& to ) { if ( to != "image/svg+xml" || from != "application/x-karbon" ) { return KoFilter::NotImplemented; } KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read ); if( !storeIn ) return KoFilter::StupidError; TQFile fileOut( m_chain->outputFile() ); if( !fileOut.open( IO_WriteOnly ) ) { delete storeIn; return KoFilter::StupidError; } TQDomDocument domIn; domIn.setContent( storeIn ); TQDomElement docNode = domIn.documentElement(); m_stream = new TQTextStream( &fileOut ); TQString body; m_body = new TQTextStream( &body, IO_ReadWrite ); TQString defs; m_defs = new TQTextStream( &defs, IO_ReadWrite ); // load the document and export it: VDocument doc; doc.load( docNode ); doc.accept( *this ); *m_stream << defs; *m_stream << body; fileOut.close(); delete m_stream; delete m_defs; delete m_body; return KoFilter::OK; } void SvgExport::visitVDocument( VDocument& document ) { // select all objects: document.selection()->append(); // get the bounding box of the page KoRect rect( 0, 0, document.width(), document.height() ); // standard header: *m_defs << "\n" << "" << endl; // add some PR. one line is more than enough. *m_defs << "" << endl; *m_defs << "" << endl; printIndentation( m_defs, ++m_indent2 ); *m_defs << "" << endl; m_indent++; m_indent2++; // we dont need the selection anymore: document.selection()->clear(); // set up gc SvgGraphicsContext *gc = new SvgGraphicsContext; m_gc.push( gc ); TQWMatrix mat; mat.scale( 1, -1 ); mat.translate( 0, -document.height() ); m_trans = new VTransformCmd( 0L, mat, false ); // export layers: VVisitor::visitVDocument( document ); delete m_trans; m_trans = 0L; // end tag: printIndentation( m_defs, --m_indent2 ); *m_defs << "" << endl; *m_body << "" << endl; } TQString SvgExport::getID( VObject *obj ) { if( obj && !obj->name().isEmpty() ) return TQString( " id=\"%1\"" ).arg( obj->name() ); return TQString(); } void SvgExport::visitVGroup( VGroup& group ) { printIndentation( m_body, m_indent++ ); *m_body << "" << endl; VVisitor::visitVGroup( group ); printIndentation( m_body, --m_indent ); *m_body << "" << endl; } // horrible but at least something gets exported now // will need this for patterns void SvgExport::visitVImage( VImage& image ) { printIndentation( m_body, m_indent ); *m_body << "" << endl; } void SvgExport::visitVLayer( VLayer& layer ) { printIndentation( m_body, m_indent++ ); *m_body << "" << endl; //*m_body << " transform=\"scale(1, -1) translate(0, -" << layer.document()->height() << ")\">" << endl; VVisitor::visitVLayer( layer ); printIndentation( m_body, --m_indent ); *m_body << "" << endl; } void SvgExport::writePathToStream( VPath &composite, const TQString &id, TQTextStream *stream, unsigned int indent ) { if( ! stream ) return; printIndentation( stream, indent ); *stream << "fillRule ) { if( composite.fillRule() == evenOdd ) *stream << " fill-rule=\"evenodd\""; else *stream << " fill-rule=\"nonzero\""; } *stream << " />" << endl; } void SvgExport::visitVPath( VPath& composite ) { m_trans->visitVPath( composite ); writePathToStream( composite, getID( &composite ), m_body, m_indent ); m_trans->visitVPath( composite ); } void SvgExport::visitVSubpath( VSubpath& ) { } TQString createUID() { static unsigned int nr = 0; return "defitem" + TQString().setNum( nr++ ); } void SvgExport::getColorStops( const TQPtrVector &colorStops ) { m_indent2++; for( unsigned int i = 0; i < colorStops.count() ; i++ ) { printIndentation( m_defs, m_indent2 ); *m_defs << "color ); *m_defs << "\" offset=\"" << TQString().setNum( colorStops.at( i )->rampPoint ); *m_defs << "\" stop-opacity=\"" << colorStops.at( i )->color.opacity() << "\"" << " />" << endl; } m_indent2--; } void SvgExport::getGradient( const VGradient& grad ) { TQString uid = createUID(); if( grad.type() == VGradient::linear ) { printIndentation( m_defs, m_indent2 ); // do linear grad *m_defs << "" << endl; // color stops getColorStops( grad.colorStops() ); printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; *m_body << "url(#" << uid << ")"; } else if( grad.type() == VGradient::radial ) { // do radial grad printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; // color stops getColorStops( grad.colorStops() ); printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; *m_body << "url(#" << uid << ")"; } // gah! pointless abbreviation of conical to conic else if( grad.type() == VGradient::conic ) { // fake conical grad as radial. // fugly but better than data loss. printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; // color stops getColorStops( grad.colorStops() ); printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; *m_body << "url(#" << uid << ")"; } } // better than nothing void SvgExport::getPattern( const VPattern & ) { TQString uid = createUID(); printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; // TODO: insert hard work here ;) printIndentation( m_defs, m_indent2 ); *m_defs << "" << endl; *m_body << "url(#" << uid << ")"; } void SvgExport::getFill( const VFill& fill, TQTextStream *stream ) { *stream << " fill=\""; if( fill.type() == VFill::none ) *stream << "none"; else if( fill.type() == VFill::grad ) getGradient( fill.gradient() ); else if( fill.type() == VFill::patt ) getPattern( fill.pattern() ); else getHexColor( stream, fill.color() ); *stream << "\""; if( fill.color().opacity() != m_gc.current()->fill.color().opacity() ) *stream << " fill-opacity=\"" << fill.color().opacity() << "\""; } void SvgExport::getStroke( const VStroke& stroke, TQTextStream *stream ) { if( stroke.type() != m_gc.current()->stroke.type() ) { *stream << " stroke=\""; if( stroke.type() == VStroke::none ) *stream << "none"; else if( stroke.type() == VStroke::grad ) getGradient( stroke.gradient() ); else getHexColor( stream, stroke.color() ); *stream << "\""; } if( stroke.color().opacity() != m_gc.current()->stroke.color().opacity() ) *stream << " stroke-opacity=\"" << stroke.color().opacity() << "\""; if( stroke.lineWidth() != m_gc.current()->stroke.lineWidth() ) *stream << " stroke-width=\"" << stroke.lineWidth() << "\""; if( stroke.lineCap() != m_gc.current()->stroke.lineCap() ) { if( stroke.lineCap() == VStroke::capButt ) *stream << " stroke-linecap=\"butt\""; else if( stroke.lineCap() == VStroke::capRound ) *stream << " stroke-linecap=\"round\""; else if( stroke.lineCap() == VStroke::capSquare ) *stream << " stroke-linecap=\"square\""; } if( stroke.lineJoin() != m_gc.current()->stroke.lineJoin() ) { if( stroke.lineJoin() == VStroke::joinMiter ) { *stream << " stroke-linejoin=\"miter\""; *stream << " stroke-miterlimit=\"" << stroke.miterLimit() << "\""; } else if( stroke.lineJoin() == VStroke::joinRound ) *stream << " stroke-linejoin=\"round\""; else if( stroke.lineJoin() == VStroke::joinBevel ) *stream << " stroke-linejoin=\"bevel\""; } // dash if( stroke.dashPattern().array().count() > 0 ) { *stream << " stroke-dashoffset=\"" << stroke.dashPattern().offset() << "\""; *stream << " stroke-dasharray=\" "; TQValueListConstIterator itr; for(itr = stroke.dashPattern().array().begin(); itr != stroke.dashPattern().array().end(); ++itr ) { *stream << *itr << " "; } *stream << "\""; } } void SvgExport::getHexColor( TQTextStream *stream, const VColor& color ) { // Convert the various color-spaces to hex TQString Output; VColor copy( color ); copy.setColorSpace( VColor::rgb ); Output.sprintf( "#%02x%02x%02x", int( copy[0] * 255.0 ), int( copy[1] * 255.0 ), int( copy[2] * 255.0 ) ); *stream << Output; } void SvgExport::visitVText( VText& text ) { VPath path( 0L ); path.combinePath( text.basePath() ); m_trans->visitVPath( path ); TQString id = createUID(); writePathToStream( path, " id=\""+ id + "\"", m_defs, m_indent2 ); printIndentation( m_body, m_indent++ ); *m_body << "height() << ")\""; getFill( *( text.fill() ), m_body ); getStroke( *( text.stroke() ), m_body ); *m_body << " font-family=\"" << text.font().family() << "\""; *m_body << " font-size=\"" << text.font().pointSize() << "\""; if( text.font().bold() ) *m_body << " font-weight=\"bold\""; if( text.font().italic() ) *m_body << " font-style=\"italic\""; if( text.alignment() == VText::Center ) *m_body << " text-anchor=\"middle\""; else if( text.alignment() == VText::Right ) *m_body << " text-anchor=\"end\""; *m_body << ">" << endl; printIndentation( m_body, m_indent ); *m_body << " 0.0 ) *m_body << " startOffset=\"" << text.offset() * 100.0 << "%\""; *m_body << ">"; *m_body << text.text(); *m_body << "" << endl; printIndentation( m_body, --m_indent ); *m_body << "" << endl; } #include "svgexport.moc"