filters

xamlexport.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, 2003 The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 // based on the SVG exporter.  Not intended for public release
00021 // Microsoft WVG renamed to XAML Graphics.  Worry about that later.  
00022 
00023 #include <qcstring.h>
00024 #include <qdom.h>
00025 #include <qfile.h>
00026 #include <qstring.h>
00027 #include <qvaluelist.h>
00028 
00029 #include <kgenericfactory.h>
00030 #include <KoFilter.h>
00031 #include <KoFilterChain.h>
00032 #include <KoStore.h>
00033 
00034 #include "xamlexport.h"
00035 #include "vcolor.h"
00036 #include "vcomposite.h"
00037 #include "vdashpattern.h"
00038 #include "vdocument.h"
00039 #include "vfill.h"
00040 #include "vgradient.h"
00041 #include "vgroup.h"
00042 #include "vlayer.h"
00043 #include "vpath.h"
00044 #include "vsegment.h"
00045 #include "vselection.h"
00046 #include "vstroke.h"
00047 //#include "vtext.h"  // TODO Convert Text to Paths for basic export.  Not our problem.  
00048 // TODO inline Images?
00049 
00050 #include <kdebug.h>
00051 
00052 
00053 typedef KGenericFactory<XAMLExport, KoFilter> XAMLExportFactory;
00054 K_EXPORT_COMPONENT_FACTORY( libkarbonxamlexport, XAMLExportFactory( "kofficefilters" ) )
00055 
00056 
00057 XAMLExport::XAMLExport( KoFilter*, const char*, const QStringList& )
00058     : KoFilter()
00059 {
00060     m_gc.setAutoDelete( true );
00061 }
00062 
00063 KoFilter::ConversionStatus
00064 XAMLExport::convert( const QCString& from, const QCString& to )
00065 {
00066     // TODO: ???
00067     if ( to != "image/wvg+xml" || from != "application/x-karbon" )
00068     {
00069         return KoFilter::NotImplemented;
00070     }
00071 
00072     KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read );
00073     if( !storeIn )
00074         return KoFilter::StupidError;
00075 
00076     QFile fileOut( m_chain->outputFile() );
00077     if( !fileOut.open( IO_WriteOnly ) )
00078     {
00079         delete storeIn;
00080         return KoFilter::StupidError;
00081     }
00082 
00083     QDomDocument domIn;
00084     domIn.setContent( storeIn );
00085     QDomElement docNode = domIn.documentElement();
00086 
00087     m_stream = new QTextStream( &fileOut );
00088     QString body;
00089     m_body = new QTextStream( &body, IO_ReadWrite );
00090     QString defs;
00091     m_defs = new QTextStream( &defs, IO_ReadWrite );
00092 
00093 
00094     // load the document and export it:
00095     VDocument doc;
00096     doc.load( docNode );
00097     doc.accept( *this );
00098 
00099     *m_stream << defs;
00100     *m_stream << body;
00101 
00102     fileOut.close();
00103 
00104     delete m_stream;
00105     delete m_defs;
00106     delete m_body;
00107 
00108     return KoFilter::OK;
00109 }
00110 
00111 void
00112 XAMLExport::visitVDocument( VDocument& document )
00113 {
00114     // select all objects:
00115     document.selection()->append();
00116 
00117     // get the bounding box of the page
00118     KoRect rect( 0, 0, document.width(), document.height() );
00119 
00120     // standard header:
00121     *m_defs <<
00122         "<?xml version=\"1.0\" ?>\n" <<
00123         /* "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" " <<* */
00124         // "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
00125     /*<<*/ endl;
00126 
00127     // Add one line comment to identify Content Creator, 
00128     // probably remove this later
00129     // TODO: schemas
00130     // http://schemas.microsoft.com/winfx/avalon/2005 
00131     // http://schemas.microsoft.com/2003/xaml  
00132     // need to mention defs too Defenitions namespace xmlns:def="Definition"    
00133     *m_defs <<
00134         "<!-- Generator: Karbon14 WVG XAML Graphics export filter  $VERSION/$DATE.  -->" << endl;
00135     *m_defs <<
00136         "<Canvas xmlns=\"http://schemas.microsoft.com/winfx/avalon/2005\" Width=\"" << rect.width() << 
00137         "Height=\"" << rect.height() << "\">" << endl;
00138     *m_defs << "<Canvas.Resources>" << endl;
00139 
00140     // bleuch: this is horrible, do something about it TODO
00141     // Microsoft Acrylic has a transform group just like this
00142     *m_body << "<Transform=\"scale(1, -1) Translate(0, -" << rect.height() << ")\">" << endl;
00143 
00144     // we dont need the selection anymore:
00145     document.selection()->clear();
00146 
00147     // set up gc
00148     XAMLGraphicsContext *gc = new XAMLGraphicsContext;
00149     m_gc.push( gc );
00150 
00151     // export layers:
00152     VVisitor::visitVDocument( document );
00153 
00154     // end tag:
00155     *m_body << "</Canvas>" << endl;
00156     *m_defs << "</Canvas.Resources>" << endl;
00157     *m_body << "</Canvas>" << endl;
00158 }
00159 
00160 QString
00161 XAMLExport::getID( VObject *obj )
00162 {
00163     if( obj && !obj->name().isEmpty() )
00164         return QString( " Name=\"%1\"" ).arg( obj->name() );
00165     return QString();
00166 }
00167 
00168 // which markup to use?  Group or Canvas?
00169 // for now assume Group will work.  TODO: Test properly!
00170 void
00171 XAMLExport::visitVGroup( VGroup& group )
00172 {
00173     *m_body << "<Canvas" << getID( &group ) << ">" << endl;
00174     VVisitor::visitVGroup( group );
00175     *m_body << "</Canvas>" << endl;
00176 }
00177 
00178 void
00179 XAMLExport::visitVPath( VPath& composite )
00180 {
00181     *m_body << "<Path" << getID( &composite );
00182 
00183     VVisitor::visitVPath( composite );
00184 
00185     getFill( *( composite.fill() ) );
00186     getStroke( *( composite.stroke() ) );
00187 
00188     QString d;
00189     composite.saveSvgPath( d );
00190     *m_body << " Data=\"" << d << "\" ";
00191 
00192     if( composite.fillRule() != m_gc.current()->fillRule )
00193     {
00194         if( composite.fillRule() == evenOdd )
00195             *m_body << " FillRule=\"EvenOdd\"";
00196         else
00197             *m_body << " FillRule=\"NonZero\"";
00198     }
00199 
00200     *m_body << " />" << endl;
00201 }
00202 
00203 void
00204 XAMLExport::visitVSubpath( VSubpath& )
00205 {
00206 }
00207 
00208 QString createUID()
00209 {
00210     static unsigned int nr = 0;
00211 
00212     return "defitem" + QString().setNum( nr++ );
00213 }
00214 
00215 void
00216 XAMLExport::getColorStops( const QPtrVector<VColorStop> &colorStops )
00217 {
00218     for( unsigned int i = 0; i < colorStops.count() ; i++ )
00219     {
00220         *m_defs << "<GradientStop Color=\"";
00221         getHexColor( m_defs, colorStops.at( i )->color );
00222         *m_defs << "\" Offset=\"" << QString().setNum( colorStops.at( i )->rampPoint );
00223         //  XAML uses ARGB values and other methods such as masks for Transparency/Opacity    #  aa  rrggbb  
00224         // *m_defs << "\" stop-opacity=\"" << colorStops.at( i )->color.opacity() << "\"" << " />" << endl;
00225         // Maybe this only applies to gradients, need to check.  
00226     }
00227 }
00228 
00229 void
00230 XAMLExport::getGradient( const VGradient& grad )
00231 {
00232     QString uid = createUID();
00233     if( grad.type() == VGradient::linear )
00234     {
00235         // do linear grad
00236         *m_defs << "<LinearGradientBrush id=\"" << uid << "\" ";
00237         *m_defs << "GradientUnits=\"UserSpaceOnUse\" ";
00238         *m_defs << "StartPoint=\"" << grad.origin().x() << ",";
00239         *m_defs << grad.origin().y() << "\" ";
00240         *m_defs << "EndPoint=\"" << grad.vector().x() << ",";
00241         *m_defs << grad.vector().y() << "\" ";
00242         if( grad.repeatMethod() == VGradient::reflect )
00243             *m_defs << "SpreadMethod=\"Reflect\" ";
00244         else if( grad.repeatMethod() == VGradient::repeat )
00245             *m_defs << "SpreadMethod=\"Repeat\" ";
00246         *m_defs << ">" << endl;
00247 
00248         // color stops
00249         getColorStops( grad.colorStops() );
00250 
00251         *m_defs << "</LinearGradientBrush>" << endl;
00252         *m_body << "url(#" << uid << ")";
00253     }
00254     else if( grad.type() == VGradient::radial )
00255     {
00256         // do radial grad
00257         *m_defs << "<RadialGradientBrush Name=\"" << uid << "\" ";
00258         // *m_defs << "gradientUnits=\"userSpaceOnUse\" "; // Absolute?
00259         *m_defs << "Center=\"" << grad.origin().x() << ",";
00260         *m_defs << grad.origin().y() << "\" ";
00261         // Gradient Origin also known as Focus
00262         *m_defs << "GradientOrigin=\"" << grad.focalPoint().x() << ",";
00263         *m_defs << grad.focalPoint().y() << "\" ";
00264         double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
00265         *m_defs << "Radius=\"" << QString().setNum( r ) << "\" ";
00266         if( grad.repeatMethod() == VGradient::reflect )
00267             *m_defs << "SpreadMethod=\"Reflect\" ";
00268         else if( grad.repeatMethod() == VGradient::repeat )
00269             *m_defs << "SpreadMethod=\"Repeat\" ";
00270         *m_defs << ">" << endl;
00271 
00272         // color stops
00273         getColorStops( grad.colorStops() );
00274 
00275         *m_defs << "</RadialGradientBrush>" << endl;
00276         *m_body << "url(#" << uid << ")";
00277     }
00278 }
00279 
00280 void
00281 XAMLExport::getFill( const VFill& fill )
00282 {
00283     *m_body << " Fill=\"";
00284     if( fill.type() == VFill::none )
00285         *m_body << "none";
00286     else if( fill.type() == VFill::grad )
00287         getGradient( fill.gradient() );
00288     else
00289         getHexColor( m_body, fill.color() );
00290     *m_body << "\"";
00291 
00292     if( fill.color().opacity() != m_gc.current()->fill.color().opacity() )
00293         *m_body << " FillOpacity=\"" << fill.color().opacity() << "\"";
00294 }
00295 
00296 void
00297 XAMLExport::getStroke( const VStroke& stroke )
00298 {
00299     if( stroke.type() != m_gc.current()->stroke.type() )
00300     {
00301         *m_body << " Stroke=\"";
00302         if( stroke.type() == VStroke::none )
00303             *m_body << "None";
00304         else if( stroke.type() == VStroke::grad )
00305             getGradient( stroke.gradient() );
00306         else
00307             getHexColor( m_body, stroke.color() );
00308         *m_body << "\"";
00309     }
00310 
00311     if( stroke.color().opacity() != m_gc.current()->stroke.color().opacity() )
00312         *m_body << " StrokeOpacity=\"" << stroke.color().opacity() << "\"";
00313 
00314     if( stroke.lineWidth() != m_gc.current()->stroke.lineWidth() )
00315         *m_body << " StrokeThickness=\"" << stroke.lineWidth() << "\"";
00316 
00317     if( stroke.lineCap() != m_gc.current()->stroke.lineCap() )
00318     {
00319         if( stroke.lineCap() == VStroke::capButt )
00320             *m_body << " StrokeLineCap=\"Butt\"";
00321         else if( stroke.lineCap() == VStroke::capRound )
00322             *m_body << " StrokeLineCap=\"round\"";
00323         else if( stroke.lineCap() == VStroke::capSquare )
00324             *m_body << " StrokeLineCap=\"square\"";
00325     }
00326 
00327     if( stroke.lineJoin() != m_gc.current()->stroke.lineJoin() )
00328     {
00329         if( stroke.lineJoin() == VStroke::joinMiter )
00330         {
00331             *m_body << " StrokeLineJoin=\"Miter\"";
00332             *m_body << " StrokeMiterLimit=\"" << stroke.miterLimit() << "\"";
00333         }
00334         else if( stroke.lineJoin() == VStroke::joinRound )
00335             *m_body << " StrokeLineJoin=\"Round\"";
00336         else if( stroke.lineJoin() == VStroke::joinBevel )
00337                 *m_body << " StrokeLineJoin=\"Bevel\"";
00338     }
00339 
00340     // dash
00341     if( stroke.dashPattern().array().count() > 0 )
00342     {
00343         *m_body << " StrokeDashOffset=\"" << stroke.dashPattern().offset() << "\"";
00344         *m_body << " StrokeDashArray=\" ";
00345 
00346         QValueListConstIterator<float> itr;
00347         for(itr = stroke.dashPattern().array().begin(); itr != stroke.dashPattern().array().end(); ++itr )
00348         {
00349             *m_body << *itr << " ";
00350         }
00351         *m_body << "\"";
00352     }
00353 }
00354 
00355 void
00356 XAMLExport::getHexColor( QTextStream *stream, const VColor& color )
00357 {
00358     // Convert the various color-spaces to hex
00359 
00360     QString Output;
00361 
00362     VColor copy( color );
00363     copy.setColorSpace( VColor::rgb );
00364 
00365     Output.sprintf( "#%02x%02x%02x", int( copy[0] * 255.0 ), int( copy[1] * 255.0 ), int( copy[2] * 255.0 ) );
00366 
00367     *stream << Output;
00368 }
00369 
00370 #include "xamlexport.moc"
00371 
KDE Home | KDE Accessibility Home | Description of Access Keys