00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qcstring.h>
00021 #include <qdom.h>
00022 #include <qfile.h>
00023 #include <qstring.h>
00024 #include <qvaluelist.h>
00025
00026 #include <kgenericfactory.h>
00027 #include <KoFilter.h>
00028 #include <KoFilterChain.h>
00029 #include <KoStore.h>
00030
00031 #include "svgexport.h"
00032 #include "vcolor.h"
00033 #include "vcomposite.h"
00034 #include "vdashpattern.h"
00035 #include "vdocument.h"
00036 #include "vfill.h"
00037 #include "vgradient.h"
00038 #include "vgroup.h"
00039 #include "vimage.h"
00040 #include "vlayer.h"
00041 #include "vpath.h"
00042 #include "vpattern.h"
00043 #include "vsegment.h"
00044 #include "vselection.h"
00045 #include "vstroke.h"
00046 #include "vtext.h"
00047 #include <commands/vtransformcmd.h>
00048
00049 #include <kdebug.h>
00050
00051 QString INDENT(" ");
00052
00053 void
00054 printIndentation( QTextStream *stream, unsigned int indent )
00055 {
00056 for( unsigned int i = 0; i < indent;++i)
00057 *stream << INDENT;
00058 }
00059
00060 typedef KGenericFactory<SvgExport, KoFilter> SvgExportFactory;
00061 K_EXPORT_COMPONENT_FACTORY( libkarbonsvgexport, SvgExportFactory( "kofficefilters" ) )
00062
00063
00064 SvgExport::SvgExport( KoFilter*, const char*, const QStringList& )
00065 : KoFilter(), m_indent( 0 ), m_indent2( 0 ), m_trans( 0L )
00066 {
00067 m_gc.setAutoDelete( true );
00068 }
00069
00070 KoFilter::ConversionStatus
00071 SvgExport::convert( const QCString& from, const QCString& to )
00072 {
00073 if ( to != "image/svg+xml" || from != "application/x-karbon" )
00074 {
00075 return KoFilter::NotImplemented;
00076 }
00077
00078 KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read );
00079 if( !storeIn )
00080 return KoFilter::StupidError;
00081
00082 QFile fileOut( m_chain->outputFile() );
00083 if( !fileOut.open( IO_WriteOnly ) )
00084 {
00085 delete storeIn;
00086 return KoFilter::StupidError;
00087 }
00088
00089 QDomDocument domIn;
00090 domIn.setContent( storeIn );
00091 QDomElement docNode = domIn.documentElement();
00092
00093 m_stream = new QTextStream( &fileOut );
00094 QString body;
00095 m_body = new QTextStream( &body, IO_ReadWrite );
00096 QString defs;
00097 m_defs = new QTextStream( &defs, IO_ReadWrite );
00098
00099
00100 VDocument doc;
00101 doc.load( docNode );
00102 doc.accept( *this );
00103
00104 *m_stream << defs;
00105 *m_stream << body;
00106
00107 fileOut.close();
00108
00109 delete m_stream;
00110 delete m_defs;
00111 delete m_body;
00112
00113 return KoFilter::OK;
00114 }
00115
00116 void
00117 SvgExport::visitVDocument( VDocument& document )
00118 {
00119
00120 document.selection()->append();
00121
00122
00123 KoRect rect( 0, 0, document.width(), document.height() );
00124
00125
00126 *m_defs <<
00127 "<?xml version=\"1.0\" standalone=\"no\"?>\n" <<
00128 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" " <<
00129 "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
00130 << endl;
00131
00132
00133 *m_defs <<
00134 "<!-- Created using Karbon14, part of koffice: http://www.koffice.org/karbon -->" << endl;
00135
00136 *m_defs <<
00137 "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"" <<
00138 rect.width() << "px\" height=\"" << rect.height() << "px\">" << endl;
00139 printIndentation( m_defs, ++m_indent2 );
00140 *m_defs << "<defs>" << endl;
00141
00142 m_indent++;
00143 m_indent2++;
00144
00145
00146 document.selection()->clear();
00147
00148
00149 SvgGraphicsContext *gc = new SvgGraphicsContext;
00150 m_gc.push( gc );
00151
00152 QWMatrix mat;
00153 mat.scale( 1, -1 );
00154 mat.translate( 0, -document.height() );
00155
00156 m_trans = new VTransformCmd( 0L, mat, false );
00157
00158
00159 VVisitor::visitVDocument( document );
00160
00161 delete m_trans;
00162 m_trans = 0L;
00163
00164
00165 printIndentation( m_defs, --m_indent2 );
00166 *m_defs << "</defs>" << endl;
00167 *m_body << "</svg>" << endl;
00168 }
00169
00170 QString
00171 SvgExport::getID( VObject *obj )
00172 {
00173 if( obj && !obj->name().isEmpty() )
00174 return QString( " id=\"%1\"" ).arg( obj->name() );
00175 return QString();
00176 }
00177
00178 void
00179 SvgExport::visitVGroup( VGroup& group )
00180 {
00181 printIndentation( m_body, m_indent++ );
00182 *m_body << "<g" << getID( &group ) << ">" << endl;
00183 VVisitor::visitVGroup( group );
00184 printIndentation( m_body, --m_indent );
00185 *m_body << "</g>" << endl;
00186 }
00187
00188
00189
00190 void
00191 SvgExport::visitVImage( VImage& image )
00192 {
00193 printIndentation( m_body, m_indent );
00194 *m_body << "<image ";
00195 VVisitor::visitVImage( image );
00196 *m_body << "x=\"" << "\" ";
00197 *m_body << "y=\"" << "\" ";
00198 *m_body << "width=\"" << "\" ";
00199 *m_body << "height=\"" << "\" ";
00200 *m_body << "xlink:href=\"" << "\"";
00201 *m_body << " />" << endl;
00202 }
00203
00204 void
00205 SvgExport::visitVLayer( VLayer& layer )
00206 {
00207 printIndentation( m_body, m_indent++ );
00208 *m_body << "<g" << getID( &layer ) << ">" << endl;
00209
00210 VVisitor::visitVLayer( layer );
00211 printIndentation( m_body, --m_indent );
00212 *m_body << "</g>" << endl;
00213 }
00214
00215 void
00216 SvgExport::writePathToStream( VPath &composite, const QString &id, QTextStream *stream, unsigned int indent )
00217 {
00218 if( ! stream )
00219 return;
00220
00221 printIndentation( stream, indent );
00222 *stream << "<path" << id;
00223
00224 VVisitor::visitVPath( composite );
00225
00226 getFill( *( composite.fill() ), stream );
00227 getStroke( *( composite.stroke() ), stream );
00228
00229 QString d;
00230 composite.saveSvgPath( d );
00231 *stream << " d=\"" << d << "\" ";
00232
00233 if( composite.fillRule() != m_gc.current()->fillRule )
00234 {
00235 if( composite.fillRule() == evenOdd )
00236 *stream << " fill-rule=\"evenodd\"";
00237 else
00238 *stream << " fill-rule=\"nonzero\"";
00239 }
00240
00241 *stream << " />" << endl;
00242 }
00243
00244 void
00245 SvgExport::visitVPath( VPath& composite )
00246 {
00247 m_trans->visitVPath( composite );
00248 writePathToStream( composite, getID( &composite ), m_body, m_indent );
00249 m_trans->visitVPath( composite );
00250 }
00251
00252 void
00253 SvgExport::visitVSubpath( VSubpath& )
00254 {
00255 }
00256
00257 QString createUID()
00258 {
00259 static unsigned int nr = 0;
00260
00261 return "defitem" + QString().setNum( nr++ );
00262 }
00263
00264 void
00265 SvgExport::getColorStops( const QPtrVector<VColorStop> &colorStops )
00266 {
00267 m_indent2++;
00268 for( unsigned int i = 0; i < colorStops.count() ; i++ )
00269 {
00270 printIndentation( m_defs, m_indent2 );
00271 *m_defs << "<stop stop-color=\"";
00272 getHexColor( m_defs, colorStops.at( i )->color );
00273 *m_defs << "\" offset=\"" << QString().setNum( colorStops.at( i )->rampPoint );
00274 *m_defs << "\" stop-opacity=\"" << colorStops.at( i )->color.opacity() << "\"" << " />" << endl;
00275 }
00276 m_indent2--;
00277 }
00278
00279 void
00280 SvgExport::getGradient( const VGradient& grad )
00281 {
00282 QString uid = createUID();
00283 if( grad.type() == VGradient::linear )
00284 {
00285 printIndentation( m_defs, m_indent2 );
00286
00287 *m_defs << "<linearGradient id=\"" << uid << "\" ";
00288 *m_defs << "gradientUnits=\"userSpaceOnUse\" ";
00289 *m_defs << "x1=\"" << grad.origin().x() << "\" ";
00290 *m_defs << "y1=\"" << grad.origin().y() << "\" ";
00291 *m_defs << "x2=\"" << grad.vector().x() << "\" ";
00292 *m_defs << "y2=\"" << grad.vector().y() << "\" ";
00293 if( grad.repeatMethod() == VGradient::reflect )
00294 *m_defs << "spreadMethod=\"reflect\" ";
00295 else if( grad.repeatMethod() == VGradient::repeat )
00296 *m_defs << "spreadMethod=\"repeat\" ";
00297 *m_defs << ">" << endl;
00298
00299
00300 getColorStops( grad.colorStops() );
00301
00302 printIndentation( m_defs, m_indent2 );
00303 *m_defs << "</linearGradient>" << endl;
00304 *m_body << "url(#" << uid << ")";
00305 }
00306 else if( grad.type() == VGradient::radial )
00307 {
00308
00309 printIndentation( m_defs, m_indent2 );
00310 *m_defs << "<radialGradient id=\"" << uid << "\" ";
00311 *m_defs << "gradientUnits=\"userSpaceOnUse\" ";
00312 *m_defs << "cx=\"" << grad.origin().x() << "\" ";
00313 *m_defs << "cy=\"" << grad.origin().y() << "\" ";
00314 *m_defs << "fx=\"" << grad.focalPoint().x() << "\" ";
00315 *m_defs << "fy=\"" << grad.focalPoint().y() << "\" ";
00316 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
00317 *m_defs << "r=\"" << QString().setNum( r ) << "\" ";
00318 if( grad.repeatMethod() == VGradient::reflect )
00319 *m_defs << "spreadMethod=\"reflect\" ";
00320 else if( grad.repeatMethod() == VGradient::repeat )
00321 *m_defs << "spreadMethod=\"repeat\" ";
00322 *m_defs << ">" << endl;
00323
00324
00325 getColorStops( grad.colorStops() );
00326
00327 printIndentation( m_defs, m_indent2 );
00328 *m_defs << "</radialGradient>" << endl;
00329 *m_body << "url(#" << uid << ")";
00330 }
00331
00332 else if( grad.type() == VGradient::conic )
00333 {
00334
00335
00336 printIndentation( m_defs, m_indent2 );
00337 *m_defs << "<radialGradient id=\"" << uid << "\" ";
00338 *m_defs << "gradientUnits=\"userSpaceOnUse\" ";
00339 *m_defs << "cx=\"" << grad.origin().x() << "\" ";
00340 *m_defs << "cy=\"" << grad.origin().y() << "\" ";
00341 *m_defs << "fx=\"" << grad.focalPoint().x() << "\" ";
00342 *m_defs << "fy=\"" << grad.focalPoint().y() << "\" ";
00343 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
00344 *m_defs << "r=\"" << QString().setNum( r ) << "\" ";
00345 if( grad.repeatMethod() == VGradient::reflect )
00346 *m_defs << "spreadMethod=\"reflect\" ";
00347 else if( grad.repeatMethod() == VGradient::repeat )
00348 *m_defs << "spreadMethod=\"repeat\" ";
00349 *m_defs << ">" << endl;
00350
00351
00352 getColorStops( grad.colorStops() );
00353
00354 printIndentation( m_defs, m_indent2 );
00355 *m_defs << "</radialGradient>" << endl;
00356 *m_body << "url(#" << uid << ")";
00357 }
00358 }
00359
00360
00361 void
00362 SvgExport::getPattern( const VPattern & )
00363 {
00364 QString uid = createUID();
00365 printIndentation( m_defs, m_indent2 );
00366 *m_defs << "<pattern id=\"" << uid << "\" ";
00367 *m_defs << "width=\"" << "\" ";
00368 *m_defs << "height=\"" << "\" ";
00369 *m_defs << "patternUnits=\"userSpaceOnUse\" ";
00370 *m_defs << "patternContentUnits=\"userSpaceOnUse\" ";
00371 *m_defs << " />" << endl;
00372
00373 printIndentation( m_defs, m_indent2 );
00374 *m_defs << "</pattern>" << endl;
00375 *m_body << "url(#" << uid << ")";
00376 }
00377
00378 void
00379 SvgExport::getFill( const VFill& fill, QTextStream *stream )
00380 {
00381 *stream << " fill=\"";
00382 if( fill.type() == VFill::none )
00383 *stream << "none";
00384 else if( fill.type() == VFill::grad )
00385 getGradient( fill.gradient() );
00386 else if( fill.type() == VFill::patt )
00387 getPattern( fill.pattern() );
00388 else
00389 getHexColor( stream, fill.color() );
00390 *stream << "\"";
00391
00392 if( fill.color().opacity() != m_gc.current()->fill.color().opacity() )
00393 *stream << " fill-opacity=\"" << fill.color().opacity() << "\"";
00394 }
00395
00396 void
00397 SvgExport::getStroke( const VStroke& stroke, QTextStream *stream )
00398 {
00399 if( stroke.type() != m_gc.current()->stroke.type() )
00400 {
00401 *stream << " stroke=\"";
00402 if( stroke.type() == VStroke::none )
00403 *stream << "none";
00404 else if( stroke.type() == VStroke::grad )
00405 getGradient( stroke.gradient() );
00406 else
00407 getHexColor( stream, stroke.color() );
00408 *stream << "\"";
00409 }
00410
00411 if( stroke.color().opacity() != m_gc.current()->stroke.color().opacity() )
00412 *stream << " stroke-opacity=\"" << stroke.color().opacity() << "\"";
00413
00414 if( stroke.lineWidth() != m_gc.current()->stroke.lineWidth() )
00415 *stream << " stroke-width=\"" << stroke.lineWidth() << "\"";
00416
00417 if( stroke.lineCap() != m_gc.current()->stroke.lineCap() )
00418 {
00419 if( stroke.lineCap() == VStroke::capButt )
00420 *stream << " stroke-linecap=\"butt\"";
00421 else if( stroke.lineCap() == VStroke::capRound )
00422 *stream << " stroke-linecap=\"round\"";
00423 else if( stroke.lineCap() == VStroke::capSquare )
00424 *stream << " stroke-linecap=\"square\"";
00425 }
00426
00427 if( stroke.lineJoin() != m_gc.current()->stroke.lineJoin() )
00428 {
00429 if( stroke.lineJoin() == VStroke::joinMiter )
00430 {
00431 *stream << " stroke-linejoin=\"miter\"";
00432 *stream << " stroke-miterlimit=\"" << stroke.miterLimit() << "\"";
00433 }
00434 else if( stroke.lineJoin() == VStroke::joinRound )
00435 *stream << " stroke-linejoin=\"round\"";
00436 else if( stroke.lineJoin() == VStroke::joinBevel )
00437 *stream << " stroke-linejoin=\"bevel\"";
00438 }
00439
00440
00441 if( stroke.dashPattern().array().count() > 0 )
00442 {
00443 *stream << " stroke-dashoffset=\"" << stroke.dashPattern().offset() << "\"";
00444 *stream << " stroke-dasharray=\" ";
00445
00446 QValueListConstIterator<float> itr;
00447 for(itr = stroke.dashPattern().array().begin(); itr != stroke.dashPattern().array().end(); ++itr )
00448 {
00449 *stream << *itr << " ";
00450 }
00451 *stream << "\"";
00452 }
00453 }
00454
00455 void
00456 SvgExport::getHexColor( QTextStream *stream, const VColor& color )
00457 {
00458
00459
00460 QString Output;
00461
00462 VColor copy( color );
00463 copy.setColorSpace( VColor::rgb );
00464
00465 Output.sprintf( "#%02x%02x%02x", int( copy[0] * 255.0 ), int( copy[1] * 255.0 ), int( copy[2] * 255.0 ) );
00466
00467 *stream << Output;
00468 }
00469
00470 void
00471 SvgExport::visitVText( VText& text )
00472 {
00473 VPath path( 0L );
00474 path.combinePath( text.basePath() );
00475
00476 m_trans->visitVPath( path );
00477
00478 QString id = createUID();
00479 writePathToStream( path, " id=\""+ id + "\"", m_defs, m_indent2 );
00480
00481 printIndentation( m_body, m_indent++ );
00482 *m_body << "<text" << getID( &text );
00483
00484 getFill( *( text.fill() ), m_body );
00485 getStroke( *( text.stroke() ), m_body );
00486
00487 *m_body << " font-family=\"" << text.font().family() << "\"";
00488 *m_body << " font-size=\"" << text.font().pointSize() << "\"";
00489 if( text.font().bold() )
00490 *m_body << " font-weight=\"bold\"";
00491 if( text.font().italic() )
00492 *m_body << " font-style=\"italic\"";
00493 if( text.alignment() == VText::Center )
00494 *m_body << " text-anchor=\"middle\"";
00495 else if( text.alignment() == VText::Right )
00496 *m_body << " text-anchor=\"end\"";
00497
00498 *m_body << ">" << endl;
00499
00500 printIndentation( m_body, m_indent );
00501 *m_body << "<textPath xlink:href=\"#" << id << "\"";
00502 if( text.offset() > 0.0 )
00503 *m_body << " startOffset=\"" << text.offset() * 100.0 << "%\"";
00504 *m_body << ">";
00505 *m_body << text.text();
00506 *m_body << "</textPath>" << endl;
00507 printIndentation( m_body, --m_indent );
00508 *m_body << "</text>" << endl;
00509 }
00510
00511 #include "svgexport.moc"
00512