filters

epsexport.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, 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 #include <qapplication.h>
00021 #include <qcstring.h>
00022 #include <qdatetime.h>  // For creation date/time.
00023 #include <qdom.h>
00024 #include <qfile.h>
00025 #include <qstring.h>
00026 #include <qvaluelist.h>
00027 
00028 #include <kdebug.h>
00029 #include <kgenericfactory.h>
00030 #include <KoDocumentInfo.h>
00031 #include <KoFilter.h>
00032 #include <KoFilterChain.h>
00033 #include <KoStore.h>
00034 
00035 #include "epsexport.h"
00036 #include "epsexportdlg.h"
00037 #include "vcolor.h"
00038 #include "vcomposite.h"
00039 #include "vdashpattern.h"
00040 #include "vdocument.h"
00041 #include "vfill.h"
00042 #include "vgroup.h"
00043 #include "vlayer.h"
00044 #include "vpath.h"
00045 #include "vsegment.h"
00046 #include "vselection.h"
00047 #include "vstroke.h"
00048 #include "vtext.h"
00049 
00050 
00051 // Define PostScript level1 operators.
00052 static char l1_newpath      = 'N';
00053 static char l1_closepath    = 'C';
00054 static char l1_moveto       = 'm';
00055 static char l1_curveto      = 'c';
00056 static char l1_lineto       = 'l';
00057 static char l1_stroke       = 's';
00058 static char l1_fill         = 'f';
00059 //static char l1_eofill     = 'e';
00060 static char l1_setlinewidth = 'w';
00061 static char l1_setdash      = 'd';
00062 static char l1_setrgbcolor  = 'r';
00063 static char l1_gsave        = 'S';
00064 static char l1_grestore     = 'R';
00065 
00066 
00067 class EpsExportFactory : KGenericFactory<EpsExport, KoFilter>
00068 {
00069 public:
00070     EpsExportFactory( void )
00071         : KGenericFactory<EpsExport, KoFilter>( "karbonepsexport" )
00072     {}
00073 
00074 protected:
00075     virtual void setupTranslations( void )
00076     {
00077         KGlobal::locale()->insertCatalogue( "kofficefilters" );
00078     }
00079 };
00080 
00081 
00082 K_EXPORT_COMPONENT_FACTORY( libkarbonepsexport, EpsExportFactory() )
00083 
00084 
00085 EpsExport::EpsExport( KoFilter*, const char*, const QStringList& )
00086     : KoFilter()
00087 {
00088 }
00089 
00090 KoFilter::ConversionStatus
00091 EpsExport::convert( const QCString& from, const QCString& to )
00092 {
00093     if ( to != "image/x-eps" || from != "application/x-karbon" )
00094     {
00095         return KoFilter::NotImplemented;
00096     }
00097 
00098 
00099     KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read );
00100 
00101     if( !storeIn )
00102         return KoFilter::StupidError;
00103 
00104 
00105     KoFilter::ConversionStatus status = KoFilter::OK;
00106 
00107     // Ask questions about PS level etc.
00108     EpsExportDlg* dialog = new EpsExportDlg();
00109 
00110     QApplication::setOverrideCursor( Qt::arrowCursor );
00111 
00112     if( dialog->exec() )
00113     {
00114         // Which PostScript level to support?
00115         m_psLevel = dialog->psLevel() + 1;
00116 
00117         QFile fileOut( m_chain->outputFile() );
00118         if( !fileOut.open( IO_WriteOnly ) )
00119         {
00120             QApplication::restoreOverrideCursor();
00121             delete( dialog );
00122 
00123             return KoFilter::StupidError;
00124         }
00125 
00126         QDomDocument domIn;
00127         domIn.setContent( storeIn );
00128         QDomElement docNode = domIn.documentElement();
00129 
00130         m_stream = new QTextStream( &fileOut );
00131 
00132         // Load the document.
00133         VDocument doc;
00134         doc.load( docNode );
00135 
00136         // Process the document.
00137         doc.accept( *this );
00138 
00139         delete m_stream;
00140         fileOut.close();
00141     }
00142     else
00143     {
00144         // Dialog cancelled.
00145         status = KoFilter::UserCancelled;
00146     }
00147 
00148     QApplication::restoreOverrideCursor();
00149     delete( dialog );
00150 
00151     return status;
00152 }
00153 
00154 void
00155 EpsExport::visitVDocument( VDocument& document )
00156 {
00157     // Select all objects.
00158     document.selection()->append();
00159 
00160     // Get the bounding box of all selected objects.
00161     const KoRect& rect = document.selection()->boundingBox();
00162 
00163     // Print a header.
00164     *m_stream <<
00165         "%!PS-Adobe-3.0 EPSF-3.0\n"
00166         "%%BoundingBox: " <<
00167         // Round down.
00168             qRound( rect.left()   - 0.5 ) << " " <<
00169             qRound( rect.top()    - 0.5 ) << " " <<
00170         // Round up.
00171             qRound( rect.right()  + 0.5 ) << " " <<
00172             qRound( rect.bottom() + 0.5 ) << "\n" <<
00173         "%%HiResBoundingBox: " <<
00174             rect.left()   << " " <<
00175             rect.top()    << " " <<
00176             rect.right()  << " " <<
00177             rect.bottom() << "\n"
00178         "%%Creator: Karbon14 EPS Exportfilter 0.5"
00179     << endl;
00180 
00181     // We dont need the selection anymore.
00182     document.selection()->clear();
00183 
00184 
00185     // Process document info.
00186     KoStoreDevice* storeIn;
00187     storeIn = m_chain->storageFile( "documentinfo.xml", KoStore::Read );
00188 
00189     if( storeIn )
00190     {
00191         QDomDocument domIn;
00192         domIn.setContent( storeIn );
00193 
00194         KoDocumentInfo docInfo;
00195         docInfo.load( domIn );
00196 
00197         KoDocumentInfoAuthor* authorPage =
00198             static_cast<KoDocumentInfoAuthor*>( docInfo.page( "author" ) );
00199 
00200         // Get creation date/time = "now".
00201         QDateTime now( QDateTime::currentDateTime() );
00202 
00203         *m_stream <<
00204             "%%CreationDate: (" << now.toString( Qt::LocalDate ) << ")\n"
00205             "%%For: (" << authorPage->fullName() << ") (" << authorPage->company() << ")\n"
00206             "%%Title: (" << docInfo.title() << ")"
00207         << endl;
00208     }
00209 
00210 
00211     // Print operator definitions.
00212     *m_stream <<
00213         "\n"
00214         "/" << l1_newpath       << " {newpath} def\n"
00215         "/" << l1_closepath     << " {closepath} def\n"
00216         "/" << l1_moveto        << " {moveto} def\n"
00217         "/" << l1_curveto       << " {curveto} def\n"
00218         "/" << l1_lineto        << " {lineto} def\n"
00219         "/" << l1_stroke        << " {stroke} def\n"
00220         "/" << l1_fill          << " {fill} def\n"
00221         "/" << l1_setlinewidth  << " {setlinewidth} def\n"
00222         "/" << l1_setdash       << " {setdash} def\n"
00223         "/" << l1_setrgbcolor   << " {setrgbcolor} def\n"
00224         "/" << l1_gsave         << " {gsave} def\n"
00225         "/" << l1_grestore      << " {grestore} def\n"
00226     << endl;
00227 
00228     // Export layers.
00229     VVisitor::visitVDocument( document );
00230 
00231     // Finished.
00232     *m_stream <<
00233         "%%EOF"
00234     << endl;
00235 }
00236 
00237 void
00238 EpsExport::visitVPath( VPath& composite )
00239 {
00240     *m_stream << l1_newpath << "\n";
00241 
00242     VVisitor::visitVPath( composite );
00243 
00244     getFill( *composite.fill() );
00245     getStroke( *composite.stroke() );
00246 
00247     *m_stream << endl;
00248 }
00249 
00250 void
00251 EpsExport::visitVSubpath( VSubpath& path )
00252 {
00253     // Export segments.
00254     VSubpathIterator itr( path );
00255 
00256     for( ; itr.current(); ++itr )
00257     {
00258         VSegment *segment = itr.current();
00259         if ( segment->isCurve() ) {
00260             *m_stream <<
00261             itr.current()->point( 0 ).x() << " " <<
00262             itr.current()->point( 0 ).y() << " " <<
00263             itr.current()->point( 1 ).x() << " " <<
00264             itr.current()->point( 1 ).y() << " " <<
00265             itr.current()->knot().x() << " " <<
00266             itr.current()->knot().y() << " " <<
00267             l1_curveto << "\n";
00268         } else if ( segment->isLine() ) {
00269             *m_stream <<
00270             itr.current()->knot().x() << " " <<
00271             itr.current()->knot().y() << " " <<
00272             l1_lineto << "\n";
00273         } else if ( segment->isBegin() ) {
00274             *m_stream <<
00275             itr.current()->knot().x() << " " <<
00276             itr.current()->knot().y() << " " <<
00277             l1_moveto << "\n";
00278         }
00279     }
00280 
00281     if( path.isClosed() )
00282         *m_stream << l1_closepath << "\n";
00283 }
00284 
00285 void
00286 EpsExport::visitVText( VText& text )
00287 {
00288     // TODO: currently we only export the glyphs if available.
00289 
00290     // Export the glyphs (= VPaths).
00291     VPathListIterator itr( text.glyphs() );
00292 
00293     for( ; itr.current(); ++itr )
00294     {
00295         visit( *itr.current() );
00296     }
00297 }
00298 
00299 void
00300 EpsExport::getStroke( const VStroke& stroke )
00301 {
00302     // Solid stroke.
00303     if( stroke.type() == VStroke::solid )
00304     {
00305         // Dash pattern.
00306         *m_stream << "[";
00307 
00308         const QValueList<float>&
00309             array( stroke.dashPattern().array() );
00310 
00311         QValueListConstIterator<float> itr = array.begin();
00312         for( ; itr != array.end(); ++itr )
00313              *m_stream << *itr << " ";
00314 
00315         *m_stream <<
00316             "] " << stroke.dashPattern().offset() <<
00317             " "  << l1_setdash << " ";
00318 
00319         getColor( stroke.color() );
00320 
00321         // "setlinewidth", "stroke".
00322         *m_stream <<
00323             " " << stroke.lineWidth() <<
00324             " " << l1_setlinewidth <<
00325             " " << l1_stroke << "\n";
00326     }
00327     else if( stroke.type() == VStroke::grad )
00328     {
00329         if( m_psLevel == 3 )
00330         {
00331 
00332         }
00333     }
00334 }
00335 
00336 void
00337 EpsExport::getFill( const VFill& fill )
00338 {
00339     // Solid fill.
00340     if( fill.type() == VFill::solid )
00341     {
00342         // "gsave".
00343         *m_stream << l1_gsave << " ";
00344 
00345         // "setrgbcolor".
00346         getColor( fill.color() );
00347 
00348         // "fill", "grestore".
00349         *m_stream << " " << l1_fill << " " << l1_grestore << "\n";
00350     }
00351     // Gradient.
00352     else if( fill.type() == VFill::grad )
00353     {
00354         if( m_psLevel == 3 )
00355         {
00356             // "gsave".
00357             *m_stream << l1_gsave << " ";
00358 
00359             VGradient grad = fill.gradient();
00360             QPtrVector<VColorStop> ramp = grad.colorStops();
00361             if( ramp.size() < 2 )
00362             {
00363                 if( ramp.size() == 1 )
00364                     getColor( ramp[0]->color );
00365             }
00366             if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
00367             {
00368                 // Gradient with more than two colors or asymmetrical midpoint.
00369                 for( uint i = 1;i < ramp.size();i++ )
00370                 {
00371                     char name[15];
00372                     sprintf( name, "Function%d", 2 * i - 1 );
00373 
00374                     VColorStop stop1 = *ramp[i - 1];
00375                     VColorStop stop2 = *ramp[i];
00376                     VColor mid;
00377                     mid.set( 0.5 * ( stop1.color[0] + stop2.color[0] ), 0.5 * ( stop1.color[1] + stop2.color[1] ), 0.5 * ( stop1.color[2] + stop2.color[2] ) );
00378                     *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n"
00379                                 << "\t/Domain [ 0 1 ] def\n" << "\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " "
00380                                 << stop1.color[2] << " ] def\n" << "\t/C1 [ " << mid[0] << " " << mid[1] << " "
00381                                 << mid[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
00382 
00383                     sprintf( name, "Function%d", 2 * i );
00384 
00385                     *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n" << "\t/Domain [ 0 1 ] def\n"
00386                                 << "\t/C0 [ " << mid[0] << " " << mid[1] << " " << mid[2] << " ] def\n" << "\t/C1 [ " << stop2.color[0] << " "
00387                                 << stop2.color[1] << " " << stop2.color[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
00388                 }
00389             }
00390             if( grad.type() == VGradient::linear )
00391                 *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 2\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
00392                             << grad.origin().x() << " " << grad.origin().y() << " " << grad.vector().x() << " " << grad.vector().y() << " ]\n\t/Extend[ true true ]\n" << "\t/Function <<\n";
00393             else if( grad.type() == VGradient::radial )
00394             {
00395                 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
00396                 *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 3\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
00397                             << grad.origin().x() << " " << grad.origin().y() << " 0.0 " << grad.origin().x() << " " << grad.origin().y()
00398                             << " " << r << "]\n\t\t/Extend [ false true ]\n" << "\t/Function <<\n";
00399             }
00400             if( ramp.size() == 2 && ramp[0]->midPoint == 0.5 )
00401             {
00402                 // Gradient with only two colors and symmetrical midpoint.
00403                 VColorStop stop1 = *ramp[0];
00404                 VColorStop stop2 = *ramp[1];
00405                 *m_stream << "\t\t/FunctionType 2\n" << "\t\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " " << stop1.color[2]
00406                           << " ]\n" << "\t\t/C1 [ " << stop2.color[0] << " " << stop2.color[1] << " " << stop2.color[2] << " ]\n" << "\t\t/N 1\n";
00407             }
00408             else if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
00409             {
00410                 // Gradient with more than two colors or asymmetrical midpoint.
00411                 *m_stream << "\t\t/FunctionType 3\n" << "\t\t/Functions [ ";
00412                 for( uint i = 1; i < ( 2 * ramp.size() - 1 );i++ )
00413                     *m_stream << "Function" << i << " ";
00414                 *m_stream << "]\n" << "\t\t/Bounds [";
00415                 for( uint i = 0;i < ramp.size() - 1;i++ )
00416                 {
00417                     VColorStop stop = *ramp[i];
00418                     if( i > 0 )
00419                         *m_stream << " " << stop.rampPoint;
00420                     *m_stream << " " << ( stop.rampPoint + ( ramp[i + 1]->rampPoint - stop.rampPoint ) * stop.midPoint );
00421                 }
00422                 *m_stream << " ]\n" << "\t\t/Encode [ ";
00423                 for( uint i = 0;i < 2 * ramp.size() - 2;i++ )
00424                     *m_stream << "0 1 ";
00425                 *m_stream << "]\n";
00426             }
00427             *m_stream << "\t\t/Domain [ " << ramp[0]->rampPoint << " "
00428                     << ramp[ramp.size() - 1]->rampPoint << " ]\n" << "\t>>\n" << ">>\n";
00429             // "shfill", "grestore".
00430             *m_stream << " shfill " << l1_grestore << "\n";
00431         }
00432     }
00433 }
00434 
00435 void
00436 EpsExport::getColor( const VColor& color )
00437 {
00438     VColor copy( color );
00439     copy.setColorSpace( VColor::rgb );
00440 
00441     *m_stream <<
00442         copy[0] << " " <<
00443         copy[1] << " " <<
00444         copy[2] << " " << l1_setrgbcolor;
00445 }
00446 
00447 
00448 #include "epsexport.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys