24#include <tqvaluelist.h>
26#include <kgenericfactory.h>
28#include <KoFilterChain.h>
33#include "vcomposite.h"
34#include "vdashpattern.h"
44#include "vselection.h"
47#include <commands/vtransformcmd.h>
54printIndentation( TQTextStream *stream,
unsigned int indent )
56 for(
unsigned int i = 0; i < indent;++i)
60typedef KGenericFactory<SvgExport, KoFilter> SvgExportFactory;
61K_EXPORT_COMPONENT_FACTORY( libkarbonsvgexport, SvgExportFactory(
"kofficefilters" ) )
64SvgExport::SvgExport( KoFilter*, const
char*, const TQStringList& )
65 : KoFilter(), m_indent( 0 ), m_indent2( 0 ), m_trans( 0L )
67 m_gc.setAutoDelete(
true );
70KoFilter::ConversionStatus
71SvgExport::convert(
const TQCString& from,
const TQCString& to )
73 if ( to !=
"image/svg+xml" || from !=
"application/x-karbon" )
75 return KoFilter::NotImplemented;
78 KoStoreDevice* storeIn = m_chain->storageFile(
"root", KoStore::Read );
80 return KoFilter::StupidError;
82 TQFile fileOut( m_chain->outputFile() );
83 if( !fileOut.open( IO_WriteOnly ) )
86 return KoFilter::StupidError;
90 domIn.setContent( storeIn );
91 TQDomElement docNode = domIn.documentElement();
93 m_stream =
new TQTextStream( &fileOut );
95 m_body =
new TQTextStream( &body, IO_ReadWrite );
97 m_defs =
new TQTextStream( &defs, IO_ReadWrite );
117SvgExport::visitVDocument( VDocument& document )
120 document.selection()->append();
123 KoRect rect( 0, 0, document.width(), document.height() );
127 "<?xml version=\"1.0\" standalone=\"no\"?>\n" <<
128 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" " <<
129 "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
134 "<!-- Created using Karbon14, part of koffice: http://www.trinitydesktop.org -->" << endl;
137 "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"" <<
138 rect.width() <<
"px\" height=\"" << rect.height() <<
"px\">" << endl;
139 printIndentation( m_defs, ++m_indent2 );
140 *m_defs <<
"<defs>" << endl;
146 document.selection()->clear();
149 SvgGraphicsContext *gc =
new SvgGraphicsContext;
154 mat.translate( 0, -document.height() );
156 m_trans =
new VTransformCmd( 0L, mat,
false );
159 VVisitor::visitVDocument( document );
165 printIndentation( m_defs, --m_indent2 );
166 *m_defs <<
"</defs>" << endl;
167 *m_body <<
"</svg>" << endl;
171SvgExport::getID( VObject *obj )
173 if( obj && !obj->name().isEmpty() )
174 return TQString(
" id=\"%1\"" ).arg( obj->name() );
179SvgExport::visitVGroup( VGroup& group )
181 printIndentation( m_body, m_indent++ );
182 *m_body <<
"<g" << getID( &group ) <<
">" << endl;
183 VVisitor::visitVGroup( group );
184 printIndentation( m_body, --m_indent );
185 *m_body <<
"</g>" << endl;
191SvgExport::visitVImage( VImage& image )
193 printIndentation( m_body, m_indent );
194 *m_body <<
"<image ";
195 VVisitor::visitVImage( image );
196 *m_body <<
"x=\"" <<
"\" ";
197 *m_body <<
"y=\"" <<
"\" ";
198 *m_body <<
"width=\"" <<
"\" ";
199 *m_body <<
"height=\"" <<
"\" ";
200 *m_body <<
"xlink:href=\"" <<
"\"";
201 *m_body <<
" />" << endl;
205SvgExport::visitVLayer( VLayer& layer )
207 printIndentation( m_body, m_indent++ );
208 *m_body <<
"<g" << getID( &layer ) <<
">" << endl;
210 VVisitor::visitVLayer( layer );
211 printIndentation( m_body, --m_indent );
212 *m_body <<
"</g>" << endl;
216SvgExport::writePathToStream( VPath &composite,
const TQString &
id, TQTextStream *stream,
unsigned int indent )
221 printIndentation( stream, indent );
222 *stream <<
"<path" << id;
224 VVisitor::visitVPath( composite );
226 getFill( *( composite.fill() ), stream );
227 getStroke( *( composite.stroke() ), stream );
230 composite.saveSvgPath( d );
231 *stream <<
" d=\"" << d <<
"\" ";
233 if( composite.fillRule() != m_gc.current()->fillRule )
235 if( composite.fillRule() == evenOdd )
236 *stream <<
" fill-rule=\"evenodd\"";
238 *stream <<
" fill-rule=\"nonzero\"";
241 *stream <<
" />" << endl;
245SvgExport::visitVPath( VPath& composite )
247 m_trans->visitVPath( composite );
248 writePathToStream( composite, getID( &composite ), m_body, m_indent );
249 m_trans->visitVPath( composite );
253SvgExport::visitVSubpath( VSubpath& )
259 static unsigned int nr = 0;
261 return "defitem" + TQString().setNum( nr++ );
265SvgExport::getColorStops(
const TQPtrVector<VColorStop> &colorStops )
268 for(
unsigned int i = 0; i < colorStops.count() ; i++ )
270 printIndentation( m_defs, m_indent2 );
271 *m_defs <<
"<stop stop-color=\"";
272 getHexColor( m_defs, colorStops.at( i )->color );
273 *m_defs <<
"\" offset=\"" << TQString().setNum( colorStops.at( i )->rampPoint );
274 *m_defs <<
"\" stop-opacity=\"" << colorStops.at( i )->color.opacity() <<
"\"" <<
" />" << endl;
280SvgExport::getGradient(
const VGradient& grad )
282 TQString uid = createUID();
283 if( grad.type() == VGradient::linear )
285 printIndentation( m_defs, m_indent2 );
287 *m_defs <<
"<linearGradient id=\"" << uid <<
"\" ";
288 *m_defs <<
"gradientUnits=\"userSpaceOnUse\" ";
289 *m_defs <<
"x1=\"" << grad.origin().x() <<
"\" ";
290 *m_defs <<
"y1=\"" << grad.origin().y() <<
"\" ";
291 *m_defs <<
"x2=\"" << grad.vector().x() <<
"\" ";
292 *m_defs <<
"y2=\"" << grad.vector().y() <<
"\" ";
293 if( grad.repeatMethod() == VGradient::reflect )
294 *m_defs <<
"spreadMethod=\"reflect\" ";
295 else if( grad.repeatMethod() == VGradient::repeat )
296 *m_defs <<
"spreadMethod=\"repeat\" ";
297 *m_defs <<
">" << endl;
300 getColorStops( grad.colorStops() );
302 printIndentation( m_defs, m_indent2 );
303 *m_defs <<
"</linearGradient>" << endl;
304 *m_body <<
"url(#" << uid <<
")";
306 else if( grad.type() == VGradient::radial )
309 printIndentation( m_defs, m_indent2 );
310 *m_defs <<
"<radialGradient id=\"" << uid <<
"\" ";
311 *m_defs <<
"gradientUnits=\"userSpaceOnUse\" ";
312 *m_defs <<
"cx=\"" << grad.origin().x() <<
"\" ";
313 *m_defs <<
"cy=\"" << grad.origin().y() <<
"\" ";
314 *m_defs <<
"fx=\"" << grad.focalPoint().x() <<
"\" ";
315 *m_defs <<
"fy=\"" << grad.focalPoint().y() <<
"\" ";
316 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
317 *m_defs <<
"r=\"" << TQString().setNum( r ) <<
"\" ";
318 if( grad.repeatMethod() == VGradient::reflect )
319 *m_defs <<
"spreadMethod=\"reflect\" ";
320 else if( grad.repeatMethod() == VGradient::repeat )
321 *m_defs <<
"spreadMethod=\"repeat\" ";
322 *m_defs <<
">" << endl;
325 getColorStops( grad.colorStops() );
327 printIndentation( m_defs, m_indent2 );
328 *m_defs <<
"</radialGradient>" << endl;
329 *m_body <<
"url(#" << uid <<
")";
332 else if( grad.type() == VGradient::conic )
336 printIndentation( m_defs, m_indent2 );
337 *m_defs <<
"<radialGradient id=\"" << uid <<
"\" ";
338 *m_defs <<
"gradientUnits=\"userSpaceOnUse\" ";
339 *m_defs <<
"cx=\"" << grad.origin().x() <<
"\" ";
340 *m_defs <<
"cy=\"" << grad.origin().y() <<
"\" ";
341 *m_defs <<
"fx=\"" << grad.focalPoint().x() <<
"\" ";
342 *m_defs <<
"fy=\"" << grad.focalPoint().y() <<
"\" ";
343 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
344 *m_defs <<
"r=\"" << TQString().setNum( r ) <<
"\" ";
345 if( grad.repeatMethod() == VGradient::reflect )
346 *m_defs <<
"spreadMethod=\"reflect\" ";
347 else if( grad.repeatMethod() == VGradient::repeat )
348 *m_defs <<
"spreadMethod=\"repeat\" ";
349 *m_defs <<
">" << endl;
352 getColorStops( grad.colorStops() );
354 printIndentation( m_defs, m_indent2 );
355 *m_defs <<
"</radialGradient>" << endl;
356 *m_body <<
"url(#" << uid <<
")";
362SvgExport::getPattern(
const VPattern & )
364 TQString uid = createUID();
365 printIndentation( m_defs, m_indent2 );
366 *m_defs <<
"<pattern id=\"" << uid <<
"\" ";
367 *m_defs <<
"width=\"" <<
"\" ";
368 *m_defs <<
"height=\"" <<
"\" ";
369 *m_defs <<
"patternUnits=\"userSpaceOnUse\" ";
370 *m_defs <<
"patternContentUnits=\"userSpaceOnUse\" ";
371 *m_defs <<
" />" << endl;
373 printIndentation( m_defs, m_indent2 );
374 *m_defs <<
"</pattern>" << endl;
375 *m_body <<
"url(#" << uid <<
")";
379SvgExport::getFill(
const VFill& fill, TQTextStream *stream )
381 *stream <<
" fill=\"";
382 if( fill.type() == VFill::none )
384 else if( fill.type() == VFill::grad )
385 getGradient( fill.gradient() );
386 else if( fill.type() == VFill::patt )
387 getPattern( fill.pattern() );
389 getHexColor( stream, fill.color() );
392 if( fill.color().opacity() != m_gc.current()->fill.color().opacity() )
393 *stream <<
" fill-opacity=\"" << fill.color().opacity() <<
"\"";
397SvgExport::getStroke(
const VStroke& stroke, TQTextStream *stream )
399 if( stroke.type() != m_gc.current()->stroke.type() )
401 *stream <<
" stroke=\"";
402 if( stroke.type() == VStroke::none )
404 else if( stroke.type() == VStroke::grad )
405 getGradient( stroke.gradient() );
407 getHexColor( stream, stroke.color() );
411 if( stroke.color().opacity() != m_gc.current()->stroke.color().opacity() )
412 *stream <<
" stroke-opacity=\"" << stroke.color().opacity() <<
"\"";
414 if( stroke.lineWidth() != m_gc.current()->stroke.lineWidth() )
415 *stream <<
" stroke-width=\"" << stroke.lineWidth() <<
"\"";
417 if( stroke.lineCap() != m_gc.current()->stroke.lineCap() )
419 if( stroke.lineCap() == VStroke::capButt )
420 *stream <<
" stroke-linecap=\"butt\"";
421 else if( stroke.lineCap() == VStroke::capRound )
422 *stream <<
" stroke-linecap=\"round\"";
423 else if( stroke.lineCap() == VStroke::capSquare )
424 *stream <<
" stroke-linecap=\"square\"";
427 if( stroke.lineJoin() != m_gc.current()->stroke.lineJoin() )
429 if( stroke.lineJoin() == VStroke::joinMiter )
431 *stream <<
" stroke-linejoin=\"miter\"";
432 *stream <<
" stroke-miterlimit=\"" << stroke.miterLimit() <<
"\"";
434 else if( stroke.lineJoin() == VStroke::joinRound )
435 *stream <<
" stroke-linejoin=\"round\"";
436 else if( stroke.lineJoin() == VStroke::joinBevel )
437 *stream <<
" stroke-linejoin=\"bevel\"";
441 if( stroke.dashPattern().array().count() > 0 )
443 *stream <<
" stroke-dashoffset=\"" << stroke.dashPattern().offset() <<
"\"";
444 *stream <<
" stroke-dasharray=\" ";
446 TQValueListConstIterator<float> itr;
447 for(itr = stroke.dashPattern().array().begin(); itr != stroke.dashPattern().array().end(); ++itr )
449 *stream << *itr <<
" ";
456SvgExport::getHexColor( TQTextStream *stream,
const VColor& color )
462 VColor copy( color );
463 copy.setColorSpace( VColor::rgb );
465 Output.sprintf(
"#%02x%02x%02x",
int( copy[0] * 255.0 ),
int( copy[1] * 255.0 ),
int( copy[2] * 255.0 ) );
471SvgExport::visitVText( VText& text )
474 path.combinePath( text.basePath() );
476 m_trans->visitVPath( path );
478 TQString
id = createUID();
479 writePathToStream( path,
" id=\""+
id +
"\"", m_defs, m_indent2 );
481 printIndentation( m_body, m_indent++ );
482 *m_body <<
"<text" << getID( &text );
484 getFill( *( text.fill() ), m_body );
485 getStroke( *( text.stroke() ), m_body );
487 *m_body <<
" font-family=\"" << text.font().family() <<
"\"";
488 *m_body <<
" font-size=\"" << text.font().pointSize() <<
"\"";
489 if( text.font().bold() )
490 *m_body <<
" font-weight=\"bold\"";
491 if( text.font().italic() )
492 *m_body <<
" font-style=\"italic\"";
493 if( text.alignment() == VText::Center )
494 *m_body <<
" text-anchor=\"middle\"";
495 else if( text.alignment() == VText::Right )
496 *m_body <<
" text-anchor=\"end\"";
498 *m_body <<
">" << endl;
500 printIndentation( m_body, m_indent );
501 *m_body <<
"<textPath xlink:href=\"#" <<
id <<
"\"";
502 if( text.offset() > 0.0 )
503 *m_body <<
" startOffset=\"" << text.offset() * 100.0 <<
"%\"";
505 *m_body << text.text();
506 *m_body <<
"</textPath>" << endl;
507 printIndentation( m_body, --m_indent );
508 *m_body <<
"</text>" << endl;
511#include "svgexport.moc"