/* 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 #include #include #include #include #include #include #include #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 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; } }