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 #include "vcomputeboundingbox.h"
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(), m_exportHidden( true )
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         m_exportHidden = dialog->exportHidden();
00117 
00118         QFile fileOut( m_chain->outputFile() );
00119         if( !fileOut.open( IO_WriteOnly ) )
00120         {
00121             QApplication::restoreOverrideCursor();
00122             delete( dialog );
00123 
00124             return KoFilter::StupidError;
00125         }
00126 
00127         QDomDocument domIn;
00128         domIn.setContent( storeIn );
00129         QDomElement docNode = domIn.documentElement();
00130 
00131         m_stream = new QTextStream( &fileOut );
00132 
00133         // Load the document.
00134         VDocument doc;
00135         doc.load( docNode );
00136 
00137         // Process the document.
00138         doc.accept( *this );
00139 
00140         delete m_stream;
00141         fileOut.close();
00142     }
00143     else
00144     {
00145         // Dialog cancelled.
00146         status = KoFilter::UserCancelled;
00147     }
00148 
00149     QApplication::restoreOverrideCursor();
00150     delete( dialog );
00151 
00152     return status;
00153 }
00154 
00155 void
00156 EpsExport::visitVDocument( VDocument& document )
00157 {
00158     // calculate the documents bounding box
00159     VComputeBoundingBox bbox( ! m_exportHidden );
00160     document.accept( bbox );
00161     const KoRect &rect = bbox.boundingRect();
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     // Process document info.
00182     KoStoreDevice* storeIn;
00183     storeIn = m_chain->storageFile( "documentinfo.xml", KoStore::Read );
00184 
00185     if( storeIn )
00186     {
00187         QDomDocument domIn;
00188         domIn.setContent( storeIn );
00189 
00190         KoDocumentInfo docInfo;
00191         docInfo.load( domIn );
00192 
00193         KoDocumentInfoAuthor* authorPage =
00194             static_cast<KoDocumentInfoAuthor*>( docInfo.page( "author" ) );
00195 
00196         // Get creation date/time = "now".
00197         QDateTime now( QDateTime::currentDateTime() );
00198 
00199         *m_stream <<
00200             "%%CreationDate: (" << now.toString( Qt::LocalDate ) << ")\n"
00201             "%%For: (" << authorPage->fullName() << ") (" << authorPage->company() << ")\n"
00202             "%%Title: (" << docInfo.title() << ")"
00203         << endl;
00204     }
00205 
00206 
00207     // Print operator definitions.
00208     *m_stream <<
00209         "\n"
00210         "/" << l1_newpath       << " {newpath} def\n"
00211         "/" << l1_closepath     << " {closepath} def\n"
00212         "/" << l1_moveto        << " {moveto} def\n"
00213         "/" << l1_curveto       << " {curveto} def\n"
00214         "/" << l1_lineto        << " {lineto} def\n"
00215         "/" << l1_stroke        << " {stroke} def\n"
00216         "/" << l1_fill          << " {fill} def\n"
00217         "/" << l1_setlinewidth  << " {setlinewidth} def\n"
00218         "/" << l1_setdash       << " {setdash} def\n"
00219         "/" << l1_setrgbcolor   << " {setrgbcolor} def\n"
00220         "/" << l1_gsave         << " {gsave} def\n"
00221         "/" << l1_grestore      << " {grestore} def\n"
00222     << endl;
00223 
00224     // Export layers.
00225     VVisitor::visitVDocument( document );
00226 
00227     // Finished.
00228     *m_stream <<
00229         "%%EOF"
00230     << endl;
00231 }
00232 
00233 void
00234 EpsExport::visitVGroup( VGroup& group )
00235 {
00236     VObjectListIterator itr( group.objects() );
00237 
00238     for( ; itr.current(); ++itr )
00239     {
00240         // do not export hidden child objects
00241         if( ! m_exportHidden && ! isVisible( itr.current() ) )
00242             continue;
00243         itr.current()->accept( *this );
00244     }
00245 }
00246 
00247 void
00248 EpsExport::visitVLayer( VLayer& layer )
00249 {
00250     // do not export hidden layers
00251     if( ! m_exportHidden && ! isVisible( &layer ) )
00252         return;
00253 
00254     VObjectListIterator itr( layer.objects() );
00255 
00256     for( ; itr.current(); ++itr )
00257     {
00258         // do not export hidden objects
00259         if( ! m_exportHidden && ! isVisible( itr.current() ) )
00260             continue;
00261         itr.current()->accept( *this );
00262     }
00263 }
00264 
00265 void
00266 EpsExport::visitVPath( VPath& composite )
00267 {
00268     *m_stream << l1_newpath << "\n";
00269 
00270     VVisitor::visitVPath( composite );
00271 
00272     getFill( *composite.fill() );
00273     getStroke( *composite.stroke() );
00274 
00275     *m_stream << endl;
00276 }
00277 
00278 void
00279 EpsExport::visitVSubpath( VSubpath& path )
00280 {
00281     // Export segments.
00282     VSubpathIterator itr( path );
00283 
00284     for( ; itr.current(); ++itr )
00285     {
00286         VSegment *segment = itr.current();
00287         if ( segment->isCurve() ) {
00288             *m_stream <<
00289             itr.current()->point( 0 ).x() << " " <<
00290             itr.current()->point( 0 ).y() << " " <<
00291             itr.current()->point( 1 ).x() << " " <<
00292             itr.current()->point( 1 ).y() << " " <<
00293             itr.current()->knot().x() << " " <<
00294             itr.current()->knot().y() << " " <<
00295             l1_curveto << "\n";
00296         } else if ( segment->isLine() ) {
00297             *m_stream <<
00298             itr.current()->knot().x() << " " <<
00299             itr.current()->knot().y() << " " <<
00300             l1_lineto << "\n";
00301         } else if ( segment->isBegin() ) {
00302             *m_stream <<
00303             itr.current()->knot().x() << " " <<
00304             itr.current()->knot().y() << " " <<
00305             l1_moveto << "\n";
00306         }
00307     }
00308 
00309     if( path.isClosed() )
00310         *m_stream << l1_closepath << "\n";
00311 }
00312 
00313 void
00314 EpsExport::visitVText( VText& text )
00315 {
00316     // TODO: currently we only export the glyphs if available.
00317 
00318     // Export the glyphs (= VPaths).
00319     VPathListIterator itr( text.glyphs() );
00320 
00321     for( ; itr.current(); ++itr )
00322     {
00323         visit( *itr.current() );
00324     }
00325 }
00326 
00327 void
00328 EpsExport::getStroke( const VStroke& stroke )
00329 {
00330     // Solid stroke.
00331     if( stroke.type() == VStroke::solid )
00332     {
00333         // Dash pattern.
00334         *m_stream << "[";
00335 
00336         const QValueList<float>&
00337             array( stroke.dashPattern().array() );
00338 
00339         QValueListConstIterator<float> itr = array.begin();
00340         for( ; itr != array.end(); ++itr )
00341              *m_stream << *itr << " ";
00342 
00343         *m_stream <<
00344             "] " << stroke.dashPattern().offset() <<
00345             " "  << l1_setdash << " ";
00346 
00347         getColor( stroke.color() );
00348 
00349         // "setlinewidth", "stroke".
00350         *m_stream <<
00351             " " << stroke.lineWidth() <<
00352             " " << l1_setlinewidth <<
00353             " " << l1_stroke << "\n";
00354     }
00355     else if( stroke.type() == VStroke::grad )
00356     {
00357         if( m_psLevel == 3 )
00358         {
00359 
00360         }
00361     }
00362 }
00363 
00364 void
00365 EpsExport::getFill( const VFill& fill )
00366 {
00367     // Solid fill.
00368     if( fill.type() == VFill::solid )
00369     {
00370         // "gsave".
00371         *m_stream << l1_gsave << " ";
00372 
00373         // "setrgbcolor".
00374         getColor( fill.color() );
00375 
00376         // "fill", "grestore".
00377         *m_stream << " " << l1_fill << " " << l1_grestore << "\n";
00378     }
00379     // Gradient.
00380     else if( fill.type() == VFill::grad )
00381     {
00382         if( m_psLevel == 3 )
00383         {
00384             // "gsave".
00385             *m_stream << l1_gsave << " ";
00386 
00387             VGradient grad = fill.gradient();
00388             QPtrVector<VColorStop> ramp = grad.colorStops();
00389             if( ramp.size() < 2 )
00390             {
00391                 if( ramp.size() == 1 )
00392                     getColor( ramp[0]->color );
00393             }
00394             if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
00395             {
00396                 // Gradient with more than two colors or asymmetrical midpoint.
00397                 for( uint i = 1;i < ramp.size();i++ )
00398                 {
00399                     char name[15];
00400                     sprintf( name, "Function%d", 2 * i - 1 );
00401 
00402                     VColorStop stop1 = *ramp[i - 1];
00403                     VColorStop stop2 = *ramp[i];
00404                     VColor mid;
00405                     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] ) );
00406                     *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n"
00407                                 << "\t/Domain [ 0 1 ] def\n" << "\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " "
00408                                 << stop1.color[2] << " ] def\n" << "\t/C1 [ " << mid[0] << " " << mid[1] << " "
00409                                 << mid[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
00410 
00411                     sprintf( name, "Function%d", 2 * i );
00412 
00413                     *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n" << "\t/Domain [ 0 1 ] def\n"
00414                                 << "\t/C0 [ " << mid[0] << " " << mid[1] << " " << mid[2] << " ] def\n" << "\t/C1 [ " << stop2.color[0] << " "
00415                                 << stop2.color[1] << " " << stop2.color[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
00416                 }
00417             }
00418             if( grad.type() == VGradient::linear )
00419                 *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 2\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
00420                             << grad.origin().x() << " " << grad.origin().y() << " " << grad.vector().x() << " " << grad.vector().y() << " ]\n\t/Extend[ true true ]\n" << "\t/Function <<\n";
00421             else if( grad.type() == VGradient::radial )
00422             {
00423                 double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
00424                 *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 3\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
00425                             << grad.origin().x() << " " << grad.origin().y() << " 0.0 " << grad.origin().x() << " " << grad.origin().y()
00426                             << " " << r << "]\n\t\t/Extend [ false true ]\n" << "\t/Function <<\n";
00427             }
00428             if( ramp.size() == 2 && ramp[0]->midPoint == 0.5 )
00429             {
00430                 // Gradient with only two colors and symmetrical midpoint.
00431                 VColorStop stop1 = *ramp[0];
00432                 VColorStop stop2 = *ramp[1];
00433                 *m_stream << "\t\t/FunctionType 2\n" << "\t\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " " << stop1.color[2]
00434                           << " ]\n" << "\t\t/C1 [ " << stop2.color[0] << " " << stop2.color[1] << " " << stop2.color[2] << " ]\n" << "\t\t/N 1\n";
00435             }
00436             else if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
00437             {
00438                 // Gradient with more than two colors or asymmetrical midpoint.
00439                 *m_stream << "\t\t/FunctionType 3\n" << "\t\t/Functions [ ";
00440                 for( uint i = 1; i < ( 2 * ramp.size() - 1 );i++ )
00441                     *m_stream << "Function" << i << " ";
00442                 *m_stream << "]\n" << "\t\t/Bounds [";
00443                 for( uint i = 0;i < ramp.size() - 1;i++ )
00444                 {
00445                     VColorStop stop = *ramp[i];
00446                     if( i > 0 )
00447                         *m_stream << " " << stop.rampPoint;
00448                     *m_stream << " " << ( stop.rampPoint + ( ramp[i + 1]->rampPoint - stop.rampPoint ) * stop.midPoint );
00449                 }
00450                 *m_stream << " ]\n" << "\t\t/Encode [ ";
00451                 for( uint i = 0;i < 2 * ramp.size() - 2;i++ )
00452                     *m_stream << "0 1 ";
00453                 *m_stream << "]\n";
00454             }
00455             *m_stream << "\t\t/Domain [ " << ramp[0]->rampPoint << " "
00456                     << ramp[ramp.size() - 1]->rampPoint << " ]\n" << "\t>>\n" << ">>\n";
00457             // "shfill", "grestore".
00458             *m_stream << " shfill " << l1_grestore << "\n";
00459         }
00460     }
00461 }
00462 
00463 void
00464 EpsExport::getColor( const VColor& color )
00465 {
00466     VColor copy( color );
00467     copy.setColorSpace( VColor::rgb );
00468 
00469     *m_stream <<
00470         copy[0] << " " <<
00471         copy[1] << " " <<
00472         copy[2] << " " << l1_setrgbcolor;
00473 }
00474 
00475 bool
00476 EpsExport::isVisible( const VObject* object ) const
00477 {
00478     return object->state() != VObject::hidden && object->state() != VObject::hidden_locked;
00479 }
00480 
00481 #include "epsexport.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys