You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kwmf/kowmfreadprivate.cpp

1252 lines
33 KiB

/* This file is part of the KDE libraries
* Copyright (c) 1998 Stefan Taferner
* 2001/2003 thierry lorthiois (lorthioist@wanadoo.fr)
* 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 <tqfileinfo.h>
#include <tqimage.h>
#include <tqwmatrix.h>
#include <tqptrlist.h>
#include <tqpointarray.h>
#include <tqdatastream.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 TQByteArray& array )
{
// delete previous buffer
if ( mBuffer != 0 ) {
mBuffer->close();
delete mBuffer;
}
// load into buffer
mBuffer = new TQBuffer( array );
mBuffer->open( IO_ReadOnly );
// read and check the header
WmfEnhMetaHeader eheader;
WmfMetaHeader header;
WmfPlaceableHeader pheader;
unsigned short checksum;
int filePos;
TQDataStream st( mBuffer );
st.setByteOrder( TQDataStream::LittleEndian );
mStackOverflow = mWinding = false;
mTextAlign = mTextRotation = 0;
mTextColor = TQt::black;
mValid = false;
mStandard = false;
mPlaceable = false;
mEnhanced = false;
//----- Read placeable metafile header
st >> pheader.key;
if ( pheader.key==( TQ_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) ) {
TQ_UINT16 numFunction = 1;
TQ_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 ) {
TQ_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 ) {
TQ_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;
}
TQ_UINT16 numFunction;
TQ_UINT32 size;
int bufferOffset, j;
// buffer with functions
TQDataStream st( mBuffer );
st.setByteOrder( TQDataStream::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();
TQ_UINT16 param;
kdDebug() << j << " : " << numFunction << " : ";
for ( TQ_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( TQ_UINT32, TQDataStream& stream )
{
TQ_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( TQ_UINT32, TQDataStream& stream )
{
TQ_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( TQ_UINT32, TQDataStream &stream )
{
TQ_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( TQ_UINT32, TQDataStream &stream )
{
TQ_INT16 width, height;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left;
stream >> top >> left;
mReadWmf->lineTo( left, top );
}
void KoWmfReadPrivate::moveTo( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left;
stream >> top >> left;
mReadWmf->moveTo( left, top );
}
void KoWmfReadPrivate::ellipse( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left, right, bottom;
stream >> bottom >> right >> top >> left;
mReadWmf->drawEllipse( left, top, right-left, bottom-top );
}
void KoWmfReadPrivate::polygon( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 num;
stream >> num;
TQPointArray pa( num );
pointArray( stream, pa );
mReadWmf->drawPolygon( pa, mWinding );
}
void KoWmfReadPrivate::polyPolygon( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 numberPoly;
TQ_UINT16 sizePoly;
TQPtrList<TQPointArray> listPa;
stream >> numberPoly;
listPa.setAutoDelete( true );
for ( int i=0 ; i < numberPoly ; i++ ) {
stream >> sizePoly;
listPa.append( new TQPointArray( sizePoly ) );
}
// list of point array
TQPointArray *pa;
for ( pa = listPa.first() ; pa ; pa = listPa.next() ) {
pointArray( stream, *pa );
}
// draw polygon's
mReadWmf->drawPolyPolygon( listPa, mWinding );
listPa.clear();
}
void KoWmfReadPrivate::polyline( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 num;
stream >> num;
TQPointArray pa( num );
pointArray( stream, pa );
mReadWmf->drawPolyline( pa );
}
void KoWmfReadPrivate::rectangle( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left, right, bottom;
stream >> bottom >> right >> top >> left;
mReadWmf->drawRect( left, top, right-left, bottom-top );
}
void KoWmfReadPrivate::roundRect( TQ_UINT32, TQDataStream& stream )
{
int xRnd = 0, yRnd = 0;
TQ_UINT16 widthCorner, heightCorner;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
int xCenter, yCenter, angleStart, aLength;
TQ_INT16 topEnd, leftEnd, topStart, leftStart;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
int xCenter, yCenter, angleStart, aLength;
TQ_INT16 topEnd, leftEnd, topStart, leftStart;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
int xCenter, yCenter, angleStart, aLength;
TQ_INT16 topEnd, leftEnd, topStart, leftStart;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 winding;
stream >> winding;
mWinding = (winding != 0);
}
void KoWmfReadPrivate::setBkColor( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT32 color;
stream >> color;
mReadWmf->setBackgroundColor( qtColor( color ) );
}
void KoWmfReadPrivate::setBkMode( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 bkMode;
stream >> bkMode;
if ( bkMode == 1 )
mReadWmf->setBackgroundMode( Qt::TransparentMode );
else
mReadWmf->setBackgroundMode( Qt::OpaqueMode );
}
void KoWmfReadPrivate::setPixel( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left;
TQ_UINT32 color;
stream >> color >> top >> left;
TQPen oldPen = mReadWmf->pen();
TQPen pen = oldPen;
pen.setColor( qtColor( color ) );
mReadWmf->setPen( pen );
mReadWmf->moveTo( left, top );
mReadWmf->lineTo( left, top );
mReadWmf->setPen( oldPen );
}
void KoWmfReadPrivate::setRop( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT16 rop;
stream >> rop;
mReadWmf->setRasterOp( winToTQtRaster( rop ) );
}
void KoWmfReadPrivate::saveDC( TQ_UINT32, TQDataStream& )
{
mReadWmf->save();
}
void KoWmfReadPrivate::restoreDC( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 num;
stream >> num;
for ( int i=0; i > num ; i-- )
mReadWmf->restore();
}
void KoWmfReadPrivate::intersectClipRect( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left, right, bottom;
stream >> bottom >> right >> top >> left;
TQRegion region = mReadWmf->clipRegion();
TQRegion newRegion( left, top, right-left, bottom-top );
if ( region.isEmpty() ) {
region = newRegion;
}
else {
region = region.intersect( newRegion );
}
mReadWmf->setClipRegion( region );
}
void KoWmfReadPrivate::excludeClipRect( TQ_UINT32, TQDataStream& stream )
{
TQ_INT16 top, left, right, bottom;
stream >> bottom >> right >> top >> left;
TQRegion region = mReadWmf->clipRegion();
TQRegion newRegion( left, top, right-left, bottom-top );
if ( region.isEmpty() ) {
region = newRegion;
}
else {
region = region.subtract( newRegion );
}
mReadWmf->setClipRegion( region );
}
//-----------------------------------------------------------------------------
// Text
void KoWmfReadPrivate::setTextColor( TQ_UINT32, TQDataStream& stream )
{
TQ_UINT32 color;
stream >> color;
mTextColor = qtColor( color );
}
void KoWmfReadPrivate::setTextAlign( TQ_UINT32, TQDataStream& stream )
{
stream >> mTextAlign;
}
void KoWmfReadPrivate::textOut( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "textOut : unimplemented " << endl;
}
}
void KoWmfReadPrivate::extTextOut( TQ_UINT32 , TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "extTextOut : unimplemented " << endl;
}
}
//-----------------------------------------------------------------------------
// Bitmap
void KoWmfReadPrivate::SetStretchBltMode( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "SetStretchBltMode : unimplemented " << endl;
}
}
void KoWmfReadPrivate::dibBitBlt( TQ_UINT32 size, TQDataStream& stream )
{
TQ_UINT32 raster;
TQ_INT16 topSrc, leftSrc, widthSrc, heightSrc;
TQ_INT16 topDst, leftDst;
stream >> raster;
stream >> topSrc >> leftSrc >> heightSrc >> widthSrc;
stream >> topDst >> leftDst;
if ( size > 11 ) { // DIB image
TQImage bmpSrc;
if ( dibToBmp( bmpSrc, stream, (size - 11) * 2 ) ) {
mReadWmf->setRasterOp( winToTQtRaster( raster ) );
mReadWmf->save();
if ( widthSrc < 0 ) {
// negative width => horizontal flip
TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
mReadWmf->setWorldMatrix( m, true );
}
if ( heightSrc < 0 ) {
// negative height => vertical flip
TQWMatrix 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( TQ_UINT32 size, TQDataStream& stream )
{
TQ_UINT32 raster;
TQ_INT16 topSrc, leftSrc, widthSrc, heightSrc;
TQ_INT16 topDst, leftDst, widthDst, heightDst;
TQImage bmpSrc;
stream >> raster;
stream >> heightSrc >> widthSrc >> topSrc >> leftSrc;
stream >> heightDst >> widthDst >> topDst >> leftDst;
if ( dibToBmp( bmpSrc, stream, (size - 13) * 2 ) ) {
mReadWmf->setRasterOp( winToTQtRaster( raster ) );
mReadWmf->save();
if ( widthDst < 0 ) {
// negative width => horizontal flip
TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
mReadWmf->setWorldMatrix( m, true );
}
if ( heightDst < 0 ) {
// negative height => vertical flip
TQWMatrix 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 : TQImage::scale(widthDst, heightDst)
// is actually too slow
mReadWmf->drawImage( leftDst, topDst, bmpSrc );
mReadWmf->restore();
}
}
void KoWmfReadPrivate::stretchDib( TQ_UINT32 size, TQDataStream& stream )
{
TQ_UINT32 raster;
TQ_INT16 arg, topSrc, leftSrc, widthSrc, heightSrc;
TQ_INT16 topDst, leftDst, widthDst, heightDst;
TQImage bmpSrc;
stream >> raster >> arg;
stream >> heightSrc >> widthSrc >> topSrc >> leftSrc;
stream >> heightDst >> widthDst >> topDst >> leftDst;
if ( dibToBmp( bmpSrc, stream, (size - 14) * 2 ) ) {
mReadWmf->setRasterOp( winToTQtRaster( raster ) );
mReadWmf->save();
if ( widthDst < 0 ) {
// negative width => horizontal flip
TQWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
mReadWmf->setWorldMatrix( m, true );
}
if ( heightDst < 0 ) {
// negative height => vertical flip
TQWMatrix 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 ( TQImage::scale(param[ 8 ], param[ 7 ]) is actually too slow )
mReadWmf->drawImage( leftDst, topDst, bmpSrc );
mReadWmf->restore();
}
}
void KoWmfReadPrivate::dibCreatePatternBrush( TQ_UINT32 size, TQDataStream& stream )
{
KoWmfPatternBrushHandle* handle = new KoWmfPatternBrushHandle;
if ( addHandle( handle ) ) {
TQ_UINT32 arg;
TQImage 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( TQ_UINT32, TQDataStream& stream )
{
TQ_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( TQ_UINT32, TQDataStream& stream )
{
TQ_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( TQ_UINT32, TQDataStream& stream )
{
Qt::BrushStyle style;
TQ_UINT16 sty, arg2;
TQ_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( TQ_UINT32, TQDataStream& stream )
{
// TODO: userStyle and alternateStyle
Qt::PenStyle penStyle;
TQ_UINT32 color;
TQ_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( TQ_UINT32 size, TQDataStream& stream )
{
TQ_INT16 pointSize, rotation;
TQ_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( TQABS(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( TQ_UINT32, TQDataStream& )
{
}
TQ_UINT16 KoWmfReadPrivate::calcCheckSum( WmfPlaceableHeader* apmfh )
{
TQ_UINT16* lpWord;
TQ_UINT16 wResult, i;
// Start with the first word
wResult = *( lpWord = ( TQ_UINT16* )( apmfh ) );
// XOR in each of the other 9 words
for( i=1; i<=9; i++ )
{
wResult ^= lpWord[ i ];
}
return wResult;
}
void KoWmfReadPrivate::notyet( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "unimplemented " << endl;
}
}
void KoWmfReadPrivate::region( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "region : unimplemented " << endl;
}
}
void KoWmfReadPrivate::palette( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "palette : unimplemented " << endl;
}
}
void KoWmfReadPrivate::escape( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "escape : unimplemented " << endl;
}
}
void KoWmfReadPrivate::setRelAbs( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "setRelAbs : unimplemented " << endl;
}
}
void KoWmfReadPrivate::setMapMode( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "setMapMode : unimplemented " << endl;
}
}
void KoWmfReadPrivate::extFloodFill( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "extFloodFill : unimplemented " << endl;
}
}
void KoWmfReadPrivate::startDoc( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "startDoc : unimplemented " << endl;
}
}
void KoWmfReadPrivate::startPage( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "startPage : unimplemented " << endl;
}
}
void KoWmfReadPrivate::endDoc( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "endDoc : unimplemented " << endl;
}
}
void KoWmfReadPrivate::endPage( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "endPage : unimplemented " << endl;
}
}
void KoWmfReadPrivate::resetDC( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "resetDC : unimplemented " << endl;
}
}
void KoWmfReadPrivate::bitBlt( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "bitBlt : unimplemented " << endl;
}
}
void KoWmfReadPrivate::setDibToDev( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "setDibToDev : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createBrush( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "createBrush : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createPatternBrush( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "createPatternBrush : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createBitmap( TQ_UINT32, TQDataStream& )
{
if ( mNbrFunc ) {
kdDebug() << "createBitmap : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createBitmapIndirect( TQ_UINT32, TQDataStream& )
{
createEmptyObject();
if ( mNbrFunc ) {
kdDebug() << "createBitmapIndirect : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createPalette( TQ_UINT32, TQDataStream& )
{
createEmptyObject();
if ( mNbrFunc ) {
kdDebug() << "createPalette : unimplemented " << endl;
}
}
void KoWmfReadPrivate::createRegion( TQ_UINT32, TQDataStream& )
{
createEmptyObject();
if ( mNbrFunc ) {
kdDebug() << "createRegion : unimplemented " << endl;
}
}
//-----------------------------------------------------------------------------
// Utilities and conversion Wmf -> TQt
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( TQDataStream& stream, TQPointArray& pa )
{
TQ_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;
}
TQt::RasterOp KoWmfReadPrivate::winToTQtRaster( TQ_UINT16 param ) const
{
if ( param < 17 )
return koWmfOpTab16[ param ];
else
return TQt::CopyROP;
}
TQt::RasterOp KoWmfReadPrivate::winToTQtRaster( TQ_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 TQt::CopyROP;
}
bool KoWmfReadPrivate::dibToBmp( TQImage& bmp, TQDataStream& stream, TQ_UINT32 size )
{
typedef struct _BMPFILEHEADER {
TQ_UINT16 bmType;
TQ_UINT32 bmSize;
TQ_UINT16 bmReserved1;
TQ_UINT16 bmReserved2;
TQ_UINT32 bmOffBits;
} BMPFILEHEADER;
int sizeBmp = size + 14;
TQByteArray 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;
}
}