summaryrefslogtreecommitdiffstats
path: root/filters/karbon/eps/epsexport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'filters/karbon/eps/epsexport.cpp')
-rw-r--r--filters/karbon/eps/epsexport.cpp481
1 files changed, 481 insertions, 0 deletions
diff --git a/filters/karbon/eps/epsexport.cpp b/filters/karbon/eps/epsexport.cpp
new file mode 100644
index 000000000..023074daa
--- /dev/null
+++ b/filters/karbon/eps/epsexport.cpp
@@ -0,0 +1,481 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, The Karbon Developers
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <tqapplication.h>
+#include <tqcstring.h>
+#include <tqdatetime.h> // For creation date/time.
+#include <tqdom.h>
+#include <tqfile.h>
+#include <tqstring.h>
+#include <tqvaluelist.h>
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <KoDocumentInfo.h>
+#include <KoFilter.h>
+#include <KoFilterChain.h>
+#include <KoStore.h>
+
+#include "epsexport.h"
+#include "epsexportdlg.h"
+#include "vcolor.h"
+#include "vcomposite.h"
+#include "vdashpattern.h"
+#include "vdocument.h"
+#include "vfill.h"
+#include "vgroup.h"
+#include "vlayer.h"
+#include "vpath.h"
+#include "vsegment.h"
+#include "vselection.h"
+#include "vstroke.h"
+#include "vtext.h"
+#include "vcomputeboundingbox.h"
+
+// Define PostScript level1 operators.
+static char l1_newpath = 'N';
+static char l1_closepath = 'C';
+static char l1_moveto = 'm';
+static char l1_curveto = 'c';
+static char l1_lineto = 'l';
+static char l1_stroke = 's';
+static char l1_fill = 'f';
+//static char l1_eofill = 'e';
+static char l1_setlinewidth = 'w';
+static char l1_setdash = 'd';
+static char l1_setrgbcolor = 'r';
+static char l1_gsave = 'S';
+static char l1_grestore = 'R';
+
+
+class EpsExportFactory : KGenericFactory<EpsExport, KoFilter>
+{
+public:
+ EpsExportFactory( void )
+ : KGenericFactory<EpsExport, KoFilter>( "karbonepsexport" )
+ {}
+
+protected:
+ virtual void setupTranslations( void )
+ {
+ TDEGlobal::locale()->insertCatalogue( "kofficefilters" );
+ }
+};
+
+
+K_EXPORT_COMPONENT_FACTORY( libkarbonepsexport, EpsExportFactory() )
+
+
+EpsExport::EpsExport( KoFilter*, const char*, const TQStringList& )
+ : KoFilter(), m_exportHidden( true )
+{
+}
+
+KoFilter::ConversionStatus
+EpsExport::convert( const TQCString& from, const TQCString& to )
+{
+ if ( to != "image/x-eps" || from != "application/x-karbon" )
+ {
+ return KoFilter::NotImplemented;
+ }
+
+
+ KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read );
+
+ if( !storeIn )
+ return KoFilter::StupidError;
+
+
+ KoFilter::ConversionStatus status = KoFilter::OK;
+
+ // Ask questions about PS level etc.
+ EpsExportDlg* dialog = new EpsExportDlg();
+
+ TQApplication::setOverrideCursor( TQt::arrowCursor );
+
+ if( dialog->exec() )
+ {
+ // Which PostScript level to support?
+ m_psLevel = dialog->psLevel() + 1;
+ m_exportHidden = dialog->exportHidden();
+
+ TQFile fileOut( m_chain->outputFile() );
+ if( !fileOut.open( IO_WriteOnly ) )
+ {
+ TQApplication::restoreOverrideCursor();
+ delete( dialog );
+
+ return KoFilter::StupidError;
+ }
+
+ TQDomDocument domIn;
+ domIn.setContent( storeIn );
+ TQDomElement docNode = domIn.documentElement();
+
+ m_stream = new TQTextStream( &fileOut );
+
+ // Load the document.
+ VDocument doc;
+ doc.load( docNode );
+
+ // Process the document.
+ doc.accept( *this );
+
+ delete m_stream;
+ fileOut.close();
+ }
+ else
+ {
+ // Dialog cancelled.
+ status = KoFilter::UserCancelled;
+ }
+
+ TQApplication::restoreOverrideCursor();
+ delete( dialog );
+
+ return status;
+}
+
+void
+EpsExport::visitVDocument( VDocument& document )
+{
+ // calculate the documents bounding box
+ VComputeBoundingBox bbox( ! m_exportHidden );
+ document.accept( bbox );
+ const KoRect &rect = bbox.boundingRect();
+
+ // Print a header.
+ *m_stream <<
+ "%!PS-Adobe-3.0 EPSF-3.0\n"
+ "%%BoundingBox: " <<
+ // Round down.
+ tqRound( rect.left() - 0.5 ) << " " <<
+ tqRound( rect.top() - 0.5 ) << " " <<
+ // Round up.
+ tqRound( rect.right() + 0.5 ) << " " <<
+ tqRound( rect.bottom() + 0.5 ) << "\n" <<
+ "%%HiResBoundingBox: " <<
+ rect.left() << " " <<
+ rect.top() << " " <<
+ rect.right() << " " <<
+ rect.bottom() << "\n"
+ "%%Creator: Karbon14 EPS Exportfilter 0.5"
+ << endl;
+
+ // Process document info.
+ KoStoreDevice* storeIn;
+ storeIn = m_chain->storageFile( "documentinfo.xml", KoStore::Read );
+
+ if( storeIn )
+ {
+ TQDomDocument domIn;
+ domIn.setContent( storeIn );
+
+ KoDocumentInfo docInfo;
+ docInfo.load( domIn );
+
+ KoDocumentInfoAuthor* authorPage =
+ static_cast<KoDocumentInfoAuthor*>( docInfo.page( "author" ) );
+
+ // Get creation date/time = "now".
+ TQDateTime now( TQDateTime::currentDateTime() );
+
+ *m_stream <<
+ "%%CreationDate: (" << now.toString( Qt::LocalDate ) << ")\n"
+ "%%For: (" << authorPage->fullName() << ") (" << authorPage->company() << ")\n"
+ "%%Title: (" << docInfo.title() << ")"
+ << endl;
+ }
+
+
+ // Print operator definitions.
+ *m_stream <<
+ "\n"
+ "/" << l1_newpath << " {newpath} def\n"
+ "/" << l1_closepath << " {closepath} def\n"
+ "/" << l1_moveto << " {moveto} def\n"
+ "/" << l1_curveto << " {curveto} def\n"
+ "/" << l1_lineto << " {lineto} def\n"
+ "/" << l1_stroke << " {stroke} def\n"
+ "/" << l1_fill << " {fill} def\n"
+ "/" << l1_setlinewidth << " {setlinewidth} def\n"
+ "/" << l1_setdash << " {setdash} def\n"
+ "/" << l1_setrgbcolor << " {setrgbcolor} def\n"
+ "/" << l1_gsave << " {gsave} def\n"
+ "/" << l1_grestore << " {grestore} def\n"
+ << endl;
+
+ // Export layers.
+ VVisitor::visitVDocument( document );
+
+ // Finished.
+ *m_stream <<
+ "%%EOF"
+ << endl;
+}
+
+void
+EpsExport::visitVGroup( VGroup& group )
+{
+ VObjectListIterator itr( group.objects() );
+
+ for( ; itr.current(); ++itr )
+ {
+ // do not export hidden child objects
+ if( ! m_exportHidden && ! isVisible( itr.current() ) )
+ continue;
+ itr.current()->accept( *this );
+ }
+}
+
+void
+EpsExport::visitVLayer( VLayer& layer )
+{
+ // do not export hidden layers
+ if( ! m_exportHidden && ! isVisible( &layer ) )
+ return;
+
+ VObjectListIterator itr( layer.objects() );
+
+ for( ; itr.current(); ++itr )
+ {
+ // do not export hidden objects
+ if( ! m_exportHidden && ! isVisible( itr.current() ) )
+ continue;
+ itr.current()->accept( *this );
+ }
+}
+
+void
+EpsExport::visitVPath( VPath& composite )
+{
+ *m_stream << l1_newpath << "\n";
+
+ VVisitor::visitVPath( composite );
+
+ getFill( *composite.fill() );
+ getStroke( *composite.stroke() );
+
+ *m_stream << endl;
+}
+
+void
+EpsExport::visitVSubpath( VSubpath& path )
+{
+ // Export segments.
+ VSubpathIterator itr( path );
+
+ for( ; itr.current(); ++itr )
+ {
+ VSegment *segment = itr.current();
+ if ( segment->isCurve() ) {
+ *m_stream <<
+ itr.current()->point( 0 ).x() << " " <<
+ itr.current()->point( 0 ).y() << " " <<
+ itr.current()->point( 1 ).x() << " " <<
+ itr.current()->point( 1 ).y() << " " <<
+ itr.current()->knot().x() << " " <<
+ itr.current()->knot().y() << " " <<
+ l1_curveto << "\n";
+ } else if ( segment->isLine() ) {
+ *m_stream <<
+ itr.current()->knot().x() << " " <<
+ itr.current()->knot().y() << " " <<
+ l1_lineto << "\n";
+ } else if ( segment->isBegin() ) {
+ *m_stream <<
+ itr.current()->knot().x() << " " <<
+ itr.current()->knot().y() << " " <<
+ l1_moveto << "\n";
+ }
+ }
+
+ if( path.isClosed() )
+ *m_stream << l1_closepath << "\n";
+}
+
+void
+EpsExport::visitVText( VText& text )
+{
+ // TODO: currently we only export the glyphs if available.
+
+ // Export the glyphs (= VPaths).
+ VPathListIterator itr( text.glyphs() );
+
+ for( ; itr.current(); ++itr )
+ {
+ visit( *itr.current() );
+ }
+}
+
+void
+EpsExport::getStroke( const VStroke& stroke )
+{
+ // Solid stroke.
+ if( stroke.type() == VStroke::solid )
+ {
+ // Dash pattern.
+ *m_stream << "[";
+
+ const TQValueList<float>&
+ array( stroke.dashPattern().array() );
+
+ TQValueListConstIterator<float> itr = array.begin();
+ for( ; itr != array.end(); ++itr )
+ *m_stream << *itr << " ";
+
+ *m_stream <<
+ "] " << stroke.dashPattern().offset() <<
+ " " << l1_setdash << " ";
+
+ getColor( stroke.color() );
+
+ // "setlinewidth", "stroke".
+ *m_stream <<
+ " " << stroke.lineWidth() <<
+ " " << l1_setlinewidth <<
+ " " << l1_stroke << "\n";
+ }
+ else if( stroke.type() == VStroke::grad )
+ {
+ if( m_psLevel == 3 )
+ {
+
+ }
+ }
+}
+
+void
+EpsExport::getFill( const VFill& fill )
+{
+ // Solid fill.
+ if( fill.type() == VFill::solid )
+ {
+ // "gsave".
+ *m_stream << l1_gsave << " ";
+
+ // "setrgbcolor".
+ getColor( fill.color() );
+
+ // "fill", "grestore".
+ *m_stream << " " << l1_fill << " " << l1_grestore << "\n";
+ }
+ // Gradient.
+ else if( fill.type() == VFill::grad )
+ {
+ if( m_psLevel == 3 )
+ {
+ // "gsave".
+ *m_stream << l1_gsave << " ";
+
+ VGradient grad = fill.gradient();
+ TQPtrVector<VColorStop> ramp = grad.colorStops();
+ if( ramp.size() < 2 )
+ {
+ if( ramp.size() == 1 )
+ getColor( ramp[0]->color );
+ }
+ if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
+ {
+ // Gradient with more than two colors or asymmetrical midpoint.
+ for( uint i = 1;i < ramp.size();i++ )
+ {
+ char name[15];
+ sprintf( name, "Function%d", 2 * i - 1 );
+
+ VColorStop stop1 = *ramp[i - 1];
+ VColorStop stop2 = *ramp[i];
+ VColor mid;
+ 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] ) );
+ *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n"
+ << "\t/Domain [ 0 1 ] def\n" << "\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " "
+ << stop1.color[2] << " ] def\n" << "\t/C1 [ " << mid[0] << " " << mid[1] << " "
+ << mid[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
+
+ sprintf( name, "Function%d", 2 * i );
+
+ *m_stream << "/" << name << " 7 dict def " << name << " begin\n" << "\t/FunctionType 2 def\n" << "\t/Domain [ 0 1 ] def\n"
+ << "\t/C0 [ " << mid[0] << " " << mid[1] << " " << mid[2] << " ] def\n" << "\t/C1 [ " << stop2.color[0] << " "
+ << stop2.color[1] << " " << stop2.color[2] << " ] def\n" << "\t/N 1 def\n" << "end\n";
+ }
+ }
+ if( grad.type() == VGradient::linear )
+ *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 2\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
+ << grad.origin().x() << " " << grad.origin().y() << " " << grad.vector().x() << " " << grad.vector().y() << " ]\n\t/Extend[ true true ]\n" << "\t/Function <<\n";
+ else if( grad.type() == VGradient::radial )
+ {
+ double r = sqrt( pow( grad.vector().x() - grad.origin().x(), 2 ) + pow( grad.vector().y() - grad.origin().y(), 2 ) );
+ *m_stream << "clip newpath\n" << "/DeviceRGB setcolorspace\n" << "<<\n" << "\t/ShadingType 3\n" << "\t/ColorSpace /DeviceRGB\n" << "\t/Coords [ "
+ << grad.origin().x() << " " << grad.origin().y() << " 0.0 " << grad.origin().x() << " " << grad.origin().y()
+ << " " << r << "]\n\t\t/Extend [ false true ]\n" << "\t/Function <<\n";
+ }
+ if( ramp.size() == 2 && ramp[0]->midPoint == 0.5 )
+ {
+ // Gradient with only two colors and symmetrical midpoint.
+ VColorStop stop1 = *ramp[0];
+ VColorStop stop2 = *ramp[1];
+ *m_stream << "\t\t/FunctionType 2\n" << "\t\t/C0 [ " << stop1.color[0] << " " << stop1.color[1] << " " << stop1.color[2]
+ << " ]\n" << "\t\t/C1 [ " << stop2.color[0] << " " << stop2.color[1] << " " << stop2.color[2] << " ]\n" << "\t\t/N 1\n";
+ }
+ else if( ramp.size() > 2 || ramp.size() == 2 && ramp[0]->midPoint != 0.5 )
+ {
+ // Gradient with more than two colors or asymmetrical midpoint.
+ *m_stream << "\t\t/FunctionType 3\n" << "\t\t/Functions [ ";
+ for( uint i = 1; i < ( 2 * ramp.size() - 1 );i++ )
+ *m_stream << "Function" << i << " ";
+ *m_stream << "]\n" << "\t\t/Bounds [";
+ for( uint i = 0;i < ramp.size() - 1;i++ )
+ {
+ VColorStop stop = *ramp[i];
+ if( i > 0 )
+ *m_stream << " " << stop.rampPoint;
+ *m_stream << " " << ( stop.rampPoint + ( ramp[i + 1]->rampPoint - stop.rampPoint ) * stop.midPoint );
+ }
+ *m_stream << " ]\n" << "\t\t/Encode [ ";
+ for( uint i = 0;i < 2 * ramp.size() - 2;i++ )
+ *m_stream << "0 1 ";
+ *m_stream << "]\n";
+ }
+ *m_stream << "\t\t/Domain [ " << ramp[0]->rampPoint << " "
+ << ramp[ramp.size() - 1]->rampPoint << " ]\n" << "\t>>\n" << ">>\n";
+ // "shfill", "grestore".
+ *m_stream << " shfill " << l1_grestore << "\n";
+ }
+ }
+}
+
+void
+EpsExport::getColor( const VColor& color )
+{
+ VColor copy( color );
+ copy.setColorSpace( VColor::rgb );
+
+ *m_stream <<
+ copy[0] << " " <<
+ copy[1] << " " <<
+ copy[2] << " " << l1_setrgbcolor;
+}
+
+bool
+EpsExport::isVisible( const VObject* object ) const
+{
+ return object->state() != VObject::hidden && object->state() != VObject::hidden_locked;
+}
+
+#include "epsexport.moc"