diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /lib/kwmf | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/kwmf')
-rw-r--r-- | lib/kwmf/Makefile.am | 19 | ||||
-rw-r--r-- | lib/kwmf/kowmfpaint.cc | 297 | ||||
-rw-r--r-- | lib/kwmf/kowmfpaint.h | 127 | ||||
-rw-r--r-- | lib/kwmf/kowmfread.cc | 101 | ||||
-rw-r--r-- | lib/kwmf/kowmfread.h | 154 | ||||
-rw-r--r-- | lib/kwmf/kowmfreadprivate.cc | 1251 | ||||
-rw-r--r-- | lib/kwmf/kowmfreadprivate.h | 362 | ||||
-rw-r--r-- | lib/kwmf/kowmfstack.cc | 38 | ||||
-rw-r--r-- | lib/kwmf/kowmfstack.h | 74 | ||||
-rw-r--r-- | lib/kwmf/kowmfstruct.h | 147 | ||||
-rw-r--r-- | lib/kwmf/kowmfwrite.cc | 456 | ||||
-rw-r--r-- | lib/kwmf/kowmfwrite.h | 142 | ||||
-rw-r--r-- | lib/kwmf/kwmf.cc | 964 | ||||
-rw-r--r-- | lib/kwmf/kwmf.h | 220 | ||||
-rw-r--r-- | lib/kwmf/metafuncs.h | 90 | ||||
-rw-r--r-- | lib/kwmf/qwmf.cc | 1258 | ||||
-rw-r--r-- | lib/kwmf/qwmf.h | 231 | ||||
-rw-r--r-- | lib/kwmf/wmfstruct.h | 107 |
18 files changed, 6038 insertions, 0 deletions
diff --git a/lib/kwmf/Makefile.am b/lib/kwmf/Makefile.am new file mode 100644 index 00000000..b257f435 --- /dev/null +++ b/lib/kwmf/Makefile.am @@ -0,0 +1,19 @@ +####### General stuff + +INCLUDES= $(KOFFICECORE_INCLUDES) -I$(srcdir) $(all_includes) +libkwmf_la_LDFLAGS = $(all_libraries) -version-info 3:0:0 -no-undefined +# We use kdecore for kdDebug :) +libkwmf_la_LIBADD = $(LIB_KDECORE) + +####### Files + +lib_LTLIBRARIES = libkwmf.la libkowmf.la + +libkwmf_la_SOURCES = kwmf.cc qwmf.cc + +#include_HEADERS = kowmfread.h kowmfwrite.h kowmfpaint.h +noinst_HEADERS = kwmf.h qwmf.h metafuncs.h wmfstruct.h kowmfreadprivate.h kowmfstack.h kowmfstruct.h + +libkowmf_la_SOURCES = kowmfreadprivate.cc kowmfstack.cc kowmfread.cc kowmfwrite.cc kowmfpaint.cc +libkowmf_la_LDFLAGS = $(all_libraries) -version-info 2:0:0 -no-undefined +libkowmf_la_LIBADD = $(LIB_KDECORE) diff --git a/lib/kwmf/kowmfpaint.cc b/lib/kwmf/kowmfpaint.cc new file mode 100644 index 00000000..7ce8ee8b --- /dev/null +++ b/lib/kwmf/kowmfpaint.cc @@ -0,0 +1,297 @@ +/* This file is part of the KDE libraries + * Copyright (c) 2003 thierry lorthiois ([email protected]) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 <kdebug.h> + +#include "kowmfpaint.h" + +KoWmfPaint::KoWmfPaint() : KoWmfRead() { + mTarget = 0; +} + + +bool KoWmfPaint::play( QPaintDevice& target, bool relativeCoord ) +{ + if ( mPainter.isActive() ) return false; + mTarget = ⌖ + mRelativeCoord = relativeCoord; + + // Play the wmf file + return KoWmfRead::play( ); +} + + +//----------------------------------------------------------------------------- +// Virtual Painter + +bool KoWmfPaint::begin() { + bool ret = mPainter.begin( mTarget ); + + if ( ret ) { + if ( mRelativeCoord ) { + mInternalWorldMatrix.reset(); + } + else { + // some wmf files doesn't call setwindowOrg and setWindowExt, so it's better to do : + QRect rec = boundingRect(); + mPainter.setWindow( rec.left(), rec.top(), rec.width(), rec.height() ); + } + } + return ret; +} + + +bool KoWmfPaint::end() { + if ( mRelativeCoord ) { + QRect rec = boundingRect(); + + // Draw 2 invisible points + // because QPicture::setBoundingRect() doesn't give expected result (QT3.1.2) + // setBoundingRect( boundingRect() ); +// mPainter.setPen( Qt::NoPen ); +// mPainter.drawPoint( rec.left(), rec.top() ); +// mPainter.drawPoint( rec.right(), rec.bottom() ); + } + return mPainter.end(); +} + + +void KoWmfPaint::save() { + mPainter.save(); +} + + +void KoWmfPaint::restore() { + mPainter.restore(); +} + + +void KoWmfPaint::setFont( const QFont &font ) { + mPainter.setFont( font ); +} + + +void KoWmfPaint::setPen( const QPen &pen ) { + QPen p = pen; + int width = pen.width(); + + if ( mTarget->isExtDev() ) { + width = 0; + } + else { + // WMF spec : width of pen in logical coordinate + // => width of pen proportional with device context width + QRect devRec = mPainter.xForm( mPainter.window() ); + QRect rec = mPainter.window(); + if ( rec.width() != 0 ) + width = ( width * devRec.width() ) / rec.width() ; + else + width = 0; + } + + p.setWidth( width ); + mPainter.setPen( p ); +} + + +const QPen &KoWmfPaint::pen() const { + return mPainter.pen(); +} + + +void KoWmfPaint::setBrush( const QBrush &brush ) { + mPainter.setBrush( brush ); +} + + +void KoWmfPaint::setBackgroundColor( const QColor &c ) { + mPainter.setBackgroundColor( c ); +} + + +void KoWmfPaint::setBackgroundMode( Qt::BGMode mode ) { + mPainter.setBackgroundMode( mode ); +} + + +void KoWmfPaint::setRasterOp( Qt::RasterOp op ) { + mPainter.setRasterOp( op ); +} + + +// --------------------------------------------------------------------- +// To change those functions it's better to have +// a large set of WMF files. WMF special case includes : +// - without call to setWindowOrg and setWindowExt +// - change the origin or the scale in the middle of the drawing +// - negative width or height +// and relative/absolute coordinate +void KoWmfPaint::setWindowOrg( int left, int top ) { + if ( mRelativeCoord ) { + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + + // translation : Don't use setWindow() + mInternalWorldMatrix.translate( -dx, -dy ); + mPainter.translate( -dx, -dy ); + mInternalWorldMatrix.translate( -left, -top ); + mPainter.translate( -left, -top ); + } + else { + QRect rec = mPainter.window(); + mPainter.setWindow( left, top, rec.width(), rec.height() ); + } +} + + +void KoWmfPaint::setWindowExt( int w, int h ) { + if ( mRelativeCoord ) { + QRect r = mPainter.window(); + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + double sx = mInternalWorldMatrix.m11(); + double sy = mInternalWorldMatrix.m22(); + + // scale : don't use setWindow() + mInternalWorldMatrix.translate( -dx, -dy ); + mPainter.translate( -dx, -dy ); + mInternalWorldMatrix.scale( 1/sx, 1/sy ); + mPainter.scale( 1/sx, 1/sy ); + + sx = (double)r.width() / (double)w; + sy = (double)r.height() / (double)h; + + mInternalWorldMatrix.scale( sx, sy ); + mPainter.scale( sx, sy ); + mInternalWorldMatrix.translate( dx, dy ); + mPainter.translate( dx, dy ); + } + else { + QRect rec = mPainter.window(); + mPainter.setWindow( rec.left(), rec.top(), w, h ); + } +} + + +void KoWmfPaint::setWorldMatrix( const QWMatrix &wm, bool combine ) { + mPainter.setWorldMatrix( wm, combine ); +} + + +void KoWmfPaint::setClipRegion( const QRegion &rec ) { + mPainter.setClipRegion( rec, QPainter::CoordPainter ); +} + + +QRegion KoWmfPaint::clipRegion() { + return mPainter.clipRegion( QPainter::CoordPainter ); +} + + +void KoWmfPaint::moveTo( int x, int y ) { + mPainter.moveTo( x, y ); +} + + +void KoWmfPaint::lineTo( int x, int y ) { + mPainter.lineTo( x, y ); +} + + +void KoWmfPaint::drawRect( int x, int y, int w, int h ) { + mPainter.drawRect( x, y, w, h ); +} + + +void KoWmfPaint::drawRoundRect( int x, int y, int w, int h, int roudw, int roudh ) { + mPainter.drawRoundRect( x, y, w, h, roudw, roudh ); +} + + +void KoWmfPaint::drawEllipse( int x, int y, int w, int h ) { + mPainter.drawEllipse( x, y, w, h ); +} + + +void KoWmfPaint::drawArc( int x, int y, int w, int h, int a, int alen ) { + mPainter.drawArc( x, y, w, h, a, alen ); +} + + +void KoWmfPaint::drawPie( int x, int y, int w, int h, int a, int alen ) { + mPainter.drawPie( x, y, w, h, a, alen ); +} + + +void KoWmfPaint::drawChord( int x, int y, int w, int h, int a, int alen ) { + mPainter.drawChord( x, y, w, h, a, alen ); +} + + +void KoWmfPaint::drawPolyline( const QPointArray &pa ) { + mPainter.drawPolyline( pa ); +} + + +void KoWmfPaint::drawPolygon( const QPointArray &pa, bool winding ) { + mPainter.drawPolygon( pa, winding ); +} + + +void KoWmfPaint::drawPolyPolygon( QPtrList<QPointArray>& listPa, bool winding ) { + QPointArray *pa; + + mPainter.save(); + QBrush brush = mPainter.brush(); + + // define clipping region + QRegion region; + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + region = region.eor( *pa ); + } + mPainter.setClipRegion( region, QPainter::CoordPainter ); + + // fill polygons + if ( brush != Qt::NoBrush ) { + mPainter.fillRect( region.boundingRect(), brush ); + } + + // draw polygon's border + mPainter.setClipping( false ); + if ( mPainter.pen().style() != Qt::NoPen ) { + mPainter.setBrush( Qt::NoBrush ); + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + mPainter.drawPolygon( *pa, winding ); + } + } + + // restore previous state + mPainter.restore(); +} + + +void KoWmfPaint::drawImage( int x, int y, const QImage &img, int sx, int sy, int sw, int sh ) { + mPainter.drawImage( x, y, img, sx, sy, sw, sh ); +} + + +void KoWmfPaint::drawText( int x, int y, int w, int h, int flags, const QString& s, double ) { + mPainter.drawText( x, y, w, h, flags, s ); +} + + diff --git a/lib/kwmf/kowmfpaint.h b/lib/kwmf/kowmfpaint.h new file mode 100644 index 00000000..b229f2ff --- /dev/null +++ b/lib/kwmf/kowmfpaint.h @@ -0,0 +1,127 @@ +/* This file is part of the KDE libraries + * Copyright (c) 2003 thierry lorthiois ([email protected]) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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. +*/ +#ifndef _KOWMFPAINT_H_ +#define _KOWMFPAINT_H_ + +#include <qpainter.h> + +#include "kowmfread.h" +#include <../kofficecore/koffice_export.h> +/** + * KoWmfPaint inherits the abstract class KoWmfRead + * and redirects WMF actions onto a QPaintDevice. + * Uses relative or absolute coordinate. + * + * how to use: + * <pre> + * QPixmap pix( 100, 100 ); + * KoWmfPaint wmf; + * if ( wmf.load( "/home/test.wmf" ) ) { + * wmf.play( pix ); + * } + * paint.drawPixmap( 0, 0, pix ); + * </pre> + * + */ + +class KOWMF_EXPORT KoWmfPaint : public KoWmfRead +{ +public: + KoWmfPaint(); + ~KoWmfPaint() { } + + /** + * play WMF file on a QPaintDevice. Return true on success. + * Use absolute or relative coordinate : + * absolute coord. reset the world transfomation Matrix (by default) + * relative coord. use the existing world transfomation Matrix + */ + bool play( QPaintDevice& target, bool relativeCoord=false ); + + +private: + // ------------------------------------------------------------------------- + // A virtual QPainter + bool begin(); + bool end(); + void save(); + void restore(); + + // Drawing tools + void setFont( const QFont& font ); + // the pen : the width of the pen is in logical coordinate + void setPen( const QPen& pen ); + const QPen& pen() const; + void setBrush( const QBrush& brush ); + + // Drawing attributes/modes + void setBackgroundColor( const QColor& c ); + void setBackgroundMode( Qt::BGMode mode ); + void setRasterOp( Qt::RasterOp op ); + + /** + * Change logical Coordinate + * some wmf files call those functions several times in the middle of a drawing + * others wmf files doesn't call setWindow* at all + * negative width and height are possible + */ + void setWindowOrg( int left, int top ); + void setWindowExt( int width, int height ); + + // Clipping + // the 'CoordinateMode' is ommitted : always CoordPainter in wmf + // setClipRegion() is often used with save() and restore() => implement all or none + void setClipRegion( const QRegion &rec ); + QRegion clipRegion(); + + // Graphics drawing functions + void moveTo( int x, int y ); + void lineTo( int x, int y ); + void drawRect( int x, int y, int w, int h ); + void drawRoundRect( int x, int y, int w, int h, int = 25, int = 25 ); + void drawEllipse( int x, int y, int w, int h ); + void drawArc( int x, int y, int w, int h, int a, int alen ); + void drawPie( int x, int y, int w, int h, int a, int alen ); + void drawChord( int x, int y, int w, int h, int a, int alen ); + void drawPolyline( const QPointArray& pa ); + void drawPolygon( const QPointArray& pa, bool winding=FALSE ); + /** + * drawPolyPolygon draw the XOR of a list of polygons + * listPa : list of polygons + */ + void drawPolyPolygon( QPtrList<QPointArray>& listPa, bool winding=FALSE ); + void drawImage( int x, int y, const QImage &, int sx = 0, int sy = 0, int sw = -1, int sh = -1 ); + + // Text drawing functions + // rotation = the degrees of rotation in counterclockwise + // not yet implemented in KWinMetaFile + void drawText( int x, int y, int w, int h, int flags, const QString &s, double rotation ); + + // matrix transformation : only used in some bitmap manipulation + void setWorldMatrix( const QWMatrix &, bool combine=FALSE ); + +private: + QPainter mPainter; + QPaintDevice *mTarget; + bool mRelativeCoord; + // memorisation of WMF matrix transformation (in relative coordinate) + QWMatrix mInternalWorldMatrix; + +}; + +#endif diff --git a/lib/kwmf/kowmfread.cc b/lib/kwmf/kowmfread.cc new file mode 100644 index 00000000..a4df0023 --- /dev/null +++ b/lib/kwmf/kowmfread.cc @@ -0,0 +1,101 @@ +/* This file is part of the KDE libraries + * Copyright (c) 2003 thierry lorthiois ([email protected]) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 <qfile.h> +#include <kdebug.h> + +#include "kowmfread.h" +#include "kowmfreadprivate.h" + +KoWmfRead::KoWmfRead() { + mKwmf = new KoWmfReadPrivate(); +} + +KoWmfRead::~KoWmfRead() { + delete mKwmf; +} + + +bool KoWmfRead::load( const QString& filename ) +{ + QFile file( filename ); + + if ( !file.open( IO_ReadOnly ) ) + { + kdDebug() << "KoWmfRead : Cannot open file " << QFile::encodeName(filename) << endl; + return false; + } + + bool ret = mKwmf->load( file.readAll() ); + file.close(); + + return ret; +} + + +bool KoWmfRead::load( const QByteArray& array ) +{ + return mKwmf->load( array ); +} + + +bool KoWmfRead::play( ) +{ + return mKwmf->play( this ); +} + + +bool KoWmfRead::isValid( void ) const { + return mKwmf->mValid; +} + + +bool KoWmfRead::isStandard( void ) const { + return mKwmf->mStandard; +} + + +bool KoWmfRead::isPlaceable( void ) const { + return mKwmf->mPlaceable; +} + + +bool KoWmfRead::isEnhanced( void ) const { + return mKwmf->mEnhanced; +} + + +QRect KoWmfRead::boundingRect( void ) const { + return mKwmf->mBBox; +} + + +int KoWmfRead::defaultDpi( void ) const { + if ( mKwmf->mPlaceable ) { + return mKwmf->mDpi; + } + else { + return 0; + } +} + + +void KoWmfRead::setDebug( int nbrFunc ) { + mKwmf->mNbrFunc = nbrFunc; +} + diff --git a/lib/kwmf/kowmfread.h b/lib/kwmf/kowmfread.h new file mode 100644 index 00000000..becfc74f --- /dev/null +++ b/lib/kwmf/kowmfread.h @@ -0,0 +1,154 @@ +/* This file is part of the KDE libraries + Copyright (c) 2003 thierry lorthiois ([email protected]) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef _KOWMFREAD_H_ +#define _KOWMFREAD_H_ + +#include <qpen.h> +#include <qbrush.h> +#include <qfont.h> +#include <qcolor.h> +#include <qrect.h> +#include <qregion.h> +#include <qimage.h> +#include <qwmatrix.h> +#include <qstring.h> +#include <qptrlist.h> +#include <qpointarray.h> + +#include <../kofficecore/koffice_export.h> +class KoWmfReadPrivate; + +/** + * KoWmfRead allows the redirection of the actions stored in a WMF file. + * Most of the virtuals functions are compatible with QPainter format. + * + * How to use : + * inherit this class and define abstract functions + * then create an object and call @ref load() and @ref play() + * + */ + +class KOWMF_EXPORT KoWmfRead +{ +public: + KoWmfRead(); + virtual ~KoWmfRead(); + + /** + * Load WMF file. Returns true on success. + */ + virtual bool load( const QString& fileName ); + virtual bool load( const QByteArray& array ); + + /** + * play the WMF file => call virtuals functions + */ + virtual bool play( ); + + /** + * Returns true if the metafile is standard / placeable / enhanced / valid + */ + bool isStandard( void ) const; + bool isPlaceable( void ) const; + bool isEnhanced( void ) const; + bool isValid( void ) const; + + /** + * Returns the bounding rectangle + * Standard Meta File : return the bounding box from setWindowOrg and setWindowExt (slow) + * Placeable Meta File : return the bounding box from header + * always in logical coordinate + */ + virtual QRect boundingRect( void ) const; + + /** + * Returns the default DotPerInch for placeable meta file, + * return 0 for Standard meta file + */ + int defaultDpi( void ) const; + + /** + * Activate debug mode. + * nbFunc : number of functions to draw + * nbFunc!=0 switch to debug mode with trace + */ + void setDebug( int nbFunc ); + + // ------------------------------------------------------------------------- + // A virtual QPainter : inherit those virtuals functions + // for a good documentation : check QPainter documentation + virtual bool begin() = 0; + virtual bool end() = 0; + virtual void save() = 0; + virtual void restore() = 0; + + // Drawing tools + virtual void setFont( const QFont & ) = 0; + // the pen : the width of the pen is in logical coordinate + virtual void setPen( const QPen &p ) = 0; + virtual const QPen &pen() const = 0; + virtual void setBrush( const QBrush & ) = 0; + + // Drawing attributes/modes + virtual void setBackgroundColor( const QColor & ) = 0; + virtual void setBackgroundMode( Qt::BGMode ) = 0; + virtual void setRasterOp( Qt::RasterOp ) = 0; + + // Change logical Coordinate + // some wmf files call those functions several times in the middle of a drawing + // others doesn't call setWindow* at all + virtual void setWindowOrg( int left, int top ) = 0; + virtual void setWindowExt( int width, int height ) = 0; + + // Clipping + // the 'CoordinateMode' parameter is ommitted : always CoordPainter in wmf + // setClipRegion() is often used with save() and restore() => implement all or none + virtual void setClipRegion( const QRegion & ) = 0; + virtual QRegion clipRegion() = 0; + + // Graphics drawing functions + virtual void moveTo( int x, int y ) = 0; + virtual void lineTo( int x, int y ) = 0; + virtual void drawRect( int x, int y, int w, int h ) = 0; + virtual void drawRoundRect( int x, int y, int w, int h, int = 25, int = 25 ) = 0; + virtual void drawEllipse( int x, int y, int w, int h ) = 0; + virtual void drawArc( int x, int y, int w, int h, int a, int alen ) = 0; + virtual void drawPie( int x, int y, int w, int h, int a, int alen ) = 0; + virtual void drawChord( int x, int y, int w, int h, int a, int alen ) = 0; + virtual void drawPolyline( const QPointArray &pa ) = 0; + virtual void drawPolygon( const QPointArray &pa, bool winding=FALSE ) = 0; + // drawPolyPolygon draw the XOR of a list of polygons + // listPa : list of polygons + virtual void drawPolyPolygon( QPtrList<QPointArray>& listPa, bool winding=FALSE ) = 0; + virtual void drawImage( int x, int y, const QImage &, int sx = 0, int sy = 0, int sw = -1, int sh = -1 ) = 0; + + // Text drawing functions + // rotation = the degrees of rotation in counterclockwise + // not yet implemented in KWinMetaFile + virtual void drawText( int x, int y, int w, int h, int flags, const QString &s, double rotation ) = 0; + + // matrix transformation : only used for bitmap manipulation + virtual void setWorldMatrix( const QWMatrix &, bool combine=FALSE ) = 0; + +private: + KoWmfReadPrivate *mKwmf; + +}; + +#endif + diff --git a/lib/kwmf/kowmfreadprivate.cc b/lib/kwmf/kowmfreadprivate.cc new file mode 100644 index 00000000..7a8c5efa --- /dev/null +++ b/lib/kwmf/kowmfreadprivate.cc @@ -0,0 +1,1251 @@ +/* This file is part of the KDE libraries + * Copyright (c) 1998 Stefan Taferner + * 2001/2003 thierry lorthiois ([email protected]) + * With the help of WMF documentation by Caolan Mc Namara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 <math.h> +#include <qfileinfo.h> +#include <qimage.h> +#include <qwmatrix.h> +#include <qptrlist.h> +#include <qpointarray.h> +#include <qdatastream.h> +#include <kdebug.h> + +#include "kowmfreadprivate.h" +#include "kowmfread.h" + + +KoWmfReadPrivate::KoWmfReadPrivate() +{ + mNbrFunc = 0; + mValid = false; + mStandard = false; + mPlaceable = false; + mEnhanced = false; + mBuffer = 0; + mObjHandleTab = 0; +} + + +KoWmfReadPrivate::~KoWmfReadPrivate() +{ + if ( mObjHandleTab != 0 ) { + for ( int i=0 ; i < mNbrObject ; i++ ) { + if ( mObjHandleTab[i] != 0 ) + delete mObjHandleTab[i]; + } + delete[] mObjHandleTab; + } + if ( mBuffer != 0 ) { + mBuffer->close(); + delete mBuffer; + } +} + + +bool KoWmfReadPrivate::load( const QByteArray& array ) +{ + // delete previous buffer + if ( mBuffer != 0 ) { + mBuffer->close(); + delete mBuffer; + } + + // load into buffer + mBuffer = new QBuffer( array ); + mBuffer->open( IO_ReadOnly ); + + // read and check the header + WmfEnhMetaHeader eheader; + WmfMetaHeader header; + WmfPlaceableHeader pheader; + unsigned short checksum; + int filePos; + + QDataStream st( mBuffer ); + st.setByteOrder( QDataStream::LittleEndian ); + mStackOverflow = mWinding = false; + mTextAlign = mTextRotation = 0; + mTextColor = Qt::black; + mValid = false; + mStandard = false; + mPlaceable = false; + mEnhanced = false; + + //----- Read placeable metafile header + st >> pheader.key; + if ( pheader.key==( Q_UINT32 )APMHEADER_KEY ) { + mPlaceable = true; + st >> pheader.handle; + st >> pheader.left; + st >> pheader.top; + st >> pheader.right; + st >> pheader.bottom; + st >> pheader.inch; + st >> pheader.reserved; + st >> pheader.checksum; + checksum = calcCheckSum( &pheader ); + if ( pheader.checksum!=checksum ) { + return false; + } + st >> header.fileType; + st >> header.headerSize; + st >> header.version; + st >> header.fileSize; + st >> header.numOfObjects; + st >> header.maxRecordSize; + st >> header.numOfParameters; + mNbrObject = header.numOfObjects; + mBBox.setLeft( pheader.left ); + mBBox.setTop( pheader.top ); + mBBox.setRight( pheader.right ); + mBBox.setBottom( pheader.bottom ); + mDpi = pheader.inch; + } + else { + mBuffer->at( 0 ); + //----- Read as enhanced metafile header + filePos = mBuffer->at(); + st >> eheader.recordType; + st >> eheader.recordSize; + st >> eheader.boundsLeft; + st >> eheader.boundsTop; + st >> eheader.boundsRight; + st >> eheader.boundsBottom; + st >> eheader.frameLeft; + st >> eheader.frameTop; + st >> eheader.frameRight; + st >> eheader.frameBottom; + st >> eheader.signature; + if ( eheader.signature==ENHMETA_SIGNATURE ) { + mEnhanced = true; + st >> eheader.version; + st >> eheader.size; + st >> eheader.numOfRecords; + st >> eheader.numHandles; + st >> eheader.reserved; + st >> eheader.sizeOfDescription; + st >> eheader.offsetOfDescription; + st >> eheader.numPaletteEntries; + st >> eheader.widthDevicePixels; + st >> eheader.heightDevicePixels; + st >> eheader.widthDeviceMM; + st >> eheader.heightDeviceMM; + } + else { + //----- Read as standard metafile header + mStandard = true; + mBuffer->at( filePos ); + st >> header.fileType; + st >> header.headerSize; + st >> header.version; + st >> header.fileSize; + st >> header.numOfObjects; + st >> header.maxRecordSize; + st >> header.numOfParameters; + mNbrObject = header.numOfObjects; + } + } + mOffsetFirstRecord = mBuffer->at(); + + //----- Test header validity + if ( ((header.headerSize == 9) && (header.numOfParameters == 0)) || (mPlaceable) ) { + // valid wmf file + mValid = true; + } + else { + kdDebug() << "KoWmfReadPrivate : incorrect file format !" << endl; + } + + // check bounding rectangle for standard meta file + if ( (mValid) && (mStandard) ) { + Q_UINT16 numFunction = 1; + Q_UINT32 size; + bool firstOrg=true, firstExt=true; + + // search functions setWindowOrg and setWindowExt + while ( numFunction ) { + filePos = mBuffer->at(); + st >> size >> numFunction; + + if ( size == 0 ) { + kdDebug() << "KoWmfReadPrivate : incorrect file!" << endl; + mValid = 0; + break; + } + + numFunction &= 0xFF; + if ( numFunction == 11 ) { + Q_INT16 top, left; + + st >> top >> left; + if ( firstOrg ) { + firstOrg = false; + mBBox.setLeft( left ); + mBBox.setTop( top ); + } + else { + if ( left < mBBox.left() ) mBBox.setLeft( left ); + if ( top < mBBox.top() ) mBBox.setTop( top ); + } + } + if ( numFunction == 12 ) { + Q_INT16 width, height; + + st >> height >> width; + if ( width < 0 ) width = -width; + if ( height < 0 ) height = -height; + if ( firstExt ) { + firstExt = false; + mBBox.setWidth( width ); + mBBox.setHeight( height ); + } + else { + if ( width > mBBox.width() ) mBBox.setWidth( width ); + if ( height > mBBox.height() ) mBBox.setHeight( height ); + } + } + mBuffer->at( filePos + (size<<1) ); + // ## shouldn't we break from the loop as soon as we found what we were looking for? + } + } + + return (mValid); +} + + +bool KoWmfReadPrivate::play( KoWmfRead* readWmf ) +{ + if ( !(mValid) ) { + kdDebug() << "KoWmfReadPrivate::play : invalid WMF file" << endl; + return false; + } + + if ( mNbrFunc ) { + if ( (mStandard) ) { + kdDebug() << "Standard : " << mBBox.left() << " " << mBBox.top() << " " << mBBox.width() << " " << mBBox.height() << endl; + } + else { + kdDebug() << "DPI : " << mDpi << " : " << mBBox.left() << " " << mBBox.top() << " " << mBBox.width() << " " << mBBox.height() << endl; + kdDebug() << "inch : " << mBBox.width()/mDpi << " " << mBBox.height()/mDpi << endl; + kdDebug() << "mm : " << mBBox.width()*25.4/mDpi << " " << mBBox.height()*25.4/mDpi << endl; + } + kdDebug() << mValid << " " << mStandard << " " << mPlaceable << endl; + } + + // stack of handle + mObjHandleTab = new KoWmfHandle* [ mNbrObject ]; + for ( int i=0; i < mNbrObject ; i++ ) { + mObjHandleTab[ i ] = 0; + } + + Q_UINT16 numFunction; + Q_UINT32 size; + int bufferOffset, j; + + // buffer with functions + QDataStream st( mBuffer ); + st.setByteOrder( QDataStream::LittleEndian ); + + mReadWmf = readWmf; + mWindow = mBBox; + if ( mReadWmf->begin() ) { + // play wmf functions + mBuffer->at( mOffsetFirstRecord ); + numFunction = j = 1; + mWinding = false; + + while ( ( numFunction ) && ( !mStackOverflow ) ) { + bufferOffset = mBuffer->at(); + st >> size >> numFunction; + + /** + * mapping between n� function and index of table 'metaFuncTab' + * lower 8 digits of the function => entry in the table + */ + numFunction &= 0xFF; + if ( numFunction > 0x5F ) { + numFunction -= 0x90; + } + if ( (numFunction > 111) || (koWmfFunc[ numFunction ].method == 0) ) { + // function outside WMF specification + kdDebug() << "KoWmfReadPrivate::paint : BROKEN WMF file" << endl; + mValid = false; + break; + } + + if ( mNbrFunc ) { + // debug mode + if ( (j+12) > mNbrFunc ) { + // output last 12 functions + int offBuff = mBuffer->at(); + Q_UINT16 param; + + kdDebug() << j << " : " << numFunction << " : "; + for ( Q_UINT16 i=0 ; i < (size-3) ; i++ ) { + st >> param; + kdDebug() << param << " "; + } + kdDebug() << endl; + mBuffer->at( offBuff ); + } + if ( j >= mNbrFunc ) { + break; + } + j++; + } + + // execute the function + (this->*koWmfFunc[ numFunction ].method)( size, st ); + + mBuffer->at( bufferOffset + (size<<1) ); + } + + mReadWmf->end(); + } + + for ( int i=0 ; i < mNbrObject ; i++ ) { + if ( mObjHandleTab[ i ] != 0 ) + delete mObjHandleTab[ i ]; + } + delete[] mObjHandleTab; + mObjHandleTab = 0; + + return true; +} + + +//----------------------------------------------------------------------------- +// Metafile painter methods + +void KoWmfReadPrivate::setWindowOrg( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left; + + stream >> top >> left; + mReadWmf->setWindowOrg( left, top ); + mWindow.setLeft( left ); + mWindow.setTop( top ); +// kdDebug() << "Org : (" << left << ", " << top << ") " << endl; +} + +/* TODO : deeper look in negative width and height +*/ + +void KoWmfReadPrivate::setWindowExt( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 width, height; + + // negative value allowed for width and height + stream >> height >> width; + mReadWmf->setWindowExt( width, height ); + mWindow.setWidth( width ); + mWindow.setHeight( height ); +// kdDebug() << "Ext : (" << width << ", " << height << ") "<< endl; +} + + +void KoWmfReadPrivate::OffsetWindowOrg( Q_UINT32, QDataStream &stream ) +{ + Q_INT16 offTop, offLeft; + + stream >> offTop >> offLeft; + mReadWmf->setWindowOrg( mWindow.left() + offLeft, mWindow.top() + offTop ); + mWindow.setLeft( mWindow.left() + offLeft ); + mWindow.setTop( mWindow.top() + offTop ); +} + + +void KoWmfReadPrivate::ScaleWindowExt( Q_UINT32, QDataStream &stream ) +{ + Q_INT16 width, height; + Q_INT16 heightDenom, heightNum, widthDenom, widthNum; + + stream >> heightDenom >> heightNum >> widthDenom >> widthNum; + + if ( ( widthDenom != 0 ) && ( heightDenom != 0 ) ) { + width = (mWindow.width() * widthNum) / widthDenom; + height = (mWindow.height() * heightNum) / heightDenom; + mReadWmf->setWindowExt( width, height ); + mWindow.setWidth( width ); + mWindow.setHeight( height ); + } +// kdDebug() << "KoWmfReadPrivate::ScaleWindowExt : " << widthDenom << " " << heightDenom << endl; +} + + +//----------------------------------------------------------------------------- +// Drawing + +void KoWmfReadPrivate::lineTo( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left; + + stream >> top >> left; + mReadWmf->lineTo( left, top ); +} + + +void KoWmfReadPrivate::moveTo( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left; + + stream >> top >> left; + mReadWmf->moveTo( left, top ); +} + + +void KoWmfReadPrivate::ellipse( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left, right, bottom; + + stream >> bottom >> right >> top >> left; + mReadWmf->drawEllipse( left, top, right-left, bottom-top ); +} + + +void KoWmfReadPrivate::polygon( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 num; + + stream >> num; + + QPointArray pa( num ); + + pointArray( stream, pa ); + mReadWmf->drawPolygon( pa, mWinding ); +} + + +void KoWmfReadPrivate::polyPolygon( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 numberPoly; + Q_UINT16 sizePoly; + QPtrList<QPointArray> listPa; + + stream >> numberPoly; + + listPa.setAutoDelete( true ); + for ( int i=0 ; i < numberPoly ; i++ ) { + stream >> sizePoly; + listPa.append( new QPointArray( sizePoly ) ); + } + + // list of point array + QPointArray *pa; + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + pointArray( stream, *pa ); + } + + // draw polygon's + mReadWmf->drawPolyPolygon( listPa, mWinding ); + listPa.clear(); +} + + +void KoWmfReadPrivate::polyline( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 num; + + stream >> num; + QPointArray pa( num ); + + pointArray( stream, pa ); + mReadWmf->drawPolyline( pa ); +} + + +void KoWmfReadPrivate::rectangle( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left, right, bottom; + + stream >> bottom >> right >> top >> left; + mReadWmf->drawRect( left, top, right-left, bottom-top ); +} + + +void KoWmfReadPrivate::roundRect( Q_UINT32, QDataStream& stream ) +{ + int xRnd = 0, yRnd = 0; + Q_UINT16 widthCorner, heightCorner; + Q_INT16 top, left, right, bottom; + + stream >> heightCorner >> widthCorner; + stream >> bottom >> right >> top >> left; + + // convert (widthCorner, heightCorner) in percentage + if ( (right - left) != 0 ) + xRnd = (widthCorner * 100) / (right - left); + if ( (bottom - top) != 0 ) + yRnd = (heightCorner * 100) / (bottom - top); + + mReadWmf->drawRoundRect( left, top, right-left, bottom-top, xRnd, yRnd ); +} + + +void KoWmfReadPrivate::arc( Q_UINT32, QDataStream& stream ) +{ + int xCenter, yCenter, angleStart, aLength; + Q_INT16 topEnd, leftEnd, topStart, leftStart; + Q_INT16 top, left, right, bottom; + + stream >> topEnd >> leftEnd >> topStart >> leftStart; + stream >> bottom >> right >> top >> left; + + xCenter = left + ((right-left) / 2); + yCenter = top + ((bottom-top) / 2); + xyToAngle ( leftStart-xCenter, yCenter-topStart, leftEnd-xCenter, yCenter-topEnd, angleStart, aLength ); + + mReadWmf->drawArc( left, top, right-left, bottom-top, angleStart, aLength); +} + + +void KoWmfReadPrivate::chord( Q_UINT32, QDataStream& stream ) +{ + int xCenter, yCenter, angleStart, aLength; + Q_INT16 topEnd, leftEnd, topStart, leftStart; + Q_INT16 top, left, right, bottom; + + stream >> topEnd >> leftEnd >> topStart >> leftStart; + stream >> bottom >> right >> top >> left; + + xCenter = left + ((right-left) / 2); + yCenter = top + ((bottom-top) / 2); + xyToAngle ( leftStart-xCenter, yCenter-topStart, leftEnd-xCenter, yCenter-topEnd, angleStart, aLength ); + + mReadWmf->drawChord( left, top, right-left, bottom-top, angleStart, aLength); +} + + +void KoWmfReadPrivate::pie( Q_UINT32, QDataStream& stream ) +{ + int xCenter, yCenter, angleStart, aLength; + Q_INT16 topEnd, leftEnd, topStart, leftStart; + Q_INT16 top, left, right, bottom; + + stream >> topEnd >> leftEnd >> topStart >> leftStart; + stream >> bottom >> right >> top >> left; + + xCenter = left + ((right-left) / 2); + yCenter = top + ((bottom-top) / 2); + xyToAngle ( leftStart-xCenter, yCenter-topStart, leftEnd-xCenter, yCenter-topEnd, angleStart, aLength ); + + mReadWmf->drawPie( left, top, right-left, bottom-top, angleStart, aLength); +} + + +void KoWmfReadPrivate::setPolyFillMode( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 winding; + + stream >> winding; + mWinding = (winding != 0); +} + + +void KoWmfReadPrivate::setBkColor( Q_UINT32, QDataStream& stream ) +{ + Q_UINT32 color; + + stream >> color; + mReadWmf->setBackgroundColor( qtColor( color ) ); +} + + +void KoWmfReadPrivate::setBkMode( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 bkMode; + + stream >> bkMode; + if ( bkMode == 1 ) + mReadWmf->setBackgroundMode( Qt::TransparentMode ); + else + mReadWmf->setBackgroundMode( Qt::OpaqueMode ); +} + + +void KoWmfReadPrivate::setPixel( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left; + Q_UINT32 color; + + stream >> color >> top >> left; + + QPen oldPen = mReadWmf->pen(); + QPen pen = oldPen; + pen.setColor( qtColor( color ) ); + mReadWmf->setPen( pen ); + mReadWmf->moveTo( left, top ); + mReadWmf->lineTo( left, top ); + mReadWmf->setPen( oldPen ); +} + + +void KoWmfReadPrivate::setRop( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 rop; + + stream >> rop; + mReadWmf->setRasterOp( winToQtRaster( rop ) ); +} + + +void KoWmfReadPrivate::saveDC( Q_UINT32, QDataStream& ) +{ + mReadWmf->save(); +} + + +void KoWmfReadPrivate::restoreDC( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 num; + + stream >> num; + for ( int i=0; i > num ; i-- ) + mReadWmf->restore(); +} + + +void KoWmfReadPrivate::intersectClipRect( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left, right, bottom; + + stream >> bottom >> right >> top >> left; + + QRegion region = mReadWmf->clipRegion(); + QRegion newRegion( left, top, right-left, bottom-top ); + if ( region.isEmpty() ) { + region = newRegion; + } + else { + region = region.intersect( newRegion ); + } + + mReadWmf->setClipRegion( region ); +} + + +void KoWmfReadPrivate::excludeClipRect( Q_UINT32, QDataStream& stream ) +{ + Q_INT16 top, left, right, bottom; + + stream >> bottom >> right >> top >> left; + + QRegion region = mReadWmf->clipRegion(); + QRegion newRegion( left, top, right-left, bottom-top ); + if ( region.isEmpty() ) { + region = newRegion; + } + else { + region = region.subtract( newRegion ); + } + + mReadWmf->setClipRegion( region ); +} + + +//----------------------------------------------------------------------------- +// Text + +void KoWmfReadPrivate::setTextColor( Q_UINT32, QDataStream& stream ) +{ + Q_UINT32 color; + + stream >> color; + mTextColor = qtColor( color ); +} + + +void KoWmfReadPrivate::setTextAlign( Q_UINT32, QDataStream& stream ) +{ + stream >> mTextAlign; +} + + +void KoWmfReadPrivate::textOut( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "textOut : unimplemented " << endl; + } +} + + +void KoWmfReadPrivate::extTextOut( Q_UINT32 , QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "extTextOut : unimplemented " << endl; + } +} + + + +//----------------------------------------------------------------------------- +// Bitmap + +void KoWmfReadPrivate::SetStretchBltMode( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "SetStretchBltMode : unimplemented " << endl; + } +} + + +void KoWmfReadPrivate::dibBitBlt( Q_UINT32 size, QDataStream& stream ) +{ + Q_UINT32 raster; + Q_INT16 topSrc, leftSrc, widthSrc, heightSrc; + Q_INT16 topDst, leftDst; + + stream >> raster; + stream >> topSrc >> leftSrc >> heightSrc >> widthSrc; + stream >> topDst >> leftDst; + + if ( size > 11 ) { // DIB image + QImage bmpSrc; + + if ( dibToBmp( bmpSrc, stream, (size - 11) * 2 ) ) { + mReadWmf->setRasterOp( winToQtRaster( raster ) ); + + mReadWmf->save(); + if ( widthSrc < 0 ) { + // negative width => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + if ( heightSrc < 0 ) { + // negative height => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + mReadWmf->drawImage( leftDst, topDst, bmpSrc, leftSrc, topSrc, widthSrc, heightSrc ); + mReadWmf->restore(); + } + } + else { + kdDebug() << "KoWmfReadPrivate::dibBitBlt without image not implemented " << endl; + } +} + + +void KoWmfReadPrivate::dibStretchBlt( Q_UINT32 size, QDataStream& stream ) +{ + Q_UINT32 raster; + Q_INT16 topSrc, leftSrc, widthSrc, heightSrc; + Q_INT16 topDst, leftDst, widthDst, heightDst; + QImage bmpSrc; + + stream >> raster; + stream >> heightSrc >> widthSrc >> topSrc >> leftSrc; + stream >> heightDst >> widthDst >> topDst >> leftDst; + + if ( dibToBmp( bmpSrc, stream, (size - 13) * 2 ) ) { + mReadWmf->setRasterOp( winToQtRaster( raster ) ); + + mReadWmf->save(); + if ( widthDst < 0 ) { + // negative width => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + if ( heightDst < 0 ) { + // negative height => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( leftSrc, topSrc, widthSrc, heightSrc ); + // TODO: scale the bitmap : QImage::scale(widthDst, heightDst) + // is actually too slow + + mReadWmf->drawImage( leftDst, topDst, bmpSrc ); + mReadWmf->restore(); + } +} + + +void KoWmfReadPrivate::stretchDib( Q_UINT32 size, QDataStream& stream ) +{ + Q_UINT32 raster; + Q_INT16 arg, topSrc, leftSrc, widthSrc, heightSrc; + Q_INT16 topDst, leftDst, widthDst, heightDst; + QImage bmpSrc; + + stream >> raster >> arg; + stream >> heightSrc >> widthSrc >> topSrc >> leftSrc; + stream >> heightDst >> widthDst >> topDst >> leftDst; + + if ( dibToBmp( bmpSrc, stream, (size - 14) * 2 ) ) { + mReadWmf->setRasterOp( winToQtRaster( raster ) ); + + mReadWmf->save(); + if ( widthDst < 0 ) { + // negative width => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + if ( heightDst < 0 ) { + // negative height => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mReadWmf->setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( leftSrc, topSrc, widthSrc, heightSrc ); + // TODO: scale the bitmap ( QImage::scale(param[ 8 ], param[ 7 ]) is actually too slow ) + + mReadWmf->drawImage( leftDst, topDst, bmpSrc ); + mReadWmf->restore(); + } +} + + +void KoWmfReadPrivate::dibCreatePatternBrush( Q_UINT32 size, QDataStream& stream ) +{ + KoWmfPatternBrushHandle* handle = new KoWmfPatternBrushHandle; + + if ( addHandle( handle ) ) { + Q_UINT32 arg; + QImage bmpSrc; + + stream >> arg; + if ( dibToBmp( bmpSrc, stream, (size - 5) * 2 ) ) { + handle->image = bmpSrc; + handle->brush.setPixmap( handle->image ); + } + else { + kdDebug() << "KoWmfReadPrivate::dibCreatePatternBrush : incorrect DIB image" << endl; + } + } +} + + +//----------------------------------------------------------------------------- +// Object handle + +void KoWmfReadPrivate::selectObject( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 idx; + + stream >> idx; + if ( (idx < mNbrObject) && (mObjHandleTab[ idx ] != 0) ) + mObjHandleTab[ idx ]->apply( mReadWmf ); + else + kdDebug() << "KoWmfReadPrivate::selectObject : selection of an empty object" << endl; +} + + +void KoWmfReadPrivate::deleteObject( Q_UINT32, QDataStream& stream ) +{ + Q_UINT16 idx; + + stream >> idx; + deleteHandle( idx ); +} + + +void KoWmfReadPrivate::createEmptyObject() +{ + // allocation of an empty object (to keep object counting in sync) + KoWmfPenHandle* handle = new KoWmfPenHandle; + + addHandle( handle ); +} + + +void KoWmfReadPrivate::createBrushIndirect( Q_UINT32, QDataStream& stream ) +{ + Qt::BrushStyle style; + Q_UINT16 sty, arg2; + Q_UINT32 color; + KoWmfBrushHandle* handle = new KoWmfBrushHandle; + + if ( addHandle( handle ) ) { + stream >> sty >> color >> arg2; + + if ( sty == 2 ) { + if ( arg2 < 6 ) + style = koWmfHatchedStyleBrush[ arg2 ]; + else + { + kdDebug() << "KoWmfReadPrivate::createBrushIndirect: invalid hatched brush " << arg2 << endl; + style = Qt::SolidPattern; + } + } + else { + if ( sty < 9 ) + style = koWmfStyleBrush[ sty ]; + else { + kdDebug() << "KoWmfReadPrivate::createBrushIndirect: invalid brush " << sty << endl; + style = Qt::SolidPattern; + } + } + handle->brush.setStyle( style ); + handle->brush.setColor( qtColor( color ) ); + } +} + + +void KoWmfReadPrivate::createPenIndirect( Q_UINT32, QDataStream& stream ) +{ + // TODO: userStyle and alternateStyle + Qt::PenStyle penStyle; + Q_UINT32 color; + Q_UINT16 style, width, arg; + + KoWmfPenHandle* handle = new KoWmfPenHandle; + + if ( addHandle( handle ) ) { + stream >> style >> width >> arg >> color; + + if ( style < 7 ) + penStyle=koWmfStylePen[ style ]; + else { + kdDebug() << "KoWmfReadPrivate::createPenIndirect: invalid pen " << style << endl; + penStyle = Qt::SolidLine; + } + + handle->pen.setStyle( penStyle ); + handle->pen.setColor( qtColor( color ) ); + handle->pen.setCapStyle( Qt::RoundCap ); + handle->pen.setWidth( width ); + } +} + + +void KoWmfReadPrivate::createFontIndirect( Q_UINT32 size, QDataStream& stream ) +{ + Q_INT16 pointSize, rotation; + Q_UINT16 weight, property, fixedPitch, arg; + + KoWmfFontHandle* handle = new KoWmfFontHandle; + + if ( addHandle( handle ) ) { + stream >> pointSize >> arg; + stream >> rotation >> arg; + stream >> weight >> property >> arg >> arg; + stream >> fixedPitch; + + // text rotation (in 1/10 degree) + // TODO: memorisation of rotation in object Font + mTextRotation = -rotation / 10; + handle->font.setFixedPitch( ((fixedPitch & 0x01) == 0) ); + // TODO: investigation why some test case need -2 + // size of font in logical point + handle->font.setPointSize( QABS(pointSize) - 2 ); + handle->font.setWeight( (weight >> 3) ); + handle->font.setItalic( (property & 0x01) ); + handle->font.setUnderline( (property & 0x100) ); + + // font name + int maxChar = (size-12) * 2; + char* nameFont = new char[maxChar]; + stream.readRawBytes( nameFont, maxChar ); + handle->font.setFamily( nameFont ); + delete[] nameFont; + } +} + + +//----------------------------------------------------------------------------- +// Misc functions + +void KoWmfReadPrivate::end( Q_UINT32, QDataStream& ) +{ +} + +Q_UINT16 KoWmfReadPrivate::calcCheckSum( WmfPlaceableHeader* apmfh ) +{ + Q_UINT16* lpWord; + Q_UINT16 wResult, i; + + // Start with the first word + wResult = *( lpWord = ( Q_UINT16* )( apmfh ) ); + // XOR in each of the other 9 words + for( i=1; i<=9; i++ ) + { + wResult ^= lpWord[ i ]; + } + return wResult; +} + + +void KoWmfReadPrivate::notyet( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "unimplemented " << endl; + } +} + +void KoWmfReadPrivate::region( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "region : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::palette( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "palette : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::escape( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "escape : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::setRelAbs( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "setRelAbs : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::setMapMode( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "setMapMode : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::extFloodFill( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "extFloodFill : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::startDoc( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "startDoc : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::startPage( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "startPage : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::endDoc( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "endDoc : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::endPage( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "endPage : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::resetDC( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "resetDC : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::bitBlt( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "bitBlt : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::setDibToDev( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "setDibToDev : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createBrush( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "createBrush : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createPatternBrush( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "createPatternBrush : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createBitmap( Q_UINT32, QDataStream& ) +{ + if ( mNbrFunc ) { + kdDebug() << "createBitmap : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createBitmapIndirect( Q_UINT32, QDataStream& ) +{ + createEmptyObject(); + if ( mNbrFunc ) { + kdDebug() << "createBitmapIndirect : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createPalette( Q_UINT32, QDataStream& ) +{ + createEmptyObject(); + if ( mNbrFunc ) { + kdDebug() << "createPalette : unimplemented " << endl; + } +} + +void KoWmfReadPrivate::createRegion( Q_UINT32, QDataStream& ) +{ + createEmptyObject(); + if ( mNbrFunc ) { + kdDebug() << "createRegion : unimplemented " << endl; + } +} + + + +//----------------------------------------------------------------------------- +// Utilities and conversion Wmf -> Qt + +bool KoWmfReadPrivate::addHandle( KoWmfHandle* handle ) +{ + int idx; + + for ( idx=0; idx < mNbrObject ; idx++ ) { + if ( mObjHandleTab[ idx ] == 0 ) break; + } + + if ( idx < mNbrObject ) { + mObjHandleTab[ idx ] = handle; + return true; + } + else { + delete handle; + mStackOverflow = true; + kdDebug() << "KoWmfReadPrivate::addHandle : stack overflow = broken file !" << endl; + return false; + } +} + + +void KoWmfReadPrivate::deleteHandle( int idx ) +{ + if ( (idx < mNbrObject) && (mObjHandleTab[idx] != 0) ) { + delete mObjHandleTab[ idx ]; + mObjHandleTab[ idx ] = 0; + } + else { + kdDebug() << "KoWmfReadPrivate::deletehandle() : bad index number" << endl; + } +} + + +void KoWmfReadPrivate::pointArray( QDataStream& stream, QPointArray& pa ) +{ + Q_INT16 left, top; + int i, max; + + for ( i=0, max=pa.size() ; i < max ; i++ ) { + stream >> left >> top; + pa.setPoint( i, left, top ); + } +} + + +void KoWmfReadPrivate::xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angleStart, int& angleLength ) +{ + double aStart, aLength; + + aStart = atan2( yStart, xStart ); + aLength = atan2( yEnd, xEnd ) - aStart; + + angleStart = (int)((aStart * 2880) / 3.14166); + angleLength = (int)((aLength * 2880) / 3.14166); + if ( angleLength < 0 ) angleLength = 5760 + angleLength; +} + + +Qt::RasterOp KoWmfReadPrivate::winToQtRaster( Q_UINT16 param ) const +{ + if ( param < 17 ) + return koWmfOpTab16[ param ]; + else + return Qt::CopyROP; +} + + +Qt::RasterOp KoWmfReadPrivate::winToQtRaster( Q_UINT32 param ) const +{ + /* TODO: Ternary raster operations + 0x00C000CA dest = (source AND pattern) + 0x00F00021 dest = pattern + 0x00FB0A09 dest = DPSnoo + 0x005A0049 dest = pattern XOR dest */ + int i; + + for ( i=0 ; i < 15 ; i++ ) { + if ( koWmfOpTab32[ i ].winRasterOp == param ) break; + } + + if ( i < 15 ) + return koWmfOpTab32[ i ].qtRasterOp; + else + return Qt::CopyROP; +} + + +bool KoWmfReadPrivate::dibToBmp( QImage& bmp, QDataStream& stream, Q_UINT32 size ) +{ + typedef struct _BMPFILEHEADER { + Q_UINT16 bmType; + Q_UINT32 bmSize; + Q_UINT16 bmReserved1; + Q_UINT16 bmReserved2; + Q_UINT32 bmOffBits; + } BMPFILEHEADER; + + int sizeBmp = size + 14; + + QByteArray pattern( sizeBmp ); // BMP header and DIB data + pattern.fill(0); + stream.readRawBytes( &pattern[ 14 ], size ); + + // add BMP header + BMPFILEHEADER* bmpHeader; + bmpHeader = (BMPFILEHEADER*)(pattern.data()); + bmpHeader->bmType = 0x4D42; + bmpHeader->bmSize = sizeBmp; + +// if ( !bmp.loadFromData( (const uchar*)bmpHeader, pattern.size(), "BMP" ) ) { + if ( !bmp.loadFromData( pattern, "BMP" ) ) { + kdDebug() << "KoWmfReadPrivate::dibToBmp: invalid bitmap " << endl; + return false; + } + else { + return true; + } +} + diff --git a/lib/kwmf/kowmfreadprivate.h b/lib/kwmf/kowmfreadprivate.h new file mode 100644 index 00000000..4dda478b --- /dev/null +++ b/lib/kwmf/kowmfreadprivate.h @@ -0,0 +1,362 @@ +/* This file is part of the KDE libraries + * Copyright (c) 1998 Stefan Taferner + * 2001/2003 thierry lorthiois ([email protected]) + * With the help of WMF documentation by Caolan Mc Namara + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef _KOWMFREADPRIVATE_H_ +#define _KOWMFREADPRIVATE_H_ + +#include <qpen.h> +#include <qcolor.h> +#include <qfont.h> +#include <qrect.h> +#include <qregion.h> +#include <qbuffer.h> +#include <qstring.h> + +#include "kowmfstruct.h" +#include "kowmfstack.h" + +class KoWmfRead; + +/** + * KoWmfReadPrivate allows to read WMF files + * + */ + +class KoWmfReadPrivate +{ +public: + KoWmfReadPrivate(); + virtual ~KoWmfReadPrivate(); + + /** + * Load WMF file. Returns true on success. + */ + bool load( const QByteArray& array ); + + /** + * Plays a metafile in @p readKwmf and returns true on success. + * To draw on a device you have to inherit the class ReadKwmf + */ + bool play( KoWmfRead* readKwmf ); + + + /* Metafile painter methods */ + + /// set window origin + void setWindowOrg( Q_UINT32 size, QDataStream& stream ); + /// set window extents + void setWindowExt( Q_UINT32 size, QDataStream& stream ); + /// scale window extents + void ScaleWindowExt( Q_UINT32, QDataStream& stream ); + /// offset in window origin + void OffsetWindowOrg( Q_UINT32, QDataStream& stream ); + + /****************** Drawing *******************/ + /// draw line to coord + void lineTo( Q_UINT32 size, QDataStream& stream ); + /// move pen to coord + void moveTo( Q_UINT32 size, QDataStream& stream ); + /// draw ellipse + void ellipse( Q_UINT32 size, QDataStream& stream ); + /// draw polygon + void polygon( Q_UINT32 size, QDataStream& stream ); + /// draw a list of polygons + void polyPolygon( Q_UINT32 size, QDataStream& stream ); + /// draw series of lines + void polyline( Q_UINT32 size, QDataStream& stream ); + /// draw a rectangle + void rectangle( Q_UINT32 size, QDataStream& stream ); + /// draw round rectangle + void roundRect( Q_UINT32 size, QDataStream& stream ); + /// draw arc + void arc( Q_UINT32 size, QDataStream& stream ); + /// draw chord + void chord( Q_UINT32 size, QDataStream& stream ); + /// draw pie + void pie( Q_UINT32 size, QDataStream& stream ); + /// set polygon fill mode + void setPolyFillMode( Q_UINT32 size, QDataStream& stream ); + /// set background pen color + void setBkColor( Q_UINT32 size, QDataStream& stream ); + /// set background pen mode + void setBkMode( Q_UINT32 size, QDataStream& stream ); + /// set a pixel + void setPixel( Q_UINT32 size, QDataStream& stream ); + /// set raster operation mode + void setRop( Q_UINT32 size, QDataStream& stream ); + /// save device context */ + void saveDC( Q_UINT32 size, QDataStream& stream ); + /// restore device context + void restoreDC( Q_UINT32 size, QDataStream& stream ); + /// clipping region is the intersection of this region and the original region + void intersectClipRect( Q_UINT32 size, QDataStream& stream ); + /// delete a clipping rectangle of the original region + void excludeClipRect( Q_UINT32 size, QDataStream& stream ); + + /****************** Text *******************/ + /// set text color + void setTextColor( Q_UINT32 size, QDataStream& stream ); + /// set text alignment + void setTextAlign( Q_UINT32 size, QDataStream& stream ); + /// draw text + void textOut( Q_UINT32 size, QDataStream& stream ); + void extTextOut( Q_UINT32 size, QDataStream& stream ); + + /****************** Bitmap *******************/ + void SetStretchBltMode( Q_UINT32, QDataStream& stream ); + /// copies a DIB into a dest location + void dibBitBlt( Q_UINT32 size, QDataStream& stream ); + /// stretches a DIB into a dest location + void dibStretchBlt( Q_UINT32 size, QDataStream& stream ); + void stretchDib( Q_UINT32 size, QDataStream& stream ); + /// create a pattern brush + void dibCreatePatternBrush( Q_UINT32 size, QDataStream& stream ); + + /****************** Object handle *******************/ + /// activate object handle + void selectObject( Q_UINT32 size, QDataStream& stream ); + /// free object handle + void deleteObject( Q_UINT32 size, QDataStream& stream ); + /// create an empty object in the object list + void createEmptyObject(); + /// create a logical brush + void createBrushIndirect( Q_UINT32 size, QDataStream& stream ); + /// create a logical pen + void createPenIndirect( Q_UINT32 size, QDataStream& stream ); + /// create a logical font + void createFontIndirect( Q_UINT32 size, QDataStream& stream ); + + /****************** misc *******************/ + /// end of meta file + void end( Q_UINT32, QDataStream& stream ); + + /** Calculate header checksum */ + static Q_UINT16 calcCheckSum( WmfPlaceableHeader* ); + + // function unimplemented + void notyet( Q_UINT32, QDataStream& stream ); + void region( Q_UINT32, QDataStream& stream ); + void palette( Q_UINT32, QDataStream& stream ); + void escape( Q_UINT32, QDataStream& stream ); + void setRelAbs( Q_UINT32, QDataStream& stream ); + void setMapMode( Q_UINT32, QDataStream& stream ); + void extFloodFill( Q_UINT32, QDataStream& stream ); + void startDoc( Q_UINT32, QDataStream& stream ); + void startPage( Q_UINT32, QDataStream& stream ); + void endDoc( Q_UINT32, QDataStream& stream ); + void endPage( Q_UINT32, QDataStream& stream ); + void resetDC( Q_UINT32, QDataStream& stream ); + void bitBlt( Q_UINT32, QDataStream& stream ); + void setDibToDev( Q_UINT32, QDataStream& stream ); + void createBrush( Q_UINT32, QDataStream& stream ); + void createPatternBrush( Q_UINT32, QDataStream& stream ); + void createBitmap( Q_UINT32, QDataStream& stream ); + void createBitmapIndirect( Q_UINT32, QDataStream& stream ); + void createPalette( Q_UINT32, QDataStream& stream ); + void createRegion( Q_UINT32, QDataStream& stream ); + +private: + //----------------------------------------------------------------------------- + // Utilities and conversion Wmf -> Qt + + /** Handle win-object-handles */ + bool addHandle( KoWmfHandle* ); + void deleteHandle( int ); + + /** Convert QINT16 points into QPointArray */ + void pointArray( QDataStream& stream, QPointArray& pa ); + + /** Convertion between windows color and QColor */ + QColor qtColor( Q_UINT32 color ) const + { return QColor( color & 0xFF, (color>>8) & 0xFF, (color>>16) & 0xFF ); } + + /** Convert (x1,y1) and (x2, y2) positions in angle and angleLength */ + void xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angle, int& aLength ); + + /** Convert windows rasterOp in QT rasterOp */ + Qt::RasterOp winToQtRaster( Q_UINT16 param ) const; + Qt::RasterOp winToQtRaster( Q_UINT32 param ) const; + + /** Converts DIB to BMP */ + bool dibToBmp( QImage& bmp, QDataStream& stream, Q_UINT32 size); + + +public: + // state of the WMF + bool mValid; + bool mStandard; + bool mPlaceable; + bool mEnhanced; + + /// bounding rectangle + QRect mBBox; // placeable file : this is the header + // standard file : this is the value in setWindowOrg and setWindowExt + /// number of points per inch for the default size + int mDpi; + + /// number of functions to draw (==0 for all) + int mNbrFunc; + +private: + // the output + KoWmfRead *mReadWmf; + + // current coordinate != mBBox + QRect mWindow; + // current state of the drawing + QColor mTextColor; + Q_UINT16 mTextAlign; + int mTextRotation; + bool mWinding; + + // memory allocation for WMF file + QBuffer* mBuffer; + int mOffsetFirstRecord; + + // stack of object handle + KoWmfHandle** mObjHandleTab; + // number of object on the stack + int mNbrObject; + bool mStackOverflow; +}; + +/** + * static data + */ + static const struct KoWmfFunc { + void ( KoWmfReadPrivate::*method )( Q_UINT32, QDataStream& ); + } koWmfFunc[] = { + { &KoWmfReadPrivate::end }, // 0 + { &KoWmfReadPrivate::setBkColor }, // 1 + { &KoWmfReadPrivate::setBkMode }, // 2 + { &KoWmfReadPrivate::setMapMode }, // 3 + { &KoWmfReadPrivate::setRop }, // 4 + { &KoWmfReadPrivate::setRelAbs }, // 5 + { &KoWmfReadPrivate::setPolyFillMode }, // 6 + { &KoWmfReadPrivate::SetStretchBltMode }, // 7 + { &KoWmfReadPrivate::notyet }, // 8 + { &KoWmfReadPrivate::setTextColor }, // 9 + { &KoWmfReadPrivate::ScaleWindowExt }, // 10 + { &KoWmfReadPrivate::setWindowOrg }, // 11 + { &KoWmfReadPrivate::setWindowExt }, // 12 + { &KoWmfReadPrivate::notyet }, // 13 + { &KoWmfReadPrivate::notyet }, // 14 + { &KoWmfReadPrivate::OffsetWindowOrg }, // 15 + { &KoWmfReadPrivate::notyet }, // 16 + { &KoWmfReadPrivate::notyet }, // 17 + { &KoWmfReadPrivate::notyet }, // 18 + { &KoWmfReadPrivate::lineTo }, // 19 + { &KoWmfReadPrivate::moveTo }, // 20 + { &KoWmfReadPrivate::excludeClipRect }, // 21 + { &KoWmfReadPrivate::intersectClipRect }, // 22 + { &KoWmfReadPrivate::arc }, // 23 + { &KoWmfReadPrivate::ellipse }, // 24 + { &KoWmfReadPrivate::notyet }, // 25 + { &KoWmfReadPrivate::pie }, // 26 + { &KoWmfReadPrivate::rectangle }, // 27 + { &KoWmfReadPrivate::roundRect }, // 28 + { &KoWmfReadPrivate::notyet }, // 29 + { &KoWmfReadPrivate::saveDC }, // 30 + { &KoWmfReadPrivate::setPixel }, // 31 + { &KoWmfReadPrivate::notyet }, // 32 + { &KoWmfReadPrivate::textOut }, // 33 + { &KoWmfReadPrivate::bitBlt }, // 34 + { &KoWmfReadPrivate::notyet }, // 35 + { &KoWmfReadPrivate::polygon }, // 36 + { &KoWmfReadPrivate::polyline }, // 37 + { &KoWmfReadPrivate::escape }, // 38 + { &KoWmfReadPrivate::restoreDC }, // 39 + { &KoWmfReadPrivate::region }, // 40 + { &KoWmfReadPrivate::region }, // 41 + { &KoWmfReadPrivate::region }, // 42 + { &KoWmfReadPrivate::region }, // 43 + { &KoWmfReadPrivate::region }, // 44 + { &KoWmfReadPrivate::selectObject }, // 45 + { &KoWmfReadPrivate::setTextAlign }, // 46 + { 0 }, // 47 + { &KoWmfReadPrivate::chord }, // 48 + { &KoWmfReadPrivate::notyet }, // 49 + { &KoWmfReadPrivate::extTextOut }, // 50 + { &KoWmfReadPrivate::setDibToDev }, // 51 + { &KoWmfReadPrivate::palette }, // 52 + { &KoWmfReadPrivate::palette }, // 53 + { &KoWmfReadPrivate::palette }, // 54 + { &KoWmfReadPrivate::palette }, // 55 + { &KoWmfReadPrivate::polyPolygon }, // 56 + { &KoWmfReadPrivate::palette }, // 57 + { 0 }, // 58 + { 0 }, // 59 + { 0 }, // 60 + { 0 }, // 61 + { 0 }, // 62 + { 0 }, // 63 + { &KoWmfReadPrivate::dibBitBlt }, // 64 + { &KoWmfReadPrivate::dibStretchBlt }, // 65 + { &KoWmfReadPrivate::dibCreatePatternBrush }, // 66 + { &KoWmfReadPrivate::stretchDib }, // 67 + { 0 }, // 68 + { 0 }, // 69 + { 0 }, // 70 + { 0 }, // 71 + { &KoWmfReadPrivate::extFloodFill }, // 72 + { 0 }, // 73 + { 0 }, // 74 + { 0 }, // 75 + { &KoWmfReadPrivate::resetDC }, // 76 + { &KoWmfReadPrivate::startDoc }, // 77 + { 0 }, // 78 + { &KoWmfReadPrivate::startPage }, // 79 + { &KoWmfReadPrivate::endPage }, // 80 + { 0 }, // 81 + { 0 }, // 82 + { 0 }, // 83 + { 0 }, // 84 + { 0 }, // 85 + { 0 }, // 86 + { 0 }, // 87 + { 0 }, // 88 + { 0 }, // 89 + { 0 }, // 90 + { 0 }, // 91 + { 0 }, // 92 + { 0 }, // 93 + { &KoWmfReadPrivate::endDoc }, // 94 + { 0 }, // 95 + // 0x5F last function until 0xF0 + { &KoWmfReadPrivate::deleteObject }, // 96 + { 0 }, // 97 + { 0 }, // 98 + { 0 }, // 99 + { 0 }, // 100 + { 0 }, // 101 + { 0 }, // 102 + { &KoWmfReadPrivate::createPalette }, // 103 + { &KoWmfReadPrivate::createBrush }, // 104 + { &KoWmfReadPrivate::createPatternBrush }, // 105 + { &KoWmfReadPrivate::createPenIndirect }, // 106 + { &KoWmfReadPrivate::createFontIndirect }, // 107 + { &KoWmfReadPrivate::createBrushIndirect }, //108 + { &KoWmfReadPrivate::createBitmapIndirect }, //109 + { &KoWmfReadPrivate::createBitmap }, // 110 + { &KoWmfReadPrivate::createRegion } // 111 + }; + + +#endif + diff --git a/lib/kwmf/kowmfstack.cc b/lib/kwmf/kowmfstack.cc new file mode 100644 index 00000000..80896690 --- /dev/null +++ b/lib/kwmf/kowmfstack.cc @@ -0,0 +1,38 @@ +/* This file is part of the KDE libraries + Copyright (c) 1998 Stefan Taferner + 2001/2003 thierry lorthiois ([email protected]) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 "kowmfstack.h" +#include "kowmfread.h" + +void KoWmfBrushHandle::apply( KoWmfRead *p ) { + p->setBrush( brush ); +} + +void KoWmfPenHandle::apply( KoWmfRead *p ) { + p->setPen( pen ); +} + +void KoWmfPatternBrushHandle::apply( KoWmfRead *p ) { + p->setBrush( brush ); +} + +void KoWmfFontHandle::apply( KoWmfRead *p ) { + p->setFont( font ); +} + diff --git a/lib/kwmf/kowmfstack.h b/lib/kwmf/kowmfstack.h new file mode 100644 index 00000000..0dcb5a8d --- /dev/null +++ b/lib/kwmf/kowmfstack.h @@ -0,0 +1,74 @@ +/* This file is part of the KDE libraries + Copyright (c) 1998 Stefan Taferner + 2001/2003 thierry lorthiois ([email protected]) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef _KOWMFSTACK_H_ +#define _KOWMFSTACK_H_ + +#include <qpen.h> +#include <qcolor.h> +#include <qfont.h> +#include <qbrush.h> +#include <qpixmap.h> + +class KoWmfRead; + +/** + * WMF file allows manipulation on a stack of object. + * It's possile to create, delete or select an object. + */ +class KoWmfHandle +{ +public: + virtual void apply( KoWmfRead * ) = 0; +}; + +class KoWmfBrushHandle: public KoWmfHandle +{ +public: + virtual ~KoWmfBrushHandle() {}; + virtual void apply( KoWmfRead * ); + QBrush brush; +}; + +class KoWmfPenHandle: public KoWmfHandle +{ +public: + virtual ~KoWmfPenHandle() {}; + virtual void apply( KoWmfRead * ); + QPen pen; +}; + +class KoWmfPatternBrushHandle: public KoWmfHandle +{ +public: + virtual ~KoWmfPatternBrushHandle() {}; + virtual void apply( KoWmfRead * ); + QBrush brush; + QPixmap image; +}; + +class KoWmfFontHandle: public KoWmfHandle +{ +public: + virtual ~KoWmfFontHandle() {}; + virtual void apply( KoWmfRead * ); + QFont font; + int rotation; +}; + +#endif diff --git a/lib/kwmf/kowmfstruct.h b/lib/kwmf/kowmfstruct.h new file mode 100644 index 00000000..2837fa71 --- /dev/null +++ b/lib/kwmf/kowmfstruct.h @@ -0,0 +1,147 @@ +/* This library is distributed under the conditions of the GNU LGPL. + * WMF Metafile Structures + * Author: 2002/2003 thierry lorthiois + */ +#ifndef _KOWMFSTRUCT_H_ +#define _KOWMFSTRUCT_H_ + +#include <qglobal.h> +#include <qnamespace.h> + +#define APMHEADER_KEY 0x9AC6CDD7 +#define ENHMETA_SIGNATURE 0x464D4520 + +struct WmfMetaHeader +{ + Q_UINT16 fileType; // Type of metafile (0=memory, 1=disk) + Q_UINT16 headerSize; // always 9 + Q_UINT16 version; + Q_UINT32 fileSize; // Total size of the metafile in WORDs + Q_UINT16 numOfObjects; // Maximum Number of objects in the stack + Q_UINT32 maxRecordSize; // The size of largest record in WORDs + Q_UINT16 numOfParameters; // not used (always 0) +}; + + +struct WmfPlaceableHeader +{ + Q_UINT32 key; // Magic number (always 9AC6CDD7h) + Q_UINT16 handle; // Metafile HANDLE number (always 0) + Q_INT16 left; // Left coordinate in metafile units + Q_INT16 top; + Q_INT16 right; + Q_INT16 bottom; + Q_UINT16 inch; // Number of metafile units per inch + Q_UINT32 reserved; + Q_UINT16 checksum; // Checksum value for previous 10 WORDs +}; + + +struct WmfEnhMetaHeader +{ + Q_UINT32 recordType; // Record type (is always 00000001h) + Q_UINT32 recordSize; // Record size in bytes. This may be greater + // than the sizeof( ENHMETAHEADER ). + Q_INT32 boundsLeft; // Inclusive-inclusive bounds in device units + Q_INT32 boundsTop; + Q_INT32 boundsRight; + Q_INT32 boundsBottom; + Q_INT32 frameLeft; // Inclusive-inclusive Picture Frame + Q_INT32 frameTop; + Q_INT32 frameRight; + Q_INT32 frameBottom; + Q_UINT32 signature; // Signature. Must be ENHMETA_SIGNATURE. + Q_UINT32 version; // Version number + Q_UINT32 size; // Size of the metafile in bytes + Q_UINT32 numOfRecords; // Number of records in the metafile + Q_UINT16 numHandles; // Number of handles in the handle table + // Handle index zero is reserved. + Q_UINT16 reserved; // always 0 + Q_UINT32 sizeOfDescription; // Number of chars in the unicode description string + // This is 0 if there is no description string + Q_UINT32 offsetOfDescription; // Offset to the metafile description record. + // This is 0 if there is no description string + Q_UINT32 numPaletteEntries; // Number of color palette entries + Q_INT32 widthDevicePixels; // Size of the reference device in pixels + Q_INT32 heightDevicePixels; + Q_INT32 widthDeviceMM; // Size of the reference device in millimeters + Q_INT32 heightDeviceMM; +}; + + +struct WmfMetaRecord +{ + Q_UINT32 size; // Total size of the record in WORDs + Q_UINT16 function; // Record function number + Q_UINT16 param[ 1 ]; // Q_UINT16 array of parameters +}; + + +struct WmfEnhMetaRecord +{ + Q_UINT32 function; // Record function number + Q_UINT32 size; // Record size in bytes + Q_UINT32 param[ 1 ]; // Q_UINT32 array of parameters +}; + +// Static data + static const struct OpTab + { + Q_UINT32 winRasterOp; + Qt::RasterOp qtRasterOp; + } koWmfOpTab32[] = + { + { 0x00CC0020, Qt::CopyROP }, + { 0x00EE0086, Qt::OrROP }, + { 0x008800C6, Qt::AndROP }, + { 0x00660046, Qt::XorROP }, + { 0x00440328, Qt::AndNotROP }, + { 0x00330008, Qt::NotCopyROP }, + { 0x001100A6, Qt::NandROP }, + { 0x00C000CA, Qt::CopyROP }, + { 0x00BB0226, Qt::NotOrROP }, + { 0x00F00021, Qt::CopyROP }, + { 0x00FB0A09, Qt::CopyROP }, + { 0x005A0049, Qt::CopyROP }, + { 0x00550009, Qt::NotROP }, + { 0x00000042, Qt::ClearROP }, + { 0x00FF0062, Qt::SetROP } + }; + + static const Qt::RasterOp koWmfOpTab16[] = + { + Qt::CopyROP, + Qt::ClearROP, Qt::NandROP, Qt::NotAndROP, Qt::NotCopyROP, + Qt::AndNotROP, Qt::NotROP, Qt::XorROP, Qt::NorROP, + Qt::AndROP, Qt::NotXorROP, Qt::NopROP, Qt::NotOrROP, + Qt::CopyROP, Qt::OrNotROP, Qt::OrROP, Qt::SetROP + }; + + static const Qt::BrushStyle koWmfHatchedStyleBrush[] = + { + Qt::HorPattern, + Qt::VerPattern, + Qt::FDiagPattern, + Qt::BDiagPattern, + Qt::CrossPattern, + Qt::DiagCrossPattern + }; + + static const Qt::BrushStyle koWmfStyleBrush[] = + { Qt::SolidPattern, + Qt::NoBrush, + Qt::FDiagPattern, /* hatched */ + Qt::Dense4Pattern, /* should be custom bitmap pattern */ + Qt::HorPattern, /* should be BS_INDEXED (?) */ + Qt::VerPattern, /* should be device-independent bitmap */ + Qt::Dense6Pattern, /* should be device-independent packed-bitmap */ + Qt::Dense2Pattern, /* should be BS_PATTERN8x8 */ + Qt::Dense3Pattern /* should be device-independent BS_DIBPATTERN8x8 */ + }; + + static const Qt::PenStyle koWmfStylePen[] = + { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine, + Qt::NoPen, Qt::SolidLine }; + +#endif + diff --git a/lib/kwmf/kowmfwrite.cc b/lib/kwmf/kowmfwrite.cc new file mode 100644 index 00000000..1c553391 --- /dev/null +++ b/lib/kwmf/kowmfwrite.cc @@ -0,0 +1,456 @@ +/* This file is part of the KDE libraries + * Copyright (c) 2003 thierry lorthiois ([email protected]) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 <math.h> +#include <qfile.h> +#include <qdatastream.h> + +#include <kdebug.h> + +#include "kowmfstruct.h" +#include "kowmfreadprivate.h" +#include "kowmfwrite.h" + +/** + * Private data + */ +class KoWmfWritePrivate +{ +public: + QRect mBBox; // bounding rectangle + int mDpi; // number of point per inch for the default size + int mMaxRecordSize; + + // memory allocation for WMF file + QFile mFileOut; + QDataStream mSt; +}; + + + +KoWmfWrite::KoWmfWrite( const QString& fileName ) { + d = new KoWmfWritePrivate; + + d->mDpi = 1024; + d->mMaxRecordSize = 0; + d->mFileOut.setName( fileName ); +} + +KoWmfWrite::~KoWmfWrite() { + delete d; +} + + +void KoWmfWrite::setDefaultDpi( int dpi ) { + d->mDpi = dpi; +} + + +//----------------------------------------------------------------------------- +// Virtual Painter => create the WMF + +bool KoWmfWrite::begin() { + + if ( !d->mFileOut.open( IO_WriteOnly ) ) + { + kdDebug() << "Cannot open file " << QFile::encodeName(d->mFileOut.name()) << endl; + return false; + } + d->mSt.setDevice( &d->mFileOut ); + d->mSt.setByteOrder( QDataStream::LittleEndian ); + + // reserved placeable and standard header + for ( int i=0 ; i < 10 ; i++ ) { + d->mSt << (Q_UINT32)0; + } + + // initialize the stack of objects + // Pen + d->mSt << (Q_UINT32)8 << (Q_UINT16)0x02FA; + d->mSt << (Q_UINT16)5 << (Q_UINT16)0 << (Q_UINT16)0 << (Q_UINT32)0; + // Brush + d->mSt << (Q_UINT32)7 << (Q_UINT16)0x02FC; + d->mSt << (Q_UINT16)1 << (Q_UINT32)0 << (Q_UINT16)0; + for ( int i=0 ; i < 4 ; i++ ) { + d->mSt << (Q_UINT32)8 << (Q_UINT16)0x02FA << (Q_UINT16)0 << (Q_UINT32)0 << (Q_UINT32)0; + } + d->mMaxRecordSize = 8; + + return true; +} + + +bool KoWmfWrite::end() { + WmfPlaceableHeader pheader = { 0x9AC6CDD7, 0, 0, 0, 0, 0, 0, 0, 0 }; + Q_UINT16 checksum; + + // End of the wmf file + d->mSt << (Q_UINT32)3 << (Q_UINT16)0; + + // adjust header + pheader.left = d->mBBox.left(); + pheader.top = d->mBBox.top(); + pheader.right = d->mBBox.right(); + pheader.bottom = d->mBBox.bottom(); + pheader.inch = d->mDpi; + checksum = KoWmfReadPrivate::calcCheckSum( &pheader ); + + // write headers + d->mFileOut.at( 0 ); + d->mSt << (Q_UINT32)0x9AC6CDD7 << (Q_UINT16)0; + d->mSt << (Q_INT16)d->mBBox.left() << (Q_INT16)d->mBBox.top() << (Q_INT16)d->mBBox.right() << (Q_INT16)d->mBBox.bottom(); + d->mSt << (Q_UINT16)d->mDpi << (Q_UINT32)0 << checksum; + d->mSt << (Q_UINT16)1 << (Q_UINT16)9 << (Q_UINT16)0x300 << (Q_UINT32)(d->mFileOut.size()/2); + d->mSt << (Q_UINT16)6 << (Q_UINT32)d->mMaxRecordSize << (Q_UINT16)0; + + d->mFileOut.close(); + + return true; +} + + +void KoWmfWrite::save() { + d->mSt << (Q_UINT32)3 << (Q_UINT16)0x001E; +} + + +void KoWmfWrite::restore() { + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x0127 << (Q_UINT16)1; +} + + +void KoWmfWrite::setPen( const QPen &pen ) { + int style; + int max = sizeof(koWmfStylePen) / sizeof(Qt::SolidLine); + + // we can't delete an object currently selected + // select another object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x012D << (Q_UINT16)0; + // delete object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x01f0 << (Q_UINT16)2; + + for ( style=0 ; style < max ; style++ ) { + if ( koWmfStylePen[ style ] == pen.style() ) break; + } + if ( style == max ) { + // SolidLine + style = 0; + } + d->mSt << (Q_UINT32)8 << (Q_UINT16)0x02FA; + d->mSt << (Q_UINT16)style << (Q_UINT16)pen.width() << (Q_UINT16)0 << (Q_UINT32)winColor( pen.color() ); + + // select object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x012D << (Q_UINT16)2; +} + + +void KoWmfWrite::setBrush( const QBrush &brush ) { + int style; + int max = sizeof(koWmfStyleBrush) / sizeof(Qt::NoBrush); + + // we can't delete an object currently selected + // select another object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x012D << (Q_UINT16)1; + // delete object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x01f0 << (Q_UINT16)3; + + for ( style=0 ; style < max ; style++ ) { + if ( koWmfStyleBrush[ style ] == brush.style() ) break; + } + if ( style == max ) { + // SolidPattern + style = 0; + } + d->mSt << (Q_UINT32)7 << (Q_UINT16)0x02FC; + d->mSt << (Q_UINT16)style << (Q_UINT32)winColor( brush.color() ) << (Q_UINT16)0; + + // select object + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x012D << (Q_UINT16)3; +} + + +void KoWmfWrite::setFont( const QFont & ) { +} + + +void KoWmfWrite::setBackgroundColor( const QColor &c ) { + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x0201 << (Q_UINT32)winColor( c ); +} + + +void KoWmfWrite::setBackgroundMode( Qt::BGMode mode ) { + d->mSt << (Q_UINT32)4 << (Q_UINT16)0x0102; + if ( mode == Qt::TransparentMode ) + d->mSt << (Q_UINT16)1; + else + d->mSt << (Q_UINT16)0; +} + + +void KoWmfWrite::setRasterOp( Qt::RasterOp op ) { + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x0104 << (Q_UINT32)qtRasterToWin32( op ); +} + + +void KoWmfWrite::setWindow( int left, int top, int width, int height ) { + d->mBBox.setRect( left, top, width, height ); + + // windowOrg + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x020B << (Q_UINT16)top << (Q_UINT16)left; + + // windowExt + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x020C << (Q_UINT16)height << (Q_UINT16)width; +} + + +void KoWmfWrite::setClipRegion( const QRegion & ) { + +} + + +void KoWmfWrite::clipping( bool enable ) { + if ( !enable ) { + // clipping region == bounding rectangle + setClipRegion( d->mBBox ); + } +} + + +void KoWmfWrite::moveTo( int left, int top ) { + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x0214 << (Q_UINT16)top << (Q_UINT16)left; +} + + +void KoWmfWrite::lineTo( int left, int top ) { + d->mSt << (Q_UINT32)5 << (Q_UINT16)0x0213 << (Q_UINT16)top << (Q_UINT16)left; +} + + +void KoWmfWrite::drawRect( int left, int top, int width, int height ) { + QRect rec( left, top, width, height ); + + d->mSt << (Q_UINT32)7 << (Q_UINT16)0x041B; + d->mSt << (Q_UINT16)rec.bottom() << (Q_UINT16)rec.right() << (Q_UINT16)rec.top() << (Q_UINT16)rec.left(); +} + + +void KoWmfWrite::drawRoundRect( int left, int top, int width, int height , int roudw, int roudh ) { + int widthCorner, heightCorner; + QRect rec( left, top, width, height ); + + // convert percentage (roundw, roudh) in (widthCorner, heightCorner) + widthCorner = ( roudw * width ) / 100; + heightCorner = ( roudh * height ) / 100; + + d->mSt << (Q_UINT32)9 << (Q_UINT16)0x061C << (Q_UINT16)heightCorner << (Q_UINT16)widthCorner; + d->mSt << (Q_UINT16)rec.bottom() << (Q_UINT16)rec.right() << (Q_UINT16)rec.top() << (Q_UINT16)rec.left(); + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, 9 ); +} + + +void KoWmfWrite::drawEllipse( int left, int top, int width, int height ) { + QRect rec( left, top, width, height ); + + d->mSt << (Q_UINT32)7 << (Q_UINT16)0x0418; + d->mSt << (Q_UINT16)rec.bottom() << (Q_UINT16)rec.right() << (Q_UINT16)rec.top() << (Q_UINT16)rec.left(); +} + + +void KoWmfWrite::drawArc( int left, int top, int width, int height , int a, int alen ) { + int xCenter, yCenter; + int offXStart, offYStart, offXEnd, offYEnd; + + angleToxy( offXStart, offYStart, offXEnd, offYEnd, a, alen ); + xCenter = left + (width / 2); + yCenter = top + (height / 2); + + d->mSt << (Q_UINT32)11 << (Q_UINT16)0x0817; + d->mSt << (Q_UINT16)(yCenter + offYEnd) << (Q_UINT16)(xCenter + offXEnd); + d->mSt << (Q_UINT16)(yCenter + offYStart) << (Q_UINT16)(xCenter + offXStart); + d->mSt << (Q_UINT16)(top + height) << (Q_UINT16)(left + width); + d->mSt << (Q_UINT16)top << (Q_UINT16)left; + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, 11 ); +} + + +void KoWmfWrite::drawPie( int left, int top, int width, int height , int a, int alen ) { + int xCenter, yCenter; + int offXStart, offYStart, offXEnd, offYEnd; + + angleToxy( offXStart, offYStart, offXEnd, offYEnd, a, alen ); + xCenter = left + (width / 2); + yCenter = top + (height / 2); + + d->mSt << (Q_UINT32)11 << (Q_UINT16)0x081A; + d->mSt << (Q_UINT16)(yCenter + offYEnd) << (Q_UINT16)(xCenter + offXEnd); + d->mSt << (Q_UINT16)(yCenter + offYStart) << (Q_UINT16)(xCenter + offXStart); + d->mSt << (Q_UINT16)(top + height) << (Q_UINT16)(left + width); + d->mSt << (Q_UINT16)top << (Q_UINT16)left; + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, 11 ); +} + + +void KoWmfWrite::drawChord( int left, int top, int width, int height , int a, int alen ) { + int xCenter, yCenter; + int offXStart, offYStart, offXEnd, offYEnd; + + angleToxy( offXStart, offYStart, offXEnd, offYEnd, a, alen ); + xCenter = left + (width / 2); + yCenter = top + (height / 2); + + d->mSt << (Q_UINT32)11 << (Q_UINT16)0x0830; + d->mSt << (Q_UINT16)(yCenter + offYEnd) << (Q_UINT16)(xCenter + offXEnd); + d->mSt << (Q_UINT16)(yCenter + offYStart) << (Q_UINT16)(xCenter + offXStart); + d->mSt << (Q_UINT16)(top + height) << (Q_UINT16)(left + width); + d->mSt << (Q_UINT16)top << (Q_UINT16)left; + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, 11 ); +} + + +void KoWmfWrite::drawPolyline( const QPointArray &pa ) { + int size = 4 + (pa.size() * 2); + + d->mSt << (Q_UINT32)size << (Q_UINT16)0x0325 << (Q_UINT16)pa.size(); + pointArray( pa ); + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, size ); +} + + +void KoWmfWrite::drawPolygon( const QPointArray &pa, bool ) { + int size = 4 + (pa.size() * 2); + + d->mSt << (Q_UINT32)size << (Q_UINT16)0x0324 << (Q_UINT16)pa.size(); + pointArray( pa ); + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, size ); +} + + +void KoWmfWrite::drawPolyPolygon( QPtrList<QPointArray>& listPa, bool ) { + + QPointArray *pa; + int sizeArrayPoly = 0; + + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + sizeArrayPoly += (pa->size() * 2); + } + int size = 4 + listPa.count() + sizeArrayPoly; + d->mSt << (Q_UINT32)size << (Q_UINT16)0x0538 << (Q_UINT16)listPa.count(); + + // number of point for each Polygon + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + d->mSt << (Q_UINT16)pa->size(); + } + + // list of points + for ( pa = listPa.first() ; pa ; pa = listPa.next() ) { + pointArray( *pa ); + } + + d->mMaxRecordSize = QMAX( d->mMaxRecordSize, size ); + +} + + +void KoWmfWrite::drawImage( int , int , const QImage &, int , int , int , int ) { +/* + QImage img; + + img = image; + img.setFormat( "BMP" ); + + QIODevice io = img.ioDevice(); + io.at( 14 ); // skip the BMP header + d->mSt << io.readAll(); +*/ +} + + +void KoWmfWrite::drawText( int , int , int , int , int , const QString& , double ) { +// d->mSt << (Q_UINT32)3 << (Q_UINT16)0x0A32; +} + +//----------------------------------------------------------------------------- +// Utilities and conversion Qt --> Wmf + +void KoWmfWrite::pointArray( const QPointArray &pa ) { + int left, top, i, max; + + for ( i=0, max=pa.size() ; i < max ; i++ ) { + pa.point( i, &left, &top ); + d->mSt << (Q_INT16)left << (Q_INT16)top; + } +} + + +Q_UINT32 KoWmfWrite::winColor( QColor color ) { + Q_UINT32 c; + + c = (color.red() & 0xFF); + c += ( (color.green() & 0xFF) << 8 ); + c += ( (color.blue() & 0xFF) << 16 ); + + return c; +} + + +void KoWmfWrite::angleToxy( int &xStart, int &yStart, int &xEnd, int &yEnd, int a, int alen ) { + double angleStart, angleLength; + + angleStart = ((double)a * 3.14166) / 2880; + angleLength = ((double)alen * 3.14166) / 2880; + + xStart = (int)(cos(angleStart) * 50); + yStart = -(int)(sin(angleStart) * 50); + xEnd = (int)(cos(angleLength) * 50); + yEnd = -(int)(sin(angleLength) * 50); +} + + +Q_UINT16 KoWmfWrite::qtRasterToWin16( Qt::RasterOp op ) const { + int i; + + for ( i=0 ; i < 17 ; i++ ) { + if ( koWmfOpTab16[ i ] == op ) break; + } + + if ( i < 17 ) + return (Q_UINT16)i; + else + return (Q_UINT16)0; +} + + +Q_UINT32 KoWmfWrite::qtRasterToWin32( Qt::RasterOp op ) const { + int i; + + for ( i=0 ; i < 15 ; i++ ) { + if ( koWmfOpTab32[ i ].qtRasterOp == op ) break; + } + + if ( i < 15 ) + return koWmfOpTab32[ i ].winRasterOp; + else + return koWmfOpTab32[ 0 ].winRasterOp; +} + diff --git a/lib/kwmf/kowmfwrite.h b/lib/kwmf/kowmfwrite.h new file mode 100644 index 00000000..1063ef76 --- /dev/null +++ b/lib/kwmf/kowmfwrite.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE libraries + Copyright (c) 2003 thierry lorthiois ([email protected]) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef _KOWMFWRITE_H_ +#define _KOWMFWRITE_H_ + +#include <qpen.h> +#include <qbrush.h> +#include <qcolor.h> +#include <qfont.h> +#include <qrect.h> +#include <qbuffer.h> +#include <qregion.h> +#include <qstring.h> +#include <qwmatrix.h> +#include <qimage.h> +#include <qptrlist.h> +#include <qpointarray.h> +#include <koffice_export.h> +class KoWmfWritePrivate; + +/** + * KoWmfWrite allows to create a windows placeable meta file (WMF). + * Most of the functions are compatible with QPainter format. + * + * sample of utilization: + * <pre> + * KoWmfWrite wmf("/home/test.wmf"); + * wmf.begin(); + * wmf.setWindow(0, 0, 200, 200); + * wmf.drawRect(10, 20, 50, 120); + * wmf.end(); + * </pre> + */ +class KOWMF_EXPORT KoWmfWrite +{ +public: + KoWmfWrite( const QString& fileName ); + virtual ~KoWmfWrite(); + + + // ------------------------------------------------------------------------- + // virtual Painter + // for a good documentation : check QPainter documentation + /** + * Open the file. Returns true on success. + */ + bool begin(); + /** + * Close the file. Returns true on success. + */ + bool end(); + void save(); + void restore(); + + /** + * Placeable WMF's use logical coordinates and have a default DPI. + * This function set the dot per inch ratio. + * If not specified the dpi is 1024. + */ + void setDefaultDpi( int dpi ); + + // Drawing tools + void setFont( const QFont& f ); + // the width of the pen is in logical coordinate + void setPen( const QPen& p ); + void setBrush( const QBrush& b ); + + // Drawing attributes/modes + void setBackgroundColor( const QColor& r ); + void setBackgroundMode( Qt::BGMode ); + void setRasterOp( Qt::RasterOp ); + + // Change logical Coordinate + void setWindow( int left, int top , int width, int height ); + + // Clipping + // the 'CoordinateMode' parameter is ommitted : always CoordPainter in wmf + // not yet implemented + void setClipRegion( const QRegion& r ); + void clipping( bool enable ); + + // Graphics drawing functions + void moveTo( int left, int top ); + void lineTo( int left, int top ); + void drawRect( int left, int top, int width, int height ); + void drawRoundRect( int left, int top, int width, int height, int = 25, int = 25 ); + void drawEllipse( int left, int top, int width, int height ); + void drawArc( int left, int top, int width, int height, int a, int alen ); + void drawPie( int left, int top, int width, int height, int a, int alen ); + void drawChord( int left, int top, int width, int height, int a, int alen ); + void drawPolyline( const QPointArray& pa ); + void drawPolygon( const QPointArray& pa, bool winding=FALSE ); + // drawPolyPolygon draw the XOR of a list of polygons + // listPa : list of polygons + void drawPolyPolygon( QPtrList<QPointArray>& listPa, bool winding=FALSE ); + void drawImage( int left, int top, const QImage &, int sx = 0, int sy = 0, int sw = -1, int sh = -1 ); + + // Text drawing functions + // rotation = the degrees of rotation in counterclockwise + // not yet implemented + void drawText( int x, int y, int w, int h, int flags, const QString &s, double rotation ); + +private: + //----------------------------------------------------------------------------- + // Utilities and conversion Qt --> Wmf + + /** Convert QPointArray into Q_INT16 position (result in mSt) */ + void pointArray( const QPointArray& pa ); + + /** Convertion between windows color and QColor */ + Q_UINT32 winColor( QColor color ); + + /** Convert angle a and alen in coordinate (xStart,yStart) and (xEnd, yEnd) */ + void angleToxy( int& xStart, int& yStart, int& xEnd, int& yEnd, int a, int alen ); + + /** Convert windows rasterOp in QT rasterOp */ + Q_UINT16 qtRasterToWin16( Qt::RasterOp op ) const; + Q_UINT32 qtRasterToWin32( Qt::RasterOp op ) const; + + +private: + KoWmfWritePrivate *d; + +}; + +#endif + diff --git a/lib/kwmf/kwmf.cc b/lib/kwmf/kwmf.cc new file mode 100644 index 00000000..989b3e29 --- /dev/null +++ b/lib/kwmf/kwmf.cc @@ -0,0 +1,964 @@ +/* + Copyright (C) 2000, S.R.Haque <[email protected]>. + This file is part of the KDE project + + 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. + +DESCRIPTION + + This is based on code originally written by Stefan Taferner + ([email protected]) and also borrows from libwmf (by Martin Vermeer and + Caolan McNamara). +*/ + +#include <kdebug.h> +#include <math.h> +#include <qfile.h> +#include <qpointarray.h> +#include <kwmf.h> +#include <qrect.h> + +#define PI (3.14159265358979323846) + +const int KWmf::s_area = 30504; +const int KWmf::s_maxHandles = 64; + +KWmf::KWmf( + unsigned dpi) +{ + m_dpi = dpi; + m_objectHandles = new WinObjHandle*[s_maxHandles]; +} + +KWmf::~KWmf() +{ + delete[] m_objectHandles; +} + +// +// +// + +void KWmf::brushSet( + unsigned colour, + unsigned style) +{ + m_dc.m_brushColour = colour; + m_dc.m_brushStyle = style; +} + +//----------------------------------------------------------------------------- +unsigned KWmf::getColour( + S32 colour) +{ + unsigned red, green, blue; + + red = colour & 255; + green = (colour >> 8) & 255; + blue = (colour >> 16) & 255; + return (red << 16) + (green << 8) + blue; +} + +void KWmf::genericArc( + QString type, + QDataStream &operands) +{ + QPoint topLeft; + QPoint bottomRight; + QPoint start; + QPoint end; + + topLeft = normalisePoint(operands); + bottomRight = normalisePoint(operands); + start = normalisePoint(operands); + end = normalisePoint(operands); + + // WMF defines arcs with the major and minor axes of an ellipse, and two points. + // From each point draw a line to the center of the ellipse: the intercepts define + // the ends of the arc. + + QRect ellipse(topLeft, bottomRight); + QPoint centre = ellipse.center(); + double startAngle = atan2((double)(centre.y() - start.y()), (double)(centre.x() - start.x())); + double stopAngle = atan2((double)(centre.y() - end.y()), (double)(centre.x() - end.x())); + + startAngle = 180 * startAngle / PI; + stopAngle = 180 * stopAngle / PI; + + gotEllipse(m_dc, type, centre, ellipse.size() / 2, + static_cast<unsigned int>(startAngle), + static_cast<unsigned int>(stopAngle)); +} + +int KWmf::handleIndex(void) const +{ + int i; + + for (i = 0; i < s_maxHandles; i++) + { + if (!m_objectHandles[i]) + return i; + } + kdError(s_area) << "handle table full !" << endl; + return -1; +} + +//----------------------------------------------------------------------------- +KWmf::WinObjPenHandle *KWmf::handleCreatePen(void) +{ + WinObjPenHandle *handle = new WinObjPenHandle; + int idx = handleIndex(); + + if (idx >= 0) + m_objectHandles[idx] = handle; + return handle; +} + +//----------------------------------------------------------------------------- +KWmf::WinObjBrushHandle *KWmf::handleCreateBrush(void) +{ + WinObjBrushHandle *handle = new WinObjBrushHandle; + int idx = handleIndex(); + + if (idx >= 0) + m_objectHandles[idx] = handle; + return handle; +} + +//----------------------------------------------------------------------------- +void KWmf::handleDelete(int idx) +{ + if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx]) + { + delete m_objectHandles[idx]; + m_objectHandles[idx] = NULL; + } +} + +// +// +// + +void KWmf::invokeHandler( + S16 opcode, + U32 words, + QDataStream &operands) +{ + typedef void (KWmf::*method)(U32 words, QDataStream &operands); + + typedef struct + { + const char *name; + unsigned short opcode; + method handler; + } opcodeEntry; + + static const opcodeEntry funcTab[] = + { + { "ANIMATEPALETTE", 0x0436, 0 }, + { "ARC", 0x0817, &KWmf::opArc }, + { "BITBLT", 0x0922, 0 }, + { "CHORD", 0x0830, 0 }, + { "CREATEBRUSHINDIRECT", 0x02FC, &KWmf::opBrushCreateIndirect }, + { "CREATEFONTINDIRECT", 0x02FB, 0 }, + { "CREATEPALETTE", 0x00F7, 0 }, + { "CREATEPATTERNBRUSH", 0x01F9, 0 }, + { "CREATEPENINDIRECT", 0x02FA, &KWmf::opPenCreateIndirect }, + { "CREATEREGION", 0x06FF, 0 }, + { "DELETEOBJECT", 0x01F0, &KWmf::opObjectDelete }, + { "DIBBITBLT", 0x0940, 0 }, + { "DIBCREATEPATTERNBRUSH",0x0142, 0 }, + { "DIBSTRETCHBLT", 0x0b41, 0 }, + { "ELLIPSE", 0x0418, &KWmf::opEllipse }, + { "ESCAPE", 0x0626, &KWmf::opNoop }, + { "EXCLUDECLIPRECT", 0x0415, 0 }, + { "EXTFLOODFILL", 0x0548, 0 }, + { "EXTTEXTOUT", 0x0a32, 0 }, + { "FILLREGION", 0x0228, 0 }, + { "FLOODFILL", 0x0419, 0 }, + { "FRAMEREGION", 0x0429, 0 }, + { "INTERSECTCLIPRECT", 0x0416, 0 }, + { "INVERTREGION", 0x012A, 0 }, + { "LINETO", 0x0213, &KWmf::opLineTo }, + { "MOVETO", 0x0214, &KWmf::opMoveTo }, + { "OFFSETCLIPRGN", 0x0220, 0 }, + { "OFFSETVIEWPORTORG", 0x0211, 0 }, + { "OFFSETWINDOWORG", 0x020F, 0 }, + { "PAINTREGION", 0x012B, 0 }, + { "PATBLT", 0x061D, 0 }, + { "PIE", 0x081A, &KWmf::opPie }, + { "POLYGON", 0x0324, &KWmf::opPolygon }, + { "POLYLINE", 0x0325, &KWmf::opPolyline }, + { "POLYPOLYGON", 0x0538, 0 }, + { "REALIZEPALETTE", 0x0035, 0 }, + { "RECTANGLE", 0x041B, &KWmf::opRectangle }, + { "RESIZEPALETTE", 0x0139, 0 }, + { "RESTOREDC", 0x0127, &KWmf::opRestoreDc }, + { "ROUNDRECT", 0x061C, 0 }, + { "SAVEDC", 0x001E, &KWmf::opSaveDc }, + { "SCALEVIEWPORTEXT", 0x0412, 0 }, + { "SCALEWINDOWEXT", 0x0410, 0 }, + { "SELECTCLIPREGION", 0x012C, 0 }, + { "SELECTOBJECT", 0x012D, &KWmf::opObjectSelect }, + { "SELECTPALETTE", 0x0234, 0 }, + { "SETBKCOLOR", 0x0201, 0 }, + { "SETBKMODE", 0x0102, 0 }, + { "SETDIBTODEV", 0x0d33, 0 }, + { "SETMAPMODE", 0x0103, 0 }, + { "SETMAPPERFLAGS", 0x0231, 0 }, + { "SETPALENTRIES", 0x0037, 0 }, + { "SETPIXEL", 0x041F, 0 }, + { "SETPOLYFILLMODE", 0x0106, &KWmf::opPolygonSetFillMode }, + { "SETRELABS", 0x0105, 0 }, + { "SETROP2", 0x0104, 0 }, + { "SETSTRETCHBLTMODE", 0x0107, 0 }, + { "SETTEXTALIGN", 0x012E, 0 }, + { "SETTEXTCHAREXTRA", 0x0108, 0 }, + { "SETTEXTCOLOR", 0x0209, 0 }, + { "SETTEXTJUSTIFICATION", 0x020A, 0 }, + { "SETVIEWPORTEXT", 0x020E, 0 }, + { "SETVIEWPORTORG", 0x020D, 0 }, + { "SETWINDOWEXT", 0x020C, &KWmf::opWindowSetExt }, + { "SETWINDOWORG", 0x020B, &KWmf::opWindowSetOrg }, + { "STRETCHBLT", 0x0B23, 0 }, + { "STRETCHDIB", 0x0f43, 0 }, + { "TEXTOUT", 0x0521, 0 }, + { NULL, 0, 0 } + }; + unsigned i; + method result; + + // Scan lookup table for operation. + + for (i = 0; funcTab[i].name; i++) + { + if (funcTab[i].opcode == opcode) + { + break; + } + } + + // Invoke handler. + + result = funcTab[i].handler; + if (!result) + { + if (funcTab[i].name) + kdError(s_area) << "invokeHandler: unsupported opcode: " << + funcTab[i].name << + " operands: " << words << endl; + else + kdError(s_area) << "invokeHandler: unsupported opcode: 0x" << + QString::number(opcode, 16) << + " operands: " << words << endl; + + // Skip data we cannot use. + + for (i = 0; i < words; i++) + { + S16 discard; + + operands >> discard; + } + } + else + { + kdDebug(s_area) << "invokeHandler: opcode: " << funcTab[i].name << + " operands: " << words << endl; + + // We don't invoke the handler directly on the incoming operands, but + // via a temporary datastream. This adds overhead, but eliminates the + // need for the individual handlers to read *exactly* the right amount + // of data (thus speeding development, and possibly adding some + // future-proofing). + + if (words) + { + QByteArray *record = new QByteArray(words * 2); + QDataStream *body; + + operands.readRawBytes(record->data(), words * 2); + body = new QDataStream(*record, IO_ReadOnly); + body->setByteOrder(QDataStream::LittleEndian); + (this->*result)(words, *body); + delete body; + delete record; + } + else + { + QDataStream *body = new QDataStream(); + + (this->*result)(words, *body); + delete body; + } + } +} + +QPoint KWmf::normalisePoint( + QDataStream &operands) +{ + S16 x; + S16 y; + + operands >> x >> y; + return QPoint((x - m_windowOrgX) * m_windowFlipX / m_dpi, (y - m_windowOrgY) * m_windowFlipY / m_dpi); +} + +QSize KWmf::normaliseSize( + QDataStream &operands) +{ + S16 width; + S16 height; + + operands >> width >> height; + return QSize(width / m_dpi, height / m_dpi); +} + +bool KWmf::parse( + const QString &file) +{ + QFile in(file); + if (!in.open(IO_ReadOnly)) + { + kdError(s_area) << "Unable to open input file!" << endl; + in.close(); + return false; + } + QDataStream stream(&in); + bool result = parse(stream, in.size()); + in.close(); + return result; +} + +bool KWmf::parse( + QDataStream &stream, + unsigned size) +{ + int startedAt; + bool isPlaceable; + bool isEnhanced; + + startedAt = stream.device()->at(); + stream.setByteOrder(QDataStream::LittleEndian); // Great, I love Qt ! + + for (int i = 0; i < s_maxHandles; i++) + m_objectHandles[i] = NULL; + + typedef struct _RECT + { + S16 left; + S16 top; + S16 right; + S16 bottom; + } RECT; + + typedef struct _RECTL + { + S32 left; + S32 top; + S32 right; + S32 bottom; + } RECTL; + + typedef struct _SIZE + { + S16 width; + S16 height; + } SIZE; + + typedef struct _SIZEL + { + S32 width; + S32 height; + } SIZEL; + + struct WmfEnhMetaHeader + { + S32 iType; // Record type EMR_HEADER + S32 nSize; // Record size in bytes. This may be greater + // than the sizeof(ENHMETAHEADER). + RECTL rclBounds; // Inclusive-inclusive bounds in device units + RECTL rclFrame; // Inclusive-inclusive Picture Frame of metafile + // in .01 mm units + S32 dSignature; // Signature. Must be ENHMETA_SIGNATURE. + S32 nVersion; // Version number + S32 nBytes; // Size of the metafile in bytes + S32 nRecords; // Number of records in the metafile + S16 nHandles; // Number of handles in the handle table + // Handle index zero is reserved. + S16 sReserved; // Reserved. Must be zero. + S32 nDescription; // Number of chars in the unicode description string + // This is 0 if there is no description string + S32 offDescription; // Offset to the metafile description record. + // This is 0 if there is no description string + S32 nPalEntries; // Number of entries in the metafile palette. + SIZEL szlDevice; // Size of the reference device in pels + SIZEL szlMillimeters; // Size of the reference device in millimeters + }; + #define ENHMETA_SIGNATURE 0x464D4520 + + struct WmfMetaHeader + { + S16 mtType; + S16 mtHeaderSize; + S16 mtVersion; + S32 mtSize; + S16 mtNoObjects; + S32 mtMaxRecord; + S16 mtNoParameters; + }; + + struct WmfPlaceableHeader + { + S32 key; + S16 hmf; + RECT bbox; + S16 inch; + S32 reserved; + S16 checksum; + }; + #define APMHEADER_KEY 0x9AC6CDD7L + + WmfPlaceableHeader pheader; + WmfEnhMetaHeader eheader; + WmfMetaHeader header; + S16 checksum; + int fileAt; + + //----- Read placeable metafile header + + stream >> pheader.key; + isPlaceable = (pheader.key == (S32)APMHEADER_KEY); + if (isPlaceable) + { + stream >> pheader.hmf; + stream >> pheader.bbox.left; + stream >> pheader.bbox.top; + stream >> pheader.bbox.right; + stream >> pheader.bbox.bottom; + stream >> pheader.inch; + stream >> pheader.reserved; + stream >> pheader.checksum; + checksum = 0; + S16 *ptr = (S16 *)&pheader; + + // XOR in each of the S16s. + + for (unsigned i = 0; i < sizeof(WmfPlaceableHeader)/sizeof(S16); i++) + { + checksum ^= ptr[i]; + } + if (pheader.checksum != checksum) + isPlaceable = false; + m_dpi = (unsigned)((double)pheader.inch / m_dpi); + m_windowOrgX = pheader.bbox.left; + m_windowOrgY = pheader.bbox.top; + if (pheader.bbox.right > pheader.bbox.left) + m_windowFlipX = 1; + else + m_windowFlipX = -1; + if (pheader.bbox.bottom > pheader.bbox.top) + m_windowFlipY = 1; + else + m_windowFlipY = -1; + } + else + { + stream.device()->at(startedAt); + m_dpi = (unsigned)((double)576 / m_dpi); + m_windowOrgX = 0; + m_windowOrgY = 0; + m_windowFlipX = 1; + m_windowFlipY = 1; + } + + //----- Read as enhanced metafile header + + fileAt = stream.device()->at(); + stream >> eheader.iType; + stream >> eheader.nSize; + stream >> eheader.rclBounds.left; + stream >> eheader.rclBounds.top; + stream >> eheader.rclBounds.right; + stream >> eheader.rclBounds.bottom; + stream >> eheader.rclFrame.left; + stream >> eheader.rclFrame.top; + stream >> eheader.rclFrame.right; + stream >> eheader.rclFrame.bottom; + stream >> eheader.dSignature; + isEnhanced = (eheader.dSignature == ENHMETA_SIGNATURE); + if (isEnhanced) // is it really enhanced ? + { + stream >> eheader.nVersion; + stream >> eheader.nBytes; + stream >> eheader.nRecords; + stream >> eheader.nHandles; + stream >> eheader.sReserved; + stream >> eheader.nDescription; + stream >> eheader.offDescription; + stream >> eheader.nPalEntries; + stream >> eheader.szlDevice.width; + stream >> eheader.szlDevice.height; + stream >> eheader.szlMillimeters.width; + stream >> eheader.szlMillimeters.height; + + kdError(s_area) << "WMF Extended Header NOT YET IMPLEMENTED, SORRY." << endl; + /* + if (mSingleStep) + { + debug(" iType=%d", eheader.iType); + debug(" nSize=%d", eheader.nSize); + debug(" rclBounds=(%ld;%ld;%ld;%ld)", + eheader.rclBounds.left, eheader.rclBounds.top, + eheader.rclBounds.right, eheader.rclBounds.bottom); + debug(" rclFrame=(%ld;%ld;%ld;%ld)", + eheader.rclFrame.left, eheader.rclFrame.top, + eheader.rclFrame.right, eheader.rclFrame.bottom); + debug(" dSignature=%d", eheader.dSignature); + debug(" nVersion=%d", eheader.nVersion); + debug(" nBytes=%d", eheader.nBytes); + } + debug("NOT YET IMPLEMENTED, SORRY."); + */ + return false; + } + else // no, not enhanced + { + // debug("WMF Header"); + //----- Read as standard metafile header + stream.device()->at(fileAt); + stream >> header.mtType; + stream >> header.mtHeaderSize; + stream >> header.mtVersion; + stream >> header.mtSize; + stream >> header.mtNoObjects; + stream >> header.mtMaxRecord; + stream >> header.mtNoParameters; + /* + if (mSingleStep) + { + debug(" mtType=%u", header.mtType); + debug(" mtHeaderSize=%u", header.mtHeaderSize); + debug(" mtVersion=%u", header.mtVersion); + debug(" mtSize=%ld", header.mtSize); + } + */ + } + + walk((size - (stream.device()->at() - startedAt)) / 2, stream); + return true; +} + +void KWmf::opArc( + U32 /*words*/, + QDataStream &operands) +{ + genericArc("arc", operands); +} + +void KWmf::opBrushCreateIndirect( + U32 /*words*/, + QDataStream &operands) +{ + static Qt::BrushStyle hatchedStyleTab[] = + { + Qt::HorPattern, + Qt::FDiagPattern, + Qt::BDiagPattern, + Qt::CrossPattern, + Qt::DiagCrossPattern + }; + static Qt::BrushStyle styleTab[] = + { + Qt::SolidPattern, + Qt::NoBrush, + Qt::FDiagPattern, // hatched + Qt::Dense4Pattern, // should be custom bitmap pattern + Qt::HorPattern, // should be BS_INDEXED (?) + Qt::VerPattern, // should be device-independent bitmap + Qt::Dense6Pattern, // should be device-independent packed-bitmap + Qt::Dense2Pattern, // should be BS_PATTERN8x8 + Qt::Dense3Pattern // should be device-independent BS_DIBPATTERN8x8 + }; + Qt::BrushStyle style; + WinObjBrushHandle *handle = handleCreateBrush(); + S16 arg; + S32 colour; + S16 discard; + + operands >> arg >> colour; + handle->m_colour = getColour(colour); + if (arg == 2) + { + operands >> arg; + if (arg >= 0 && arg < 6) + { + style = hatchedStyleTab[arg]; + } + else + { + kdError(s_area) << "createBrushIndirect: invalid hatched brush " << arg << endl; + style = Qt::SolidPattern; + } + } + else + if (arg >= 0 && arg < 9) + { + style = styleTab[arg]; + operands >> discard; + } + else + { + kdError(s_area) << "createBrushIndirect: invalid brush " << arg << endl; + style = Qt::SolidPattern; + operands >> discard; + } + handle->m_style = style; +} + +void KWmf::opEllipse( + U32 /*words*/, + QDataStream &operands) +{ + QPoint topLeft; + QPoint bottomRight; + + topLeft = normalisePoint(operands); + bottomRight = normalisePoint(operands); + + QRect ellipse(topLeft, bottomRight); + + gotEllipse(m_dc, "full", ellipse.center(), ellipse.size() / 2, 0, 0); +} + +void KWmf::opLineTo( + U32 /*words*/, + QDataStream &operands) +{ + QPoint lineTo; + + lineTo = normalisePoint(operands); + QPointArray points(2); + points.setPoint(0, m_lineFrom); + points.setPoint(1, lineTo); + gotPolyline(m_dc, points); + + // Remember this point for next time. + + m_lineFrom = lineTo; +} + +void KWmf::opMoveTo( + U32 /*words*/, + QDataStream &operands) +{ + m_lineFrom = normalisePoint(operands); +} + +void KWmf::opNoop( + U32 words, + QDataStream &operands) +{ + skip(words, operands); +} + +//----------------------------------------------------------------------------- +void KWmf::opObjectDelete( + U32 /*words*/, + QDataStream &operands) +{ + S16 idx; + + operands >> idx; + handleDelete(idx); +} + +//----------------------------------------------------------------------------- +void KWmf::opObjectSelect( + U32 /*words*/, + QDataStream &operands) +{ + S16 idx; + + operands >> idx; + if (idx >= 0 && idx < s_maxHandles && m_objectHandles[idx]) + m_objectHandles[idx]->apply(*this); +} + +// +// +// + +void KWmf::opPenCreateIndirect( + U32 /*words*/, + QDataStream &operands) +{ + static Qt::PenStyle styleTab[] = + { + Qt::SolidLine, + Qt::DashLine, + Qt::DotLine, + Qt::DashDotLine, + Qt::DashDotDotLine, + Qt::NoPen, + Qt::SolidLine, // PS_INSIDEFRAME + Qt::SolidLine, // PS_USERSTYLE + Qt::SolidLine // PS_ALTERNATE + }; + WinObjPenHandle *handle = handleCreatePen(); + S16 arg; + S32 colour; + + operands >> arg; + if (arg >= 0 && arg < 8) + { + handle->m_style = styleTab[arg]; + } + else + { + kdError(s_area) << "createPenIndirect: invalid pen " << arg << endl; + handle->m_style = Qt::SolidLine; + } + operands >> arg; + handle->m_width = arg; + operands >> arg >> colour; + handle->m_colour = getColour(colour); +} + +void KWmf::opPie( + U32 /*words*/, + QDataStream &operands) +{ + genericArc("pie", operands); +} + +void KWmf::opPolygonSetFillMode( + U32 /*words*/, + QDataStream &operands) +{ + S16 tmp; + + operands >> tmp; + m_dc.m_winding = tmp != 0; +} + +void KWmf::opPolygon( + U32 /*words*/, + QDataStream &operands) +{ + S16 tmp; + + operands >> tmp; + QPointArray points(tmp); + + for (int i = 0; i < tmp; i++) + { + points.setPoint(i, normalisePoint(operands)); + } + gotPolygon(m_dc, points); +} + +void KWmf::opPolyline( + U32 /*words*/, + QDataStream &operands) +{ + S16 tmp; + + operands >> tmp; + QPointArray points(tmp); + + for (int i = 0; i < tmp; i++) + { + points.setPoint(i, normalisePoint(operands)); + } + gotPolyline(m_dc, points); +} + +void KWmf::opRectangle( + U32 /*words*/, + QDataStream &operands) +{ + QPoint topLeft; + QSize size; + + topLeft = normalisePoint(operands); + size = normaliseSize(operands); + QRect rect(topLeft, size); + QPointArray points(4); + + points.setPoint(0, topLeft); + points.setPoint(1, rect.topRight()); + points.setPoint(2, rect.bottomRight()); + points.setPoint(3, rect.bottomLeft()); + gotRectangle(m_dc, points); +} + +void KWmf::opRestoreDc( + U32 /*words*/, + QDataStream &operands) +{ + S16 pop; + S16 i; + + operands >> pop; + for (i = 0; i < pop; i++) + { + m_dc = m_savedDcs.pop(); + } +} + +void KWmf::opSaveDc( + U32 /*words*/, + QDataStream &/*operands*/) +{ + m_savedDcs.push(m_dc); + + // TBD: reinitialise m_dc. +} + +void KWmf::opWindowSetOrg( + U32 /*words*/, + QDataStream &operands) +{ + S16 top; + S16 left; + + operands >> top >> left; + m_windowOrgX = left; + m_windowOrgY = top; +} + +void KWmf::opWindowSetExt( + U32 /*words*/, + QDataStream &operands) +{ + S16 height; + S16 width; + + operands >> height >> width; + if (width > 0) + m_windowFlipX = 1; + else + m_windowFlipX = -1; + if (height > 0) + m_windowFlipY = 1; + else + m_windowFlipY = -1; +} + +void KWmf::penSet( + unsigned colour, + unsigned style, + unsigned width) +{ + m_dc.m_penColour = colour; + m_dc.m_penStyle = style; + m_dc.m_penWidth = width; +} + +void KWmf::skip( + U32 words, + QDataStream &operands) +{ + if ((int)words < 0) + { + kdError(s_area) << "skip: " << (int)words << endl; + return; + } + if (words) + { + U32 i; + S16 discard; + + kdDebug(s_area) << "skip: " << words << endl; + for (i = 0; i < words; i++) + { + operands >> discard; + } + } +} + +void KWmf::walk( + U32 words, + QDataStream &operands) +{ + // Read bits: + // + // struct WmfMetaRecord + // { + // S32 rdSize; // Record size (in words) of the function + // S16 rdFunction; // Record function number + // S16 rdParm[1]; // WORD array of parameters + // }; + // + // struct WmfEnhMetaRecord + // { + // S32 iType; // Record type EMR_xxx + // S32 nSize; // Record size in bytes + // S32 dParm[1]; // DWORD array of parameters + // }; + + S32 wordCount; + S16 opcode; + U32 length = 0; + + while (length < words) + { + operands >> wordCount; + operands >> opcode; + + // If we get some duff data, protect ourselves. + if (length + wordCount > words) + { + wordCount = words - length; + } + length += wordCount; + if (opcode == 0) + { + // This appears to be an EOF marker. + break; + } + + // Package the arguments... + + invokeHandler(opcode, wordCount - 3, operands); + } + + // Eat unexpected data that the caller may expect us to consume. + skip(words - length, operands); +} + +KWmf::DrawContext::DrawContext() +{ + // TBD: initalise with proper values. + m_brushColour = 0x808080; + m_brushStyle = 1; + m_penColour = 0x808080; + m_penStyle = 1; + m_penWidth = 1; +} + +void KWmf::WinObjBrushHandle::apply( + KWmf &p) +{ + p.brushSet(m_colour, m_style); +} + +void KWmf::WinObjPenHandle::apply( + KWmf &p) +{ + p.penSet(m_colour, m_style, m_width); +} diff --git a/lib/kwmf/kwmf.h b/lib/kwmf/kwmf.h new file mode 100644 index 00000000..4f1b050a --- /dev/null +++ b/lib/kwmf/kwmf.h @@ -0,0 +1,220 @@ +/* + Copyright (C) 2000, S.R.Haque <[email protected]>. + This file is part of the KDE project + + 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 + aS32 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. + +DESCRIPTION + + This is a generic parser for Windows MetaFiles (WMFs). The output is + a series of callbacks (a.k.a. virtual functions) which the caller can + override as required. + + This is based on code originally written by Stefan Taferner + ([email protected]). +*/ + +#ifndef KWMF_H +#define KWMF_H + +#include <qvaluestack.h> +#include <koffice_export.h> +class QDataStream; +class QPointArray; + +class KOWMF_EXPORT KWmf +{ +public: + + // Construction. + + KWmf( + unsigned dpi); + virtual ~KWmf(); + + // Called to parse the given file. + + bool parse( + const QString &file); + bool parse( + QDataStream &stream, + unsigned size); + + class KOWMF_EXPORT DrawContext + { + public: + DrawContext(); + bool m_winding; + unsigned m_brushColour; + unsigned m_brushStyle; + unsigned m_penColour; + unsigned m_penStyle; + unsigned m_penWidth; + }; + + // Should be protected... + + void brushSet( + unsigned colour, + unsigned style); + void penSet( + unsigned colour, + unsigned style, + unsigned width); + +protected: + // Override to get results of parsing. + + virtual void gotEllipse( + const DrawContext &dc, + QString type, + QPoint topLeft, + QSize halfAxes, + unsigned startAngle, + unsigned stopAngle) = 0; + virtual void gotPolygon( + const DrawContext &dc, + const QPointArray &points) = 0; + virtual void gotPolyline( + const DrawContext &dc, + const QPointArray &points) = 0; + virtual void gotRectangle( + const DrawContext &dc, + const QPointArray &points) = 0; + +private: + // Debug support. + + static const int s_area; + + // Use unambiguous names for Microsoft types. + + typedef short S16; + typedef int S32; + typedef unsigned int U32; + + int m_dpi; + int m_windowOrgX; + int m_windowOrgY; + int m_windowFlipX; + int m_windowFlipY; + DrawContext m_dc; + QValueStack<DrawContext> m_savedDcs; + QPoint m_lineFrom; + + // Windows handle management. + + class WinObjHandle + { + public: + virtual ~WinObjHandle () {} + virtual void apply(KWmf &p) = 0; + }; + + class WinObjBrushHandle: public WinObjHandle + { + public: + virtual void apply(KWmf &p); + unsigned m_colour; + unsigned m_style; + }; + + class WinObjPenHandle: public WinObjHandle + { + public: + virtual void apply(KWmf &p); + unsigned m_colour; + unsigned m_style; + unsigned m_width; + }; + + int handleIndex(void) const; + WinObjPenHandle *handleCreatePen(void); + WinObjBrushHandle *handleCreateBrush(void); + void handleDelete(int idx); + static const int s_maxHandles; + WinObjHandle **m_objectHandles; + + unsigned getColour(S32 colour); + QPoint normalisePoint( + QDataStream &operands); + QSize normaliseSize( + QDataStream &operands); + void genericArc( + QString type, + QDataStream &operands); + + // Opcode handling and painter methods. + + void walk( + U32 words, + QDataStream &stream); + void skip( + U32 words, + QDataStream &operands); + void invokeHandler( + S16 opcode, + U32 words, + QDataStream &operands); +/* + // draw multiple polygons + void opPolypolygon(U32 words, QDataStream &operands); +*/ + void opArc(U32 words, QDataStream &operands); + // create a logical brush + void opBrushCreateIndirect(U32 words, QDataStream &operands); + void opEllipse(U32 words, QDataStream &operands); + // draw line to coord + void opLineTo(U32 words, QDataStream &operands); + // move pen to coord + void opMoveTo(U32 words, QDataStream &operands); + // do nothing + void opNoop(U32 words, QDataStream &operands); + // Free object handle + void opObjectDelete(U32 words, QDataStream &operands); + // Activate object handle + void opObjectSelect(U32 words, QDataStream &operands); + // create a logical pen + void opPenCreateIndirect(U32 words, QDataStream &operands); + void opPie(U32 words, QDataStream &operands); + // draw polygon + void opPolygon(U32 words, QDataStream &operands); + // set polygon fill mode + void opPolygonSetFillMode(U32 words, QDataStream &operands); + // draw series of lines + void opPolyline(U32 words, QDataStream &operands); + void opRectangle(U32 words, QDataStream &operands); + // restore drawing context + void opRestoreDc(U32 words, QDataStream &operands); + // save drawing context + void opSaveDc(U32 words, QDataStream &operands); + // set window origin + void opWindowSetOrg(U32 words, QDataStream &operands); + // set window extents + void opWindowSetExt(U32 words, QDataStream &operands); +/* + // set background pen color + void opsetBkColor(U32 words, QDataStream &operands); + // set background pen mode + void opsetBkMode(U32 words, QDataStream &operands); + // Set raster operation mode + void opsetRop(U32 words, QDataStream &operands); + // Escape (enhanced command set) + void opescape(U32 words, QDataStream &operands); +*/ +}; + +#endif diff --git a/lib/kwmf/metafuncs.h b/lib/kwmf/metafuncs.h new file mode 100644 index 00000000..8675851e --- /dev/null +++ b/lib/kwmf/metafuncs.h @@ -0,0 +1,90 @@ +/* WMF Metafile Function Description Table + * Author: Stefan Taferner <[email protected]> + */ +#ifndef metafunc_h +#define metafunc_h + +class QWinMetaFile; + +static const struct MetaFuncRec +{ + const char* name; + unsigned short func; + void ( QWinMetaFile::*method )( long, short* ); +} metaFuncTab[] = + { + { "SETBKCOLOR", 0x0201, &QWinMetaFile::setBkColor }, + { "SETBKMODE", 0x0102, &QWinMetaFile::setBkMode }, + { "SETMAPMODE", 0x0103, &QWinMetaFile::noop }, + { "SETROP2", 0x0104, &QWinMetaFile::setRop }, + { "SETRELABS", 0x0105, &QWinMetaFile::noop }, + { "SETPOLYFILLMODE", 0x0106, &QWinMetaFile::setPolyFillMode }, + { "SETSTRETCHBLTMODE", 0x0107, &QWinMetaFile::noop }, + { "SETTEXTCHAREXTRA", 0x0108, &QWinMetaFile::noop }, + { "SETTEXTCOLOR", 0x0209, &QWinMetaFile::setTextColor }, + { "SETTEXTJUSTIFICATION", 0x020A, &QWinMetaFile::noop }, + { "SETWINDOWORG", 0x020B, &QWinMetaFile::setWindowOrg }, + { "SETWINDOWEXT", 0x020C, &QWinMetaFile::setWindowExt }, + { "SETVIEWPORTORG", 0x020D, &QWinMetaFile::noop }, + { "SETVIEWPORTEXT", 0x020E, &QWinMetaFile::noop }, + { "OFFSETWINDOWORG", 0x020F, &QWinMetaFile::noop }, + { "SCALEWINDOWEXT", 0x0410, &QWinMetaFile::noop }, + { "OFFSETVIEWPORTORG", 0x0211, &QWinMetaFile::noop }, + { "SCALEVIEWPORTEXT", 0x0412, &QWinMetaFile::noop }, + { "LINETO", 0x0213, &QWinMetaFile::lineTo }, + { "MOVETO", 0x0214, &QWinMetaFile::moveTo }, + { "EXCLUDECLIPRECT", 0x0415, &QWinMetaFile::excludeClipRect }, + { "INTERSECTCLIPRECT", 0x0416, &QWinMetaFile::intersectClipRect }, + { "ARC", 0x0817, &QWinMetaFile::arc }, + { "ELLIPSE", 0x0418, &QWinMetaFile::ellipse }, + { "FLOODFILL", 0x0419, &QWinMetaFile::noop }, + { "PIE", 0x081A, &QWinMetaFile::pie }, + { "RECTANGLE", 0x041B, &QWinMetaFile::rectangle }, + { "ROUNDRECT", 0x061C, &QWinMetaFile::roundRect }, + { "PATBLT", 0x061D, &QWinMetaFile::noop }, + { "SAVEDC", 0x001E, &QWinMetaFile::saveDC }, + { "SETPIXEL", 0x041F, &QWinMetaFile::setPixel }, + { "OFFSETCLIPRGN", 0x0220, &QWinMetaFile::noop }, + { "TEXTOUT", 0x0521, &QWinMetaFile::textOut }, + { "BITBLT", 0x0922, &QWinMetaFile::noop }, + { "STRETCHBLT", 0x0B23, &QWinMetaFile::noop }, + { "POLYGON", 0x0324, &QWinMetaFile::polygon }, + { "POLYLINE", 0x0325, &QWinMetaFile::polyline }, + { "ESCAPE", 0x0626, &QWinMetaFile::noop }, + { "RESTOREDC", 0x0127, &QWinMetaFile::restoreDC }, + { "FILLREGION", 0x0228, &QWinMetaFile::noop }, + { "FRAMEREGION", 0x0429, &QWinMetaFile::noop }, + { "INVERTREGION", 0x012A, &QWinMetaFile::noop }, + { "PAINTREGION", 0x012B, &QWinMetaFile::noop }, + { "SELECTCLIPREGION", 0x012C, &QWinMetaFile::noop }, + { "SELECTOBJECT", 0x012D, &QWinMetaFile::selectObject }, + { "SETTEXTALIGN", 0x012E, &QWinMetaFile::setTextAlign }, + { "CHORD", 0x0830, &QWinMetaFile::chord }, + { "SETMAPPERFLAGS", 0x0231, &QWinMetaFile::noop }, + { "EXTTEXTOUT", 0x0a32, &QWinMetaFile::extTextOut }, + { "SETDIBTODEV", 0x0d33, &QWinMetaFile::noop }, + { "SELECTPALETTE", 0x0234, &QWinMetaFile::noop }, + { "REALIZEPALETTE", 0x0035, &QWinMetaFile::noop }, + { "ANIMATEPALETTE", 0x0436, &QWinMetaFile::noop }, + { "SETPALENTRIES", 0x0037, &QWinMetaFile::noop }, + { "POLYPOLYGON", 0x0538, &QWinMetaFile::polyPolygon }, + { "RESIZEPALETTE", 0x0139, &QWinMetaFile::noop }, + { "DIBBITBLT", 0x0940, &QWinMetaFile::dibBitBlt }, + { "DIBSTRETCHBLT", 0x0b41, &QWinMetaFile::dibStretchBlt }, + { "DIBCREATEPATTERNBRUSH", 0x0142, &QWinMetaFile::dibCreatePatternBrush }, + { "STRETCHDIB", 0x0f43, &QWinMetaFile::stretchDib }, + { "EXTFLOODFILL", 0x0548, &QWinMetaFile::noop }, + { "DELETEOBJECT", 0x01f0, &QWinMetaFile::deleteObject }, + { "CREATEPALETTE", 0x00f7, &QWinMetaFile::createEmptyObject }, + { "CREATEPATTERNBRUSH", 0x01F9, &QWinMetaFile::createEmptyObject }, + { "CREATEPENINDIRECT", 0x02FA, &QWinMetaFile::createPenIndirect }, + { "CREATEFONTINDIRECT", 0x02FB, &QWinMetaFile::createFontIndirect }, + { "CREATEBRUSHINDIRECT", 0x02FC, &QWinMetaFile::createBrushIndirect }, + { "CREATEREGION", 0x06FF, &QWinMetaFile::createEmptyObject }, + { "END", 0, &QWinMetaFile::end }, + // always the latest in the table : in case of unknown function + { NULL, 0, &QWinMetaFile::noop }, + }; + + +#endif /*metafunc_h*/ diff --git a/lib/kwmf/qwmf.cc b/lib/kwmf/qwmf.cc new file mode 100644 index 00000000..89e2f50f --- /dev/null +++ b/lib/kwmf/qwmf.cc @@ -0,0 +1,1258 @@ +/* Windows Meta File Loader/Painter Class Implementation + * + * Copyright ( C ) 1998 Stefan Taferner + * Modified 2002 thierry lorthiois + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or ( at your + * option ) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. You should have received a copy + * of the GNU General Public License along with this program; if not, write + * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <math.h> +#include <assert.h> +#include <qfileinfo.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qdatastream.h> +#include <qapplication.h> +#include <qbuffer.h> +#include <kdebug.h> + +bool qwmfDebug = false; + +#include "qwmf.h" +#include "wmfstruct.h" +#include "metafuncs.h" + +#define QWMF_DEBUG 0 + + +class WmfCmd +{ +public: + ~WmfCmd() { if ( next ) delete next; } + WmfCmd* next; + unsigned short funcIndex; + long numParm; + short* parm; +}; + + +class WinObjHandle +{ +public: + virtual void apply( QPainter& p ) = 0; +}; + +class WinObjBrushHandle: public WinObjHandle +{ +public: + virtual void apply( QPainter& p ); + QBrush brush; + virtual ~WinObjBrushHandle() {}; +}; + +class WinObjPenHandle: public WinObjHandle +{ +public: + virtual void apply( QPainter& p ); + QPen pen; + virtual ~WinObjPenHandle() {}; +}; + +class WinObjPatternBrushHandle: public WinObjHandle +{ +public: + virtual void apply( QPainter& p ); + QBrush brush; + QPixmap image; + virtual ~WinObjPatternBrushHandle() {}; +}; + +class WinObjFontHandle: public WinObjHandle +{ +public: + virtual void apply( QPainter& p ); + QFont font; + int rotation; + virtual ~WinObjFontHandle() {}; +}; + +void WinObjBrushHandle::apply( QPainter& p ) +{ + p.setBrush( brush ); +} + +void WinObjPenHandle::apply( QPainter& p ) +{ + p.setPen( pen ); +} + +void WinObjPatternBrushHandle::apply( QPainter& p ) +{ + p.setBrush( brush ); +} + +void WinObjFontHandle::apply( QPainter& p ) +{ + p.setFont( font ); +} + +#define MAX_OBJHANDLE 64 + + + +//----------------------------------------------------------------------------- +QWinMetaFile::QWinMetaFile() +{ + mValid = false; + mFirstCmd = NULL; + mObjHandleTab = NULL; + mDpi = 1000; +} + + +//----------------------------------------------------------------------------- +QWinMetaFile::~QWinMetaFile() +{ + if ( mFirstCmd ) delete mFirstCmd; + if ( mObjHandleTab ) delete[] mObjHandleTab; +} + + +//----------------------------------------------------------------------------- +bool QWinMetaFile::load( const QString &filename ) +{ + QFile file( filename ); + + if ( !file.exists() ) + { + kdDebug() << "File " << QFile::encodeName(filename) << " does not exist" << endl; + return false; + } + + if ( !file.open( IO_ReadOnly ) ) + { + kdDebug() << "Cannot open file " << QFile::encodeName(filename) << endl; + return false; + } + + QByteArray ba = file.readAll(); + file.close(); + + QBuffer buffer( ba ); + buffer.open( IO_ReadOnly ); + return load( buffer ); +} + +//----------------------------------------------------------------------------- +bool QWinMetaFile::load( QBuffer &buffer ) +{ + QDataStream st; + WmfEnhMetaHeader eheader; + WmfMetaHeader header; + WmfPlaceableHeader pheader; + WORD checksum; + int filePos, idx, i; + WmfCmd *cmd, *last; + DWORD rdSize; + WORD rdFunc; + + mTextAlign = 0; + mRotation = 0; + mTextColor = Qt::black; + if ( mFirstCmd ) delete mFirstCmd; + mFirstCmd = NULL; + + st.setDevice( &buffer ); + st.setByteOrder( QDataStream::LittleEndian ); // Great, I love Qt ! + + //----- Read placeable metafile header + st >> pheader.key; + mIsPlaceable = ( pheader.key==( DWORD )APMHEADER_KEY ); + if ( mIsPlaceable ) + { + st >> pheader.hmf; + st >> pheader.bbox.left; + st >> pheader.bbox.top; + st >> pheader.bbox.right; + st >> pheader.bbox.bottom; + st >> pheader.inch; + st >> pheader.reserved; + st >> pheader.checksum; + checksum = calcCheckSum( &pheader ); + if ( pheader.checksum!=checksum ) mIsPlaceable = false; + + mDpi = pheader.inch; + mBBox.setLeft( pheader.bbox.left ); + mBBox.setTop( pheader.bbox.top ); + mBBox.setRight( pheader.bbox.right ); + mBBox.setBottom( pheader.bbox.bottom ); + mHeaderBoundingBox = mBBox; + if ( QWMF_DEBUG ) + { + kdDebug() << endl << "-------------------------------------------------" << endl; + kdDebug() << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl; + kdDebug() << " bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width() + << "; " << mBBox.height() << ")" << endl; + kdDebug() << " inch=" << pheader.inch << endl; + kdDebug() << " checksum=" << pheader.checksum << "( " + << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl; + } + } + else buffer.at( 0 ); + + //----- Read as enhanced metafile header + filePos = buffer.at(); + st >> eheader.iType; + st >> eheader.nSize; + st >> eheader.rclBounds.left; + st >> eheader.rclBounds.top; + st >> eheader.rclBounds.right; + st >> eheader.rclBounds.bottom; + st >> eheader.rclFrame.left; + st >> eheader.rclFrame.top; + st >> eheader.rclFrame.right; + st >> eheader.rclFrame.bottom; + st >> eheader.dSignature; + mIsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE ); + if ( mIsEnhanced ) // is it really enhanced ? + { + st >> eheader.nVersion; + st >> eheader.nBytes; + st >> eheader.nRecords; + st >> eheader.nHandles; + st >> eheader.sReserved; + st >> eheader.nDescription; + st >> eheader.offDescription; + st >> eheader.nPalEntries; + st >> eheader.szlDevice.width; + st >> eheader.szlDevice.height; + st >> eheader.szlMillimeters.width; + st >> eheader.szlMillimeters.height; + + if ( QWMF_DEBUG ) + { + kdDebug() << endl << "-------------------------------------------------" << endl; + kdDebug() << "WMF Extended Header:" << endl; + kdDebug() << " iType=" << eheader.iType << endl; + kdDebug() << " nSize=" << eheader.nSize << endl; + kdDebug() << " rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; " + << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl; + kdDebug() << " rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; " + << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl; + kdDebug() << " nBytes=" << eheader.nBytes << endl; + kdDebug() << "\nNOT YET IMPLEMENTED, SORRY." << endl; + } + } + else // no, not enhanced + { + //----- Read as standard metafile header + buffer.at( filePos ); + st >> header.mtType; + st >> header.mtHeaderSize; + st >> header.mtVersion; + st >> header.mtSize; + st >> header.mtNoObjects; + st >> header.mtMaxRecord; + st >> header.mtNoParameters; + if ( QWMF_DEBUG ) { + kdDebug() << "WMF Header: " << "mtSize=" << header.mtSize << endl; + } + } + + //----- Test header validity + mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable; + if ( mValid ) + { + //----- Read Metafile Records + last = NULL; + rdFunc = -1; + while ( !st.eof() && (rdFunc != 0) ) + { + st >> rdSize; + st >> rdFunc; + idx = findFunc( rdFunc ); + rdSize -= 3; + + cmd = new WmfCmd; + cmd->next = NULL; + if ( last ) last->next = cmd; + else mFirstCmd = cmd; + + cmd->funcIndex = idx; + cmd->numParm = rdSize; + cmd->parm = new WORD[ rdSize ]; + last = cmd; + + for ( i=0; i<rdSize && !st.eof(); i++ ) + st >> cmd->parm[ i ]; + + + if ( rdFunc == 0x020B ) { // SETWINDOWORG: dimensions + mBBox.setLeft( cmd->parm[ 1 ] ); + mBBox.setTop( cmd->parm[ 0 ] ); + } + if ( rdFunc == 0x020C ) { // SETWINDOWEXT: dimensions + mBBox.setWidth( cmd->parm[ 1 ] ); + mBBox.setHeight( cmd->parm[ 0 ] ); + } + + if ( i<rdSize ) + { + kdDebug() << "WMF : file truncated !" << endl; + return false; + } + } + //----- Test records validities + mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0); + if ( !mValid ) { + kdDebug() << "WMF : incorrect file format !" << endl; + } + } + else { + kdDebug() << "WMF Header : incorrect header !" << endl; + } + + buffer.close(); + return mValid; +} + + +//----------------------------------------------------------------------------- +bool QWinMetaFile::paint( const QPaintDevice* aTarget, bool absolute ) +{ + int idx, i; + WmfCmd* cmd; + + if ( !mValid ) return false; + + assert( aTarget!=NULL ); + if ( mPainter.isActive() ) return false; + + if ( mObjHandleTab ) delete[] mObjHandleTab; + mObjHandleTab = new WinObjHandle* [ MAX_OBJHANDLE ]; + for ( i=MAX_OBJHANDLE-1; i>=0; i-- ) + mObjHandleTab[ i ] = NULL; + + mPainter.resetXForm(); + mWinding = false; + mAbsoluteCoord = absolute; + + mPainter.begin( aTarget ); + if ( QWMF_DEBUG ) { + kdDebug() << "Bounding box : " << mBBox.left() + << " " << mBBox.top() << " " << mBBox.right() << " " << mBBox.bottom() << endl; + } + + if ( mAbsoluteCoord ) { + mPainter.setWindow( mBBox.top(), mBBox.left(), mBBox.width(), mBBox.height() ); + } + mInternalWorldMatrix.reset(); + + for ( cmd=mFirstCmd; cmd; cmd=cmd->next ) + { + idx = cmd->funcIndex; + ( this->*metaFuncTab[ idx ].method )( cmd->numParm, cmd->parm ); + + if ( QWMF_DEBUG ) { + QString str = "", param; + if ( metaFuncTab[ idx ].name == NULL ) { + str += "UNKNOWN "; + } + if ( metaFuncTab[ idx ].method == &QWinMetaFile::noop ) { + str += "UNIMPLEMENTED "; + } + str += metaFuncTab[ idx ].name; + str += " : "; + + for ( i=0 ; i < cmd->numParm ; i++ ) { + param.setNum( cmd->parm[ i ] ); + str += param; + str += " "; + } + kdDebug() << str << endl; + } + } +/* + // TODO: cleanup this code when QPicture::setBoundingBox() is possible in KOClipart (QT31) + // because actually QPicture::boundingBox() != mBBox() + mWindowsCoord += 1; + if ( mWindowsCoord == 2 ) { + kdDebug() << "DRAW ANGLES " << endl; + mPainter.setPen( Qt::white ); + mPainter.drawPoint( mBBox.left(), mBBox.top() ); + mPainter.drawPoint( mBBox.right(), mBBox.bottom() ); + } +*/ + mPainter.end(); + return true; +} + + +//----------------s------------------------------------------------------------- +// Metafile painter methods +//----------------------------------------------------------------------------- +void QWinMetaFile::setWindowOrg( long, short* parm ) +{ + if ( mAbsoluteCoord ) { + QRect r = mPainter.window(); + mPainter.setWindow( parm[ 1 ], parm[ 0 ], r.width(), r.height() ); + } + else { + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + + mInternalWorldMatrix.translate( -dx, -dy ); + mInternalWorldMatrix.translate( -parm[ 1 ], -parm[ 0 ] ); + mPainter.translate( -dx, -dy ); + mPainter.translate( -parm[ 1 ], -parm[ 0 ] ); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setWindowExt( long, short* parm ) +{ + // negative value allowed for width and height : QABS() forbidden + if ( mAbsoluteCoord ) { + QRect r = mPainter.window(); + mPainter.setWindow( r.left(), r.top(), parm[ 1 ], parm[ 0 ] ); + } + else { + if ( (parm[ 0 ] != 0) && (parm[ 1 ] != 0) ) { + QRect r = mPainter.window(); + double dx = mInternalWorldMatrix.dx(); + double dy = mInternalWorldMatrix.dy(); + double sx = mInternalWorldMatrix.m11(); + double sy = mInternalWorldMatrix.m22(); + + mInternalWorldMatrix.translate( -dx, -dy ); + mInternalWorldMatrix.scale( 1/sx, 1/sy ); + mPainter.translate( -dx, -dy ); + mPainter.scale( 1/sx, 1/sy ); + + sx = (double)r.width() / (double)parm[ 1 ]; + sy = (double)r.height() / (double)parm[ 0 ]; + + mInternalWorldMatrix.scale( sx, sy ); + mInternalWorldMatrix.translate( dx, dy ); + mPainter.scale( sx, sy ); + mPainter.translate( dx, dy ); + } + } +} + + +//----------------------------------------------------------------------------- +// Drawing +//----------------------------------------------------------------------------- +void QWinMetaFile::lineTo( long, short* parm ) +{ + mPainter.lineTo( parm[ 1 ], parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::moveTo( long, short* parm ) +{ + mPainter.moveTo( parm[ 1 ], parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::ellipse( long, short* parm ) +{ + mPainter.drawEllipse( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polygon( long, short* parm ) +{ + QPointArray* pa; + + pa = pointArray( parm[ 0 ], &parm[ 1 ] ); + mPainter.drawPolygon( *pa, mWinding ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polyPolygon( long, short* parm ) +{ + QRegion region; + int i, j, startPolygon; + + mPainter.save(); + + // define clipping region + QRect win = bbox(); + startPolygon = 1+parm[ 0 ]; + for ( i=0 ; i < parm[ 0 ] ; i++ ) { + QPointArray pa1( parm[ 1+i ] ); + for ( j=0 ; j < parm[ 1+i ] ; j++) { + pa1.setPoint ( j, parm[ startPolygon ], parm[ startPolygon+1 ] ); + startPolygon += 2; + } + QRegion r( pa1 ); + region = region.eor( r ); + } + mPainter.setClipRegion( region, QPainter::CoordPainter ); + + // fill polygons + mPainter.fillRect( win.left(), win.top(), win.width(), win.height(), mPainter.brush() ); + + // draw polygon's border if necessary + if ( mPainter.pen().style() != Qt::NoPen ) { + mPainter.setClipping( false ); + mPainter.setBrush( Qt::NoBrush ); + + QPointArray* pa; + int idxPolygon = 1 + parm[ 0 ]; + for ( i=0 ; i < parm[ 0 ] ; i++ ) { + pa = pointArray( parm[ 1+i ], &parm[ idxPolygon ] ); + mPainter.drawPolygon( *pa ); + idxPolygon += parm[ 1+i ] * 2; + } + } + + mPainter.restore(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::polyline( long, short* parm ) +{ + QPointArray* pa; + + pa = pointArray( parm[ 0 ], &parm[ 1 ] ); + mPainter.drawPolyline( *pa ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::rectangle( long, short* parm ) +{ + mPainter.drawRect( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::roundRect( long, short* parm ) +{ + int xRnd = 0, yRnd = 0; + + // convert (xRound, yRound) in percentage + if ( (parm[ 3 ] - parm[ 5 ]) != 0 ) + xRnd = (parm[ 1 ] * 100) / (parm[ 3 ] - parm[ 5 ]) ; + if ( (parm[ 2 ] - parm[ 4 ]) != 0 ) + yRnd = (parm[ 0 ] * 100) / (parm[ 2 ] - parm[ 4 ]) ; + + mPainter.drawRoundRect( parm[ 5 ], parm[ 4 ], parm[ 3 ]-parm[ 5 ], parm[ 2 ]-parm[ 4 ], xRnd, yRnd ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::arc( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawArc( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::chord( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawChord( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::pie( long, short* parm ) +{ + int xCenter, yCenter, angleStart, aLength; + + xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2); + yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2); + + xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength ); + + mPainter.drawPie( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setPolyFillMode( long, short* parm ) +{ + mWinding = parm[ 0 ]; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setBkColor( long, short* parm ) +{ + mPainter.setBackgroundColor( color( parm ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setBkMode( long, short* parm ) +{ + if ( parm[ 0 ]==1 ) mPainter.setBackgroundMode( Qt::TransparentMode ); + else mPainter.setBackgroundMode( Qt::OpaqueMode ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setPixel( long, short* parm ) +{ + QPen pen = mPainter.pen(); + mPainter.setPen( color( parm ) ); + mPainter.drawPoint( parm[ 3 ], parm[ 2 ] ); + mPainter.setPen( pen ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setRop( long, short* parm ) +{ + mPainter.setRasterOp( winToQtRaster( parm[ 0 ] ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::saveDC( long, short* ) +{ + mPainter.save(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::restoreDC( long, short *parm ) +{ + for ( int i=0; i > parm[ 0 ] ; i-- ) + mPainter.restore(); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::intersectClipRect( long, short* parm ) +{ +/* TODO: better implementation : need QT 3.0.2 + QRegion region = mPainter.clipRegion(); + if ( region.isEmpty() ) + region = bbox(); +*/ + QRegion region( bbox() ); + + QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] ); + region = region.intersect( newRegion ); + + mPainter.setClipRegion( region, QPainter::CoordPainter ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::excludeClipRect( long, short* parm ) +{ +/* TODO: better implementation : need QT 3.0.2 + QRegion region = mPainter.clipRegion(); + if ( region.isEmpty() ) + region = bbox(); +*/ + QRegion region( bbox() ); + + QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] ); + region = region.subtract( newRegion ); + + mPainter.setClipRegion( region, QPainter::CoordPainter ); +} + + +//----------------------------------------------------------------------------- +// Text +//----------------------------------------------------------------------------- +void QWinMetaFile::setTextColor( long, short* parm ) +{ + mTextColor = color( parm ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::setTextAlign( long, short* parm ) +{ + mTextAlign = parm[ 0 ]; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::textOut( long num, short* parm ) +{ + + short *copyParm = new short[ num + 1 ]; + + // re-order parameters + int idxOffset = (parm[ 0 ] / 2) + 1 + (parm[ 0 ] & 1); + copyParm[ 0 ] = parm[ idxOffset ]; + copyParm[ 1 ] = parm[ idxOffset + 1 ]; + copyParm[ 2 ] = parm[ 0 ]; + copyParm[ 3 ] = 0; + memcpy( ©Parm[ 4 ], &parm[ 1 ], parm[ 0 ] ); + + extTextOut( num + 1, copyParm ); + delete [] copyParm; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::extTextOut( long num, short* parm ) +{ + char* ptStr; + int x, y, width, height; + int idxOffset; + + if ( parm[ 3 ] != 0 ) // ETO_CLIPPED flag add 4 parameters + ptStr = (char*)&parm[ 8 ]; + else + ptStr = (char*)&parm[ 4 ]; + + QCString text( ptStr, parm[ 2 ] + 1 ); + + QFontMetrics fm( mPainter.font() ); + width = fm.width( text ) + fm.descent(); // because fm.width(text) isn't rigth with Italic text + height = fm.height(); + + mPainter.save(); + + if ( mTextAlign & 0x01 ) { // (left, top) position = current logical position + QPoint pos = mPainter.pos(); + x = pos.x(); + y = pos.y(); + } + else { // (left, top) position = parameters + x = parm[ 1 ]; + y = parm[ 0 ]; + } + + if ( mRotation ) { + mPainter.translate( parm[ 1 ], parm[ 0 ]); + mPainter.rotate ( mRotation ); + mPainter.translate( -parm[ 1 ], -parm[ 0 ] ); + } + + // alignment + if ( mTextAlign & 0x06 ) + x -= ( width / 2 ); + if ( mTextAlign & 0x08 ) + y -= (height - fm.descent()); + + mPainter.setPen( mTextColor ); + idxOffset = (parm[ 2 ] / 2) + 4 + (parm[ 2 ] & 1); + if ( ( parm[ 2 ] > 1 ) && ( num >= (idxOffset + parm[ 2 ]) ) && ( parm[ 3 ] == 0 ) ) { + // offset for each char + int left = x; + mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(0, 1) ); + for ( int i = 1; i < parm[ 2 ] ; i++ ) { + left += parm[ idxOffset + i - 1 ]; + mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(i, 1) ); + } + } + else { + mPainter.drawText( x, y, width, height, Qt::AlignLeft | Qt::AlignTop, text ); + } + + mPainter.restore(); + +} + + + +//----------------------------------------------------------------------------- +// Bitmap +//----------------------------------------------------------------------------- +void QWinMetaFile::dibBitBlt( long num, short* parm ) +{ + if ( num > 9 ) { // DIB image + QImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 8 ], (num - 8) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 5 ] < 0 ) { // width < 0 => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 4 ] < 0 ) { // height < 0 => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + mPainter.drawImage( parm[ 7 ], parm[ 6 ], bmpSrc, parm[ 3 ], parm[ 2 ], parm[ 5 ], parm[ 4 ] ); + mPainter.restore(); + } + } + else { + kdDebug() << "QWinMetaFile::dibBitBlt without image: not implemented " << endl; + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::dibStretchBlt( long num, short* parm ) +{ + QImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 10 ], (num - 10) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 7 ] < 0 ) { // width < 0 => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 6 ] < 0 ) { // height < 0 => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( parm[ 5 ], parm[ 4 ], parm[ 3 ], parm[ 2 ] ); + // TODO: scale the bitmap ( QImage::scale(parm[ 7 ], parm[ 6 ]) is actually too slow ) + + mPainter.drawImage( parm[ 9 ], parm[ 8 ], bmpSrc ); + mPainter.restore(); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::stretchDib( long num, short* parm ) +{ + QImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 11 ], (num - 11) * 2 ) ) { + long raster = toDWord( parm ); + + mPainter.setRasterOp( winToQtRaster( raster ) ); + + // wmf file allow negative width or height + mPainter.save(); + if ( parm[ 8 ] < 0 ) { // width < 0 => horizontal flip + QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + if ( parm[ 7 ] < 0 ) { // height < 0 => vertical flip + QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F ); + mPainter.setWorldMatrix( m, true ); + } + bmpSrc = bmpSrc.copy( parm[ 6 ], parm[ 5 ], parm[ 4 ], parm[ 3 ] ); + // TODO: scale the bitmap ( QImage::scale(parm[ 8 ], parm[ 7 ]) is actually too slow ) + + mPainter.drawImage( parm[ 10 ], parm[ 9 ], bmpSrc ); + mPainter.restore(); + } +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::dibCreatePatternBrush( long num, short* parm ) +{ + WinObjPatternBrushHandle* handle = new WinObjPatternBrushHandle; + addHandle( handle ); + QImage bmpSrc; + + if ( dibToBmp( bmpSrc, (char*)&parm[ 2 ], (num - 2) * 2 ) ) { + handle->image = bmpSrc; + handle->brush.setPixmap( handle->image ); + } +} + + +//----------------------------------------------------------------------------- +// Object handle +//----------------------------------------------------------------------------- +void QWinMetaFile::selectObject( long, short* parm ) +{ + int idx = parm[ 0 ]; + if ( idx>=0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] ) + mObjHandleTab[ idx ]->apply( mPainter ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::deleteObject( long, short* parm ) +{ + deleteHandle( parm[ 0 ] ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createEmptyObject( long, short* ) +{ + // allocation of an empty object (to keep object counting in sync) + WinObjPenHandle* handle = new WinObjPenHandle; + addHandle( handle ); + kdDebug() << "QWinMetaFile: unimplemented createObject " << endl; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createBrushIndirect( long, short* parm ) +{ + static Qt::BrushStyle hatchedStyleTab[] = + { + Qt::HorPattern, + Qt::FDiagPattern, + Qt::BDiagPattern, + Qt::CrossPattern, + Qt::DiagCrossPattern + }; + static Qt::BrushStyle styleTab[] = + { Qt::SolidPattern, + Qt::NoBrush, + Qt::FDiagPattern, /* hatched */ + Qt::Dense4Pattern, /* should be custom bitmap pattern */ + Qt::HorPattern, /* should be BS_INDEXED (?) */ + Qt::VerPattern, /* should be device-independent bitmap */ + Qt::Dense6Pattern, /* should be device-independent packed-bitmap */ + Qt::Dense2Pattern, /* should be BS_PATTERN8x8 */ + Qt::Dense3Pattern /* should be device-independent BS_DIBPATTERN8x8 */ + }; + Qt::BrushStyle style; + short arg; + WinObjBrushHandle* handle = new WinObjBrushHandle; + addHandle( handle ); + + arg = parm[ 0 ]; + if ( arg==2 ) + { + arg = parm[ 3 ]; + if ( arg>=0 && arg<5 ) style = hatchedStyleTab[ arg ]; + else + { + kdDebug() << "QWinMetaFile::createBrushIndirect: invalid hatched brush " << arg << endl; + style = Qt::SolidPattern; + } + } + else if ( arg>=0 && arg<9 ) + style = styleTab[ arg ]; + else + { + kdDebug() << "QWinMetaFile::createBrushIndirect: invalid brush " << arg << endl; + style = Qt::SolidPattern; + } + handle->brush.setStyle( style ); + handle->brush.setColor( color( parm+1 ) ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createPenIndirect( long, short* parm ) +{ + static Qt::PenStyle styleTab[] = + { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine, + Qt::NoPen, Qt::SolidLine }; + Qt::PenStyle style; + WinObjPenHandle* handle = new WinObjPenHandle; + addHandle( handle ); + + if ( parm[ 0 ]>=0 && parm[ 0 ]<6 ) style=styleTab[ parm[ 0 ] ]; + else + { + kdDebug() << "QWinMetaFile::createPenIndirect: invalid pen " << parm[ 0 ] << endl; + style = Qt::SolidLine; + } + + handle->pen.setStyle( style ); + handle->pen.setColor( color( parm+3 ) ); + handle->pen.setCapStyle( Qt::RoundCap ); + + //int width = 0; + // TODO : width of pen proportional to device context width + // DOESN'T WORK +/* + QRect devRec; + devRec = mPainter.xForm( mBBox ); + width = ( parm[ 0 ] * devRec.width() ) / mBBox.width() ; + kdDebug() << "CreatePenIndirect: " << endl; + kdDebug() << " log coord. : " << mBBox.width() << " " << mBBox.height() << endl; + kdDebug() << " log. pen : " << parm[ 1 ] << " " << parm[ 2 ] << endl; + kdDebug() << " dev. pen : " << width << endl; + handle->pen.setWidth( width ); +*/ +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::createFontIndirect( long , short* parm) +{ + WinObjFontHandle* handle = new WinObjFontHandle; + addHandle( handle ); + + QString family( (const char*)&parm[ 9 ] ); + + mRotation = -parm[ 2 ] / 10; // text rotation (in 1/10 degree) + // TODO: memorisation of rotation in object Font + handle->font.setFamily( family ); + handle->font.setFixedPitch( ((parm[ 8 ] & 0x01) == 0) ); + // TODO: investigation why some test case need -2. (size of font in logical point) + handle->font.setPointSize( QABS(parm[ 0 ]) - 2 ); + handle->font.setWeight( (parm[ 4 ] >> 3) ); + handle->font.setItalic( (parm[ 5 ] & 0x01) ); + handle->font.setUnderline( (parm[ 5 ] & 0x100) ); +} + + +//----------------------------------------------------------------------------- +// Misc +//----------------------------------------------------------------------------- +void QWinMetaFile::noop( long, short* ) +{ +} + + +void QWinMetaFile::end( long, short* ) +{ + // end of file : +// kdDebug() << "END bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width() << "; " << mBBox.height() << ")" << endl; +} + + +//----------------------------------------------------------------------------- +unsigned short QWinMetaFile::calcCheckSum( WmfPlaceableHeader* apmfh ) +{ + WORD* lpWord; + WORD wResult, i; + + // Start with the first word + wResult = *( lpWord = ( WORD* )( apmfh ) ); + // XOR in each of the other 9 words + for( i=1; i<=9; i++ ) + { + wResult ^= lpWord[ i ]; + } + return wResult; +} + + +//----------------------------------------------------------------------------- +int QWinMetaFile::findFunc( unsigned short aFunc ) const +{ + int i; + + for ( i=0; metaFuncTab[ i ].name; i++ ) + if ( metaFuncTab[ i ].func == aFunc ) return i; + + // here : unknown function + return i; +} + +//----------------------------------------------------------------------------- +QPointArray* QWinMetaFile::pointArray( short num, short* parm ) +{ + int i; + + mPoints.resize( num ); + + for ( i=0; i<num; i++, parm+=2 ) + mPoints.setPoint( i, parm[ 0 ], parm[ 1 ] ); + + return &mPoints; +} + +//----------------------------------------------------------------------------- +unsigned int QWinMetaFile::toDWord( short* parm ) +{ + unsigned int l; + +#if !defined( WORDS_BIGENDIAN ) + l = *( unsigned int* )( parm ); +#else + char *bytes; + char swap[ 4 ]; + bytes = ( char* )parm; + swap[ 0 ] = bytes[ 2 ]; + swap[ 1 ] = bytes[ 3 ]; + swap[ 2 ] = bytes[ 0 ]; + swap[ 3 ] = bytes[ 1 ]; + l = *( unsigned int* )( swap ); +#endif + + return l; +} + + +//----------------------------------------------------------------------------- +QColor QWinMetaFile::color( short* parm ) +{ + unsigned int colorRef; + int red, green, blue; + + colorRef = toDWord( parm ) & 0xffffff; + red = colorRef & 255; + green = ( colorRef>>8 ) & 255; + blue = ( colorRef>>16 ) & 255; + + return QColor( red, green, blue ); +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angleStart, int& angleLength ) +{ + float aStart, aLength; + + aStart = atan2( yStart, xStart ); + aLength = atan2( yEnd, xEnd ) - aStart; + + angleStart = (int)(aStart * 2880 / 3.14166); + angleLength = (int)(aLength * 2880 / 3.14166); + if ( angleLength < 0 ) angleLength = 5760 + angleLength; +} + + +//----------------------------------------------------------------------------- +void QWinMetaFile::addHandle( WinObjHandle* handle ) +{ + int idx; + + for ( idx=0; idx < MAX_OBJHANDLE ; idx++ ) + if ( mObjHandleTab[ idx ] == NULL ) break; + + if ( idx < MAX_OBJHANDLE ) + mObjHandleTab[ idx ] = handle; + else + kdDebug() << "QWinMetaFile error: handle table full !" << endl; +} + +//----------------------------------------------------------------------------- +void QWinMetaFile::deleteHandle( int idx ) +{ + if ( idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] ) + { + delete mObjHandleTab[ idx ]; + mObjHandleTab[ idx ] = NULL; + } +} + +//----------------------------------------------------------------------------- +Qt::RasterOp QWinMetaFile::winToQtRaster( short parm ) const +{ + static const Qt::RasterOp opTab[] = + { + Qt::CopyROP, + Qt::ClearROP, Qt::NandROP, Qt::NotAndROP, Qt::NotCopyROP, + Qt::AndNotROP, Qt::NotROP, Qt::XorROP, Qt::NorROP, + Qt::AndROP, Qt::NotXorROP, Qt::NopROP, Qt::NotOrROP, + Qt::CopyROP, Qt::OrNotROP, Qt::OrROP, Qt::SetROP + }; + + if ( parm > 0 && parm <= 16 ) + return opTab[ parm ]; + else + return Qt::CopyROP; +} + +//----------------------------------------------------------------------------- +Qt::RasterOp QWinMetaFile::winToQtRaster( long parm ) const +{ + /* TODO: Ternary raster operations + 0x00C000CA dest = (source AND pattern) + 0x00F00021 dest = pattern + 0x00FB0A09 dest = DPSnoo + 0x005A0049 dest = pattern XOR dest */ + static const struct OpTab + { + long winRasterOp; + Qt::RasterOp qtRasterOp; + } opTab[] = + { + { 0x00CC0020, Qt::CopyROP }, + { 0x00EE0086, Qt::OrROP }, + { 0x008800C6, Qt::AndROP }, + { 0x00660046, Qt::XorROP }, + { 0x00440328, Qt::AndNotROP }, + { 0x00330008, Qt::NotCopyROP }, + { 0x001100A6, Qt::NandROP }, + { 0x00C000CA, Qt::CopyROP }, + { 0x00BB0226, Qt::NotOrROP }, + { 0x00F00021, Qt::CopyROP }, + { 0x00FB0A09, Qt::CopyROP }, + { 0x005A0049, Qt::CopyROP }, + { 0x00550009, Qt::NotROP }, + { 0x00000042, Qt::ClearROP }, + { 0x00FF0062, Qt::SetROP } + }; + + int i; + for ( i=0 ; i < 15 ; i++ ) + if ( opTab[ i ].winRasterOp == parm ) + break; + + if ( i < 15 ) + return opTab[ i ].qtRasterOp; + else + return Qt::CopyROP; +} + +//----------------------------------------------------------------------------- +bool QWinMetaFile::dibToBmp( QImage& bmp, const char* dib, long size ) +{ + typedef struct _BMPFILEHEADER { + WORD bmType; + DWORD bmSize; + WORD bmReserved1; + WORD bmReserved2; + DWORD bmOffBits; + } BMPFILEHEADER; + + int sizeBmp = size + 14; + + QByteArray pattern( sizeBmp ); // BMP header and DIB data + pattern.fill(0); + memcpy( &pattern[ 14 ], dib, size ); + + // add BMP header + BMPFILEHEADER* bmpHeader; + bmpHeader = (BMPFILEHEADER*)((const char*)pattern); + bmpHeader->bmType = 0x4D42; + bmpHeader->bmSize = sizeBmp; + + if ( !bmp.loadFromData( (const uchar*)bmpHeader, pattern.size(), "BMP" ) ) { + kdDebug() << "QWinMetaFile::dibToBmp: invalid bitmap " << endl; + return false; + } + else { +// if ( bmp.save("/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP") ) +// if ( bmp.load( "/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP" ) ) +// fprintf(stderr, "Bitmap ok \n"); + return true; + } +} + diff --git a/lib/kwmf/qwmf.h b/lib/kwmf/qwmf.h new file mode 100644 index 00000000..1787f4c8 --- /dev/null +++ b/lib/kwmf/qwmf.h @@ -0,0 +1,231 @@ +/* Windows Meta File Loader + * + * Copyright ( C ) 1998 Stefan Taferner + * Modified 2002 thierry lorthiois + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or ( at your + * option ) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. You should have received a copy + * of the GNU General Public License along with this program; if not, write + * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef qwmf_h +#define qwmf_h + +#include <qstring.h> +#include <qpainter.h> +#include <qwmatrix.h> +#include <qpointarray.h> +#include <qpen.h> +#include <qcolor.h> +#include <qimage.h> +#include <qrect.h> + +class QBuffer; +class QString; +class WmfCmd; +class WinObjHandle; +class WinObjPenHandle; +class WinObjBrushHandle; +struct WmfPlaceableHeader; + +/** + * QWinMetaFile is a WMF viewer based on QT toolkit + * How to use QWinMetaFile : + * <pre> + *�#include "qwmf.h" + * QWinMetaFile wmf; + * QPicture pic; // or QImage pic; + * if ( wmf.load( filename ) + *� �wmf.paint( &pic ); + * </pre> + */ + + +class QWinMetaFile +{ +public: + QWinMetaFile(); + virtual ~QWinMetaFile(); + + /** + * Load WMF file. + * @return true on success. + */ + virtual bool load( const QString &fileName ); + virtual bool load( QBuffer &buffer ); + + /** + * Paint metafile to given paint-device using absolute or relative coordinate. + * - absolute coord. Reset the world transfomation Matrix + * - relative coord. Use the existing world transfomation Matrix + * + * @return true on success. + */ + virtual bool paint( const QPaintDevice* target, bool absolute=false ); + + /** + * @return true if the metafile is placeable. + */ + bool isPlaceable( void ) const { return mIsPlaceable; } + + /** + * @return true if the metafile is enhanced. + */ + bool isEnhanced( void ) const { return mIsEnhanced; } + + /** + * @return bounding rectangle + */ + QRect bbox( void ) const { return mBBox; } + +public: // should be protected but cannot + /* Metafile painter methods */ + + /** set window origin */ + void setWindowOrg( long num, short* parms ); + /** set window extents */ + void setWindowExt( long num, short* parms ); + + /****************** Drawing *******************/ + /** draw line to coord */ + void lineTo( long num, short* parms ); + /** move pen to coord */ + void moveTo( long num, short* parms ); + /** draw ellipse */ + void ellipse( long num, short* parms ); + /** draw polygon */ + void polygon( long num, short* parms ); + /** draw a list of polygons */ + void polyPolygon( long num, short* parms ); + /** draw series of lines */ + void polyline( long num, short* parms ); + /** draw a rectangle */ + void rectangle( long num, short* parms ); + /** draw round rectangle */ + void roundRect( long num, short* parms ); + /** draw arc */ + void arc( long num, short* parms ); + /** draw chord */ + void chord( long num, short* parms ); + /** draw pie */ + void pie( long num, short* parms ); + /** set polygon fill mode */ + void setPolyFillMode( long num, short* parms ); + /** set background pen color */ + void setBkColor( long num, short* parms ); + /** set background pen mode */ + void setBkMode( long num, short* parms ); + /** set a pixel */ + void setPixel( long num, short* parms ); + /** Set raster operation mode */ + void setRop( long num, short* parms ); + /** save device context */ + void saveDC( long num, short* parms ); + /** restore device context */ + void restoreDC( long num, short* parms ); + /** clipping region is the intersection of this region and the original region */ + void intersectClipRect( long num, short* parms ); + /** delete a clipping rectangle of the original region */ + void excludeClipRect( long num, short* parms ); + + /****************** Text *******************/ + /** set text color */ + void setTextColor( long num, short* parms ); + /** set text alignment */ + void setTextAlign( long num, short* parms ); + /** draw text */ + void textOut( long num, short* parms ); + void extTextOut( long num, short* parms ); + + /****************** Bitmap *******************/ + /** copies a DIB into a dest location */ + void dibBitBlt( long num, short* parms ); + /** stretches a DIB into a dest location */ + void dibStretchBlt( long num, short* parms ); + void stretchDib( long num, short* parms ); + /** create a pattern brush */ + void dibCreatePatternBrush( long num, short* parms ); + + /****************** Object handle *******************/ + /** Activate object handle */ + void selectObject( long num, short* parms ); + /** Free object handle */ + void deleteObject( long num, short* parms ); + /** create an empty object in the object list */ + void createEmptyObject( long num, short* parms ); + /** create a logical brush */ + void createBrushIndirect( long num, short* parms ); + /** create a logical pen */ + void createPenIndirect( long num, short* parms ); + /** create a logical font */ + void createFontIndirect( long num, short* parms ); + + /****************** misc *******************/ + /** nothing to do */ + void noop( long , short* ); + /** end of meta file */ + void end( long /*num*/, short* /*parms*/ ); + /** Resolution of the image in dots per inch */ + int dpi( void ) const { return mDpi; } + +protected: + /** Calculate header checksum */ + unsigned short calcCheckSum( WmfPlaceableHeader* ); + + /** Find function in metafunc table by metafile-function. + Returns index or -1 if not found. */ + virtual int findFunc( unsigned short aFunc ) const; + + /** Fills given parms into mPoints. */ + QPointArray* pointArray( short num, short* parms ); + + /** Returns color given by the two parameters */ + QColor color( short* parm ); + + /** Converts two parameters to long */ + unsigned int toDWord( short* parm ); + + /** Convert (x1,y1) and (x2, y2) positions in angle and angleLength */ + void xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angle, int& aLength ); + + /** Handle win-object-handles */ + void addHandle( WinObjHandle* ); + void deleteHandle( int ); + + /** Convert windows rasterOp in QT rasterOp */ + Qt::RasterOp winToQtRaster( short parm ) const; + Qt::RasterOp winToQtRaster( long parm ) const; + + /** Converts DIB to BMP */ + bool dibToBmp( QImage& bmp, const char* dib, long size); + +protected: + QPainter mPainter; + bool mIsPlaceable, mIsEnhanced, mValid; + + // coordinate system + bool mAbsoluteCoord; + QWMatrix mInternalWorldMatrix; // memorisation of WMF matrix transformation + QRect mHeaderBoundingBox; + QRect mBBox; + + // information shared between Metafile Functions + QColor mTextColor; + int mTextAlign, mRotation; + bool mWinding; + + WmfCmd* mFirstCmd; + WinObjHandle** mObjHandleTab; + QPointArray mPoints; + int mDpi; +}; + +#endif /*qwmf_h*/ diff --git a/lib/kwmf/wmfstruct.h b/lib/kwmf/wmfstruct.h new file mode 100644 index 00000000..ca4f1f7d --- /dev/null +++ b/lib/kwmf/wmfstruct.h @@ -0,0 +1,107 @@ +/* WMF Metafile Structures + * Author: Stefan Taferner <[email protected]> + */ +#ifndef wmfstruct_h +#define wmfstruct_h + +typedef short WORD; +typedef int DWORD; +typedef Q_INT32 LONG; +typedef void* _HANDLE; + +typedef struct _RECT +{ + WORD left; + WORD top; + WORD right; + WORD bottom; +} RECT; + +typedef struct _RECTL +{ + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECTL; + +typedef struct _SIZE +{ + WORD width; + WORD height; +} SIZE; + +typedef struct _SIZEL +{ + LONG width; + LONG height; +} SIZEL; + + +struct WmfEnhMetaHeader +{ + DWORD iType; // Record type EMR_HEADER + DWORD nSize; // Record size in bytes. This may be greater + // than the sizeof( ENHMETAHEADER ). + RECTL rclBounds; // Inclusive-inclusive bounds in device units + RECTL rclFrame; // Inclusive-inclusive Picture Frame of metafile + // in .01 mm units + DWORD dSignature; // Signature. Must be ENHMETA_SIGNATURE. + DWORD nVersion; // Version number + DWORD nBytes; // Size of the metafile in bytes + DWORD nRecords; // Number of records in the metafile + WORD nHandles; // Number of handles in the handle table + // Handle index zero is reserved. + WORD sReserved; // Reserved. Must be zero. + DWORD nDescription; // Number of chars in the unicode description string + // This is 0 if there is no description string + DWORD offDescription; // Offset to the metafile description record. + // This is 0 if there is no description string + DWORD nPalEntries; // Number of entries in the metafile palette. + SIZEL szlDevice; // Size of the reference device in pels + SIZEL szlMillimeters; // Size of the reference device in millimeters +}; +#define ENHMETA_SIGNATURE 0x464D4520 + + +struct WmfMetaHeader +{ + WORD mtType; + WORD mtHeaderSize; + WORD mtVersion; + DWORD mtSize; + WORD mtNoObjects; + DWORD mtMaxRecord; + WORD mtNoParameters; +}; + + +struct WmfPlaceableHeader +{ + DWORD key; + WORD hmf; + RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#define APMHEADER_KEY 0x9AC6CDD7 + + +struct WmfMetaRecord +{ + DWORD rdSize; // Record size ( in words ) of the function + WORD rdFunction; // Record function number + WORD rdParm[ 1 ]; // WORD array of parameters +}; + + +struct WmfEnhMetaRecord +{ + DWORD iType; // Record type EMR_xxx + DWORD nSize; // Record size in bytes + DWORD dParm[ 1 ]; // DWORD array of parameters +}; + + +#endif /*wmfstruct_h*/ |