File indexing completed on 2024-12-22 05:00:58

0001 /* Windows Meta File Loader/Painter Class Implementation
0002  *
0003  * SPDX-FileCopyrightText: 1998 Stefan Taferner
0004  * SPDX-FileCopyrightText: 2002 thierry lorthiois
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <config-ktnef.h> // WORDS_BIGENDIAN
0010 
0011 #include <cassert>
0012 #include <cmath>
0013 
0014 #include <QBuffer>
0015 #include <QDataStream>
0016 #include <QFile>
0017 #include <QPainterPath>
0018 #include <QPolygon>
0019 
0020 #include "ktnef_debug.h"
0021 
0022 bool qwmfDebug = false;
0023 
0024 #include "metafuncs.h"
0025 #include "qwmf.h"
0026 #include "wmfstruct.h"
0027 
0028 #define QWMF_DEBUG 0
0029 
0030 class WmfCmd
0031 {
0032 public:
0033     ~WmfCmd()
0034     {
0035         delete next;
0036     }
0037 
0038     WmfCmd *next;
0039     unsigned short funcIndex;
0040     long numParm;
0041     short *parm;
0042 };
0043 
0044 class WinObjHandle
0045 {
0046 public:
0047     virtual ~WinObjHandle() = default;
0048 
0049     virtual void apply(QPainter &p) = 0;
0050 };
0051 
0052 class WinObjBrushHandle : public WinObjHandle
0053 {
0054 public:
0055     void apply(QPainter &p) override;
0056     QBrush brush;
0057     ~WinObjBrushHandle() override = default;
0058 };
0059 
0060 class WinObjPenHandle : public WinObjHandle
0061 {
0062 public:
0063     void apply(QPainter &p) override;
0064     QPen pen;
0065     ~WinObjPenHandle() override = default;
0066 };
0067 
0068 class WinObjPatternBrushHandle : public WinObjHandle
0069 {
0070 public:
0071     void apply(QPainter &p) override;
0072     QBrush brush;
0073     QImage image;
0074     ~WinObjPatternBrushHandle() override = default;
0075 };
0076 
0077 class WinObjFontHandle : public WinObjHandle
0078 {
0079 public:
0080     void apply(QPainter &p) override;
0081     QFont font;
0082     int rotation;
0083     ~WinObjFontHandle() override = default;
0084 };
0085 
0086 void WinObjBrushHandle::apply(QPainter &p)
0087 {
0088     p.setBrush(brush);
0089 }
0090 
0091 void WinObjPenHandle::apply(QPainter &p)
0092 {
0093     p.setPen(pen);
0094 }
0095 
0096 void WinObjPatternBrushHandle::apply(QPainter &p)
0097 {
0098     p.setBrush(brush);
0099 }
0100 
0101 void WinObjFontHandle::apply(QPainter &p)
0102 {
0103     p.setFont(font);
0104 }
0105 
0106 #define MAX_OBJHANDLE 64
0107 
0108 //-----------------------------------------------------------------------------
0109 QWinMetaFile::QWinMetaFile()
0110 {
0111     mValid = false;
0112     mFirstCmd = nullptr;
0113     mObjHandleTab = nullptr;
0114     mDpi = 1000;
0115 }
0116 
0117 //-----------------------------------------------------------------------------
0118 QWinMetaFile::~QWinMetaFile()
0119 {
0120     delete mFirstCmd;
0121     if (mObjHandleTab) {
0122         delete[] mObjHandleTab;
0123     }
0124 }
0125 
0126 //-----------------------------------------------------------------------------
0127 bool QWinMetaFile::load(const QString &filename)
0128 {
0129     QFile file(filename);
0130 
0131     if (!file.exists()) {
0132         qCDebug(KTNEFAPPS_LOG) << "File" << QFile::encodeName(filename) << " does not exist";
0133         return false;
0134     }
0135 
0136     if (!file.open(QIODevice::ReadOnly)) {
0137         qCDebug(KTNEFAPPS_LOG) << "Cannot open file" << QFile::encodeName(filename);
0138         return false;
0139     }
0140 
0141     QByteArray ba = file.readAll();
0142     file.close();
0143 
0144     QBuffer buffer(&ba);
0145     buffer.open(QIODevice::ReadOnly);
0146     return load(buffer);
0147 }
0148 
0149 //-----------------------------------------------------------------------------
0150 bool QWinMetaFile::load(QBuffer &buffer)
0151 {
0152     QDataStream st;
0153     WmfEnhMetaHeader eheader;
0154     WmfMetaHeader header;
0155     WmfPlaceableHeader pheader;
0156     int filePos;
0157     int idx;
0158     int i;
0159     WmfCmd *cmd;
0160     WmfCmd *last;
0161     DWORD rdSize;
0162     WORD rdFunc;
0163 
0164     mTextAlign = 0;
0165     mRotation = 0;
0166     mTextColor = Qt::black;
0167     delete mFirstCmd;
0168     mFirstCmd = nullptr;
0169 
0170     st.setDevice(&buffer);
0171     st.setByteOrder(QDataStream::LittleEndian); // Great, I love Qt !
0172 
0173     //----- Read placeable metafile header
0174     st >> pheader.key;
0175     mIsPlaceable = (pheader.key == (DWORD)APMHEADER_KEY);
0176     if (mIsPlaceable) {
0177         st >> pheader.hmf;
0178         st >> pheader.bbox.left;
0179         st >> pheader.bbox.top;
0180         st >> pheader.bbox.right;
0181         st >> pheader.bbox.bottom;
0182         st >> pheader.inch;
0183         st >> pheader.reserved;
0184         st >> pheader.checksum;
0185         const WORD checksum = calcCheckSum(&pheader);
0186         if (pheader.checksum != checksum) {
0187             mIsPlaceable = false;
0188         }
0189 
0190         mDpi = pheader.inch;
0191         mBBox.setLeft(pheader.bbox.left);
0192         mBBox.setTop(pheader.bbox.top);
0193         mBBox.setRight(pheader.bbox.right);
0194         mBBox.setBottom(pheader.bbox.bottom);
0195         mHeaderBoundingBox = mBBox;
0196         if (QWMF_DEBUG) {
0197             qCDebug(KTNEFAPPS_LOG) << "\n-------------------------------------------------";
0198             qCDebug(KTNEFAPPS_LOG) << "WMF Placeable Header (" << static_cast<int>(sizeof(pheader)) << "):";
0199             qCDebug(KTNEFAPPS_LOG) << "  bbox=(" << mBBox.left() << ";" << mBBox.top() << ";" << mBBox.width() << "; " << mBBox.height() << ")";
0200             qCDebug(KTNEFAPPS_LOG) << "  inch=" << pheader.inch;
0201             qCDebug(KTNEFAPPS_LOG) << "  checksum=" << pheader.checksum << "(" << (pheader.checksum == checksum ? "ok" : "wrong") << " )";
0202         }
0203     } else {
0204         buffer.reset();
0205     }
0206 
0207     //----- Read as enhanced metafile header
0208     filePos = buffer.pos();
0209     st >> eheader.iType;
0210     st >> eheader.nSize;
0211     st >> eheader.rclBounds.left;
0212     st >> eheader.rclBounds.top;
0213     st >> eheader.rclBounds.right;
0214     st >> eheader.rclBounds.bottom;
0215     st >> eheader.rclFrame.left;
0216     st >> eheader.rclFrame.top;
0217     st >> eheader.rclFrame.right;
0218     st >> eheader.rclFrame.bottom;
0219     st >> eheader.dSignature;
0220     mIsEnhanced = (eheader.dSignature == ENHMETA_SIGNATURE);
0221     if (mIsEnhanced) { // is it really enhanced ?
0222         st >> eheader.nVersion;
0223         st >> eheader.nBytes;
0224         st >> eheader.nRecords;
0225         st >> eheader.nHandles;
0226         st >> eheader.sReserved;
0227         st >> eheader.nDescription;
0228         st >> eheader.offDescription;
0229         st >> eheader.nPalEntries;
0230         st >> eheader.szlDevice.width;
0231         st >> eheader.szlDevice.height;
0232         st >> eheader.szlMillimeters.width;
0233         st >> eheader.szlMillimeters.height;
0234 
0235         if (QWMF_DEBUG) {
0236             qCDebug(KTNEFAPPS_LOG) << "\n-------------------------------------------------";
0237             qCDebug(KTNEFAPPS_LOG) << "WMF Extended Header:";
0238             qCDebug(KTNEFAPPS_LOG) << "  iType=" << eheader.iType;
0239             qCDebug(KTNEFAPPS_LOG) << "  nSize=" << eheader.nSize;
0240             qCDebug(KTNEFAPPS_LOG) << "  rclBounds=(" << eheader.rclBounds.left << ";" << eheader.rclBounds.top << ";" << eheader.rclBounds.right << "; "
0241                                    << eheader.rclBounds.bottom << ")";
0242             qCDebug(KTNEFAPPS_LOG) << "  rclFrame=(" << eheader.rclFrame.left << ";" << eheader.rclFrame.top << ";" << eheader.rclFrame.right << "; "
0243                                    << eheader.rclFrame.bottom << ")";
0244             qCDebug(KTNEFAPPS_LOG) << "  nBytes=" << eheader.nBytes;
0245             qCDebug(KTNEFAPPS_LOG) << "\nNOT YET IMPLEMENTED, SORRY.";
0246         }
0247     } else { // no, not enhanced
0248         //----- Read as standard metafile header
0249         buffer.seek(filePos);
0250         st >> header.mtType;
0251         st >> header.mtHeaderSize;
0252         st >> header.mtVersion;
0253         st >> header.mtSize;
0254         st >> header.mtNoObjects;
0255         st >> header.mtMaxRecord;
0256         st >> header.mtNoParameters;
0257         if (QWMF_DEBUG) {
0258             qCDebug(KTNEFAPPS_LOG) << "WMF Header:"
0259                                    << "mtSize=" << header.mtSize;
0260         }
0261     }
0262 
0263     //----- Test header validity
0264     mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable;
0265     if (mValid) {
0266         //----- Read Metafile Records
0267         last = nullptr;
0268         rdFunc = -1;
0269         while (!st.atEnd() && (rdFunc != 0)) {
0270             st >> rdSize;
0271             st >> rdFunc;
0272             idx = findFunc(rdFunc);
0273             rdSize -= 3;
0274 
0275             cmd = new WmfCmd;
0276             cmd->next = nullptr;
0277             if (last) {
0278                 last->next = cmd;
0279             } else {
0280                 mFirstCmd = cmd;
0281             }
0282 
0283             cmd->funcIndex = idx;
0284             cmd->numParm = rdSize;
0285             cmd->parm = new WORD[rdSize];
0286             last = cmd;
0287 
0288             for (i = 0; i < rdSize && !st.atEnd(); ++i) {
0289                 st >> cmd->parm[i];
0290             }
0291 
0292             if (rdFunc == 0x020B) { // SETWINDOWORG: dimensions
0293                 mBBox.setLeft(cmd->parm[1]);
0294                 mBBox.setTop(cmd->parm[0]);
0295             }
0296             if (rdFunc == 0x020C) { // SETWINDOWEXT: dimensions
0297                 mBBox.setWidth(cmd->parm[1]);
0298                 mBBox.setHeight(cmd->parm[0]);
0299             }
0300 
0301             if (i < rdSize) {
0302                 qCDebug(KTNEFAPPS_LOG) << "WMF : file truncated !";
0303                 return false;
0304             }
0305         }
0306         //----- Test records validities
0307         mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0);
0308         if (!mValid) {
0309             qCDebug(KTNEFAPPS_LOG) << "WMF : incorrect file format !";
0310         }
0311     } else {
0312         qCDebug(KTNEFAPPS_LOG) << "WMF Header : incorrect header !";
0313     }
0314 
0315     buffer.close();
0316     return mValid;
0317 }
0318 
0319 //-----------------------------------------------------------------------------
0320 bool QWinMetaFile::paint(QPaintDevice *aTarget, bool absolute)
0321 {
0322     int idx;
0323     int i;
0324     WmfCmd *cmd;
0325 
0326     if (!mValid) {
0327         return false;
0328     }
0329 
0330     assert(aTarget != nullptr);
0331     if (mPainter.isActive()) {
0332         return false;
0333     }
0334 
0335     if (mObjHandleTab) {
0336         delete[] mObjHandleTab;
0337     }
0338     mObjHandleTab = new WinObjHandle *[MAX_OBJHANDLE];
0339     for (i = MAX_OBJHANDLE - 1; i >= 0; --i) {
0340         mObjHandleTab[i] = nullptr;
0341     }
0342 
0343     mPainter.resetTransform();
0344     mWinding = false;
0345     mAbsoluteCoord = absolute;
0346 
0347     mPainter.begin(aTarget);
0348     if (QWMF_DEBUG) {
0349         qCDebug(KTNEFAPPS_LOG) << "Bounding box :" << mBBox.left() << " " << mBBox.top() << " " << mBBox.right() << " " << mBBox.bottom();
0350     }
0351 
0352     if (mAbsoluteCoord) {
0353         mPainter.setWindow(mBBox.top(), mBBox.left(), mBBox.width(), mBBox.height());
0354     }
0355     mInternalWorldMatrix.reset();
0356 
0357     for (cmd = mFirstCmd; cmd; cmd = cmd->next) {
0358         idx = cmd->funcIndex;
0359         (this->*metaFuncTab[idx].method)(cmd->numParm, cmd->parm);
0360 
0361         if (QWMF_DEBUG) {
0362             QString str;
0363             QString param;
0364             if (metaFuncTab[idx].name == nullptr) {
0365                 str += QLatin1StringView("UNKNOWN ");
0366             }
0367             if (metaFuncTab[idx].method == &QWinMetaFile::noop) {
0368                 str += QLatin1StringView("UNIMPLEMENTED ");
0369             }
0370             str += QLatin1StringView(metaFuncTab[idx].name);
0371             str += QLatin1StringView(" : ");
0372 
0373             for (i = 0; i < cmd->numParm; ++i) {
0374                 param.setNum(cmd->parm[i]);
0375                 str += param;
0376                 str += QLatin1Char(' ');
0377             }
0378             qCDebug(KTNEFAPPS_LOG) << str;
0379         }
0380     }
0381     /*
0382         // TODO: cleanup this code when QPicture::setBoundingBox() is possible in KOClipart (QT31)
0383         // because actually QPicture::boundingBox() != mBBox()
0384         mWindowsCoord += 1;
0385         if ( mWindowsCoord == 2 )  {
0386             qCDebug(KTNEFAPPS_LOG) <<"DRAW ANGLES";
0387             mPainter.setPen( Qt::white );
0388             mPainter.drawPoint( mBBox.left(), mBBox.top()  );
0389             mPainter.drawPoint( mBBox.right(), mBBox.bottom() );
0390         }
0391     */
0392     mPainter.end();
0393     return true;
0394 }
0395 
0396 //----------------s-------------------------------------------------------------
0397 // Metafile painter methods
0398 //-----------------------------------------------------------------------------
0399 void QWinMetaFile::setWindowOrg(long, short *parm)
0400 {
0401     if (mAbsoluteCoord) {
0402         QRect r = mPainter.window();
0403         mPainter.setWindow(parm[1], parm[0], r.width(), r.height());
0404     } else {
0405         double dx = mInternalWorldMatrix.dx();
0406         double dy = mInternalWorldMatrix.dy();
0407 
0408         mInternalWorldMatrix.translate(-dx, -dy);
0409         mInternalWorldMatrix.translate(-parm[1], -parm[0]);
0410         mPainter.translate(-dx, -dy);
0411         mPainter.translate(-parm[1], -parm[0]);
0412     }
0413 }
0414 
0415 //-----------------------------------------------------------------------------
0416 void QWinMetaFile::setWindowExt(long, short *parm)
0417 {
0418     // negative value allowed for width and height : QABS() forbidden
0419     if (mAbsoluteCoord) {
0420         QRect r = mPainter.window();
0421         mPainter.setWindow(r.left(), r.top(), parm[1], parm[0]);
0422     } else {
0423         if ((parm[0] != 0) && (parm[1] != 0)) {
0424             QRect r = mPainter.window();
0425             double dx = mInternalWorldMatrix.dx();
0426             double dy = mInternalWorldMatrix.dy();
0427             double sx = mInternalWorldMatrix.m11();
0428             double sy = mInternalWorldMatrix.m22();
0429 
0430             mInternalWorldMatrix.translate(-dx, -dy);
0431             mInternalWorldMatrix.scale(1 / sx, 1 / sy);
0432             mPainter.translate(-dx, -dy);
0433             mPainter.scale(1 / sx, 1 / sy);
0434 
0435             sx = (double)r.width() / (double)parm[1];
0436             sy = (double)r.height() / (double)parm[0];
0437 
0438             mInternalWorldMatrix.scale(sx, sy);
0439             mInternalWorldMatrix.translate(dx, dy);
0440             mPainter.scale(sx, sy);
0441             mPainter.translate(dx, dy);
0442         }
0443     }
0444 }
0445 
0446 //-----------------------------------------------------------------------------
0447 // Drawing
0448 //-----------------------------------------------------------------------------
0449 void QWinMetaFile::lineTo(long, short *parm)
0450 {
0451     mPainter.drawLine(mLastPos, QPoint(parm[1], parm[0]));
0452 }
0453 
0454 //-----------------------------------------------------------------------------
0455 void QWinMetaFile::moveTo(long, short *parm)
0456 {
0457     mLastPos = QPoint(parm[1], parm[0]);
0458 }
0459 
0460 //-----------------------------------------------------------------------------
0461 void QWinMetaFile::ellipse(long, short *parm)
0462 {
0463     mPainter.drawEllipse(parm[3], parm[2], parm[1] - parm[3], parm[0] - parm[2]);
0464 }
0465 
0466 //-----------------------------------------------------------------------------
0467 void QWinMetaFile::polygon(long, short *parm)
0468 {
0469     QPolygon *pa; // causing a memleck ???
0470 
0471     pa = pointArray(parm[0], &parm[1]);
0472     if (mWinding) {
0473         mPainter.drawPolygon(*pa, Qt::WindingFill);
0474     } else {
0475         mPainter.drawPolygon(*pa, Qt::OddEvenFill);
0476     }
0477 
0478     delete pa;
0479 }
0480 
0481 //-----------------------------------------------------------------------------
0482 void QWinMetaFile::polyPolygon(long, short *parm)
0483 {
0484     QRegion region;
0485     int i;
0486     int j;
0487     int startPolygon;
0488 
0489     mPainter.save();
0490 
0491     // define clipping region
0492     QRect win = bbox();
0493     startPolygon = 1 + parm[0];
0494     for (i = 0; i < parm[0]; ++i) {
0495         QPolygon pa1(parm[1 + i]);
0496         for (j = 0; j < parm[1 + i]; ++j) {
0497             pa1.setPoint(j, parm[startPolygon], parm[startPolygon + 1]);
0498             startPolygon += 2;
0499         }
0500         QRegion r(pa1);
0501         region = region.xored(r);
0502     }
0503     mPainter.setClipRegion(region);
0504 
0505     // fill polygons
0506     mPainter.fillRect(win.left(), win.top(), win.width(), win.height(), mPainter.brush());
0507 
0508     // draw polygon's border if necessary
0509     if (mPainter.pen().style() != Qt::NoPen) {
0510         mPainter.setClipping(false);
0511         mPainter.setBrush(Qt::NoBrush);
0512 
0513         QPolygon *pa;
0514         int idxPolygon = 1 + parm[0];
0515         for (i = 0; i < parm[0]; ++i) {
0516             pa = pointArray(parm[1 + i], &parm[idxPolygon]);
0517             mPainter.drawPolygon(*pa);
0518             idxPolygon += parm[1 + i] * 2;
0519         }
0520     }
0521 
0522     mPainter.restore();
0523 }
0524 
0525 //-----------------------------------------------------------------------------
0526 void QWinMetaFile::polyline(long, short *parm)
0527 {
0528     QPolygon *pa;
0529 
0530     pa = pointArray(parm[0], &parm[1]);
0531     mPainter.drawPolyline(*pa);
0532 }
0533 
0534 //-----------------------------------------------------------------------------
0535 void QWinMetaFile::rectangle(long, short *parm)
0536 {
0537     mPainter.drawRect(parm[3], parm[2], parm[1] - parm[3], parm[0] - parm[2]);
0538 }
0539 
0540 //-----------------------------------------------------------------------------
0541 void QWinMetaFile::roundRect(long, short *parm)
0542 {
0543     int xRnd = 0;
0544     int yRnd = 0;
0545 
0546     // convert (xRound, yRound) in percentage
0547     if ((parm[3] - parm[5]) != 0) {
0548         xRnd = (parm[1] * 100) / (parm[3] - parm[5]);
0549     }
0550     if ((parm[2] - parm[4]) != 0) {
0551         yRnd = (parm[0] * 100) / (parm[2] - parm[4]);
0552     }
0553 
0554     mPainter.drawRoundedRect(parm[5], parm[4], parm[3] - parm[5], parm[2] - parm[4], xRnd, yRnd, Qt::RelativeSize);
0555 }
0556 
0557 //-----------------------------------------------------------------------------
0558 void QWinMetaFile::arc(long, short *parm)
0559 {
0560     int xCenter;
0561     int yCenter;
0562     int angleStart;
0563     int aLength;
0564 
0565     xCenter = parm[7] + ((parm[5] - parm[7]) / 2);
0566     yCenter = parm[6] + ((parm[4] - parm[6]) / 2);
0567 
0568     xyToAngle(parm[3] - xCenter, yCenter - parm[2], parm[1] - xCenter, yCenter - parm[0], angleStart, aLength);
0569 
0570     mPainter.drawArc(parm[7], parm[6], parm[5] - parm[7], parm[4] - parm[6], angleStart, aLength);
0571 }
0572 
0573 //-----------------------------------------------------------------------------
0574 void QWinMetaFile::chord(long, short *parm)
0575 {
0576     int xCenter;
0577     int yCenter;
0578     int angleStart;
0579     int aLength;
0580 
0581     xCenter = parm[7] + ((parm[5] - parm[7]) / 2);
0582     yCenter = parm[6] + ((parm[4] - parm[6]) / 2);
0583 
0584     xyToAngle(parm[3] - xCenter, yCenter - parm[2], parm[1] - xCenter, yCenter - parm[0], angleStart, aLength);
0585 
0586     mPainter.drawChord(parm[7], parm[6], parm[5] - parm[7], parm[4] - parm[6], angleStart, aLength);
0587 }
0588 
0589 //-----------------------------------------------------------------------------
0590 void QWinMetaFile::pie(long, short *parm)
0591 {
0592     int xCenter;
0593     int yCenter;
0594     int angleStart;
0595     int aLength;
0596 
0597     xCenter = parm[7] + ((parm[5] - parm[7]) / 2);
0598     yCenter = parm[6] + ((parm[4] - parm[6]) / 2);
0599 
0600     xyToAngle(parm[3] - xCenter, yCenter - parm[2], parm[1] - xCenter, yCenter - parm[0], angleStart, aLength);
0601 
0602     mPainter.drawPie(parm[7], parm[6], parm[5] - parm[7], parm[4] - parm[6], angleStart, aLength);
0603 }
0604 
0605 //-----------------------------------------------------------------------------
0606 void QWinMetaFile::setPolyFillMode(long, short *parm)
0607 {
0608     mWinding = parm[0];
0609 }
0610 
0611 //-----------------------------------------------------------------------------
0612 void QWinMetaFile::setBkColor(long, short *parm)
0613 {
0614     mPainter.setBackground(QBrush(color(parm)));
0615 }
0616 
0617 //-----------------------------------------------------------------------------
0618 void QWinMetaFile::setBkMode(long, short *parm)
0619 {
0620     if (parm[0] == 1) {
0621         mPainter.setBackgroundMode(Qt::TransparentMode);
0622     } else {
0623         mPainter.setBackgroundMode(Qt::OpaqueMode);
0624     }
0625 }
0626 
0627 //-----------------------------------------------------------------------------
0628 void QWinMetaFile::setPixel(long, short *parm)
0629 {
0630     QPen pen = mPainter.pen();
0631     mPainter.setPen(color(parm));
0632     mPainter.drawPoint(parm[3], parm[2]);
0633     mPainter.setPen(pen);
0634 }
0635 
0636 //-----------------------------------------------------------------------------
0637 void QWinMetaFile::setRop(long, short *parm)
0638 {
0639     mPainter.setCompositionMode(winToQtComposition(parm[0]));
0640 }
0641 
0642 //-----------------------------------------------------------------------------
0643 void QWinMetaFile::saveDC(long, short *)
0644 {
0645     mPainter.save();
0646 }
0647 
0648 //-----------------------------------------------------------------------------
0649 void QWinMetaFile::restoreDC(long, short *parm)
0650 {
0651     for (int i = 0; i > parm[0]; i--) {
0652         mPainter.restore();
0653     }
0654 }
0655 
0656 //-----------------------------------------------------------------------------
0657 void QWinMetaFile::intersectClipRect(long, short *parm)
0658 {
0659     /*  TODO: better implementation : need QT 3.0.2
0660         QRegion region = mPainter.clipRegion();
0661         if ( region.isEmpty() )
0662             region = bbox();
0663     */
0664     QRegion region(bbox());
0665 
0666     QRegion newRegion(parm[3], parm[2], parm[1] - parm[3], parm[0] - parm[2]);
0667     region = region.intersected(newRegion);
0668 
0669     mPainter.setClipRegion(region);
0670 }
0671 
0672 //-----------------------------------------------------------------------------
0673 void QWinMetaFile::excludeClipRect(long, short *parm)
0674 {
0675     /*  TODO: better implementation : need QT 3.0.2
0676         QRegion region = mPainter.clipRegion();
0677         if ( region.isEmpty() )
0678             region = bbox();
0679     */
0680     QRegion region(bbox());
0681 
0682     QRegion newRegion(parm[3], parm[2], parm[1] - parm[3], parm[0] - parm[2]);
0683     region = region.subtracted(newRegion);
0684 
0685     mPainter.setClipRegion(region);
0686 }
0687 
0688 //-----------------------------------------------------------------------------
0689 // Text
0690 //-----------------------------------------------------------------------------
0691 void QWinMetaFile::setTextColor(long, short *parm)
0692 {
0693     mTextColor = color(parm);
0694 }
0695 
0696 //-----------------------------------------------------------------------------
0697 void QWinMetaFile::setTextAlign(long, short *parm)
0698 {
0699     mTextAlign = parm[0];
0700 }
0701 
0702 //-----------------------------------------------------------------------------
0703 void QWinMetaFile::textOut(long num, short *parm)
0704 {
0705     auto copyParm = new short[num + 1];
0706 
0707     // re-order parameters
0708     int idxOffset = (parm[0] / 2) + 1 + (parm[0] & 1);
0709     copyParm[0] = parm[idxOffset];
0710     copyParm[1] = parm[idxOffset + 1];
0711     copyParm[2] = parm[0];
0712     copyParm[3] = 0;
0713     memcpy(&copyParm[4], &parm[1], parm[0]);
0714 
0715     extTextOut(num + 1, copyParm);
0716     delete[] copyParm;
0717 }
0718 
0719 //-----------------------------------------------------------------------------
0720 void QWinMetaFile::extTextOut(long num, short *parm)
0721 {
0722     char *ptStr;
0723     int x;
0724     int y;
0725     int width;
0726     int height;
0727     int idxOffset;
0728 
0729     if (parm[3] != 0) { // ETO_CLIPPED flag add 4 parameters
0730         ptStr = (char *)&parm[8];
0731     } else {
0732         ptStr = (char *)&parm[4];
0733     }
0734 
0735     QByteArray text(ptStr, parm[2] + 1);
0736 
0737     QFontMetrics fm(mPainter.font());
0738     width = fm.boundingRect(QLatin1StringView(text)).width() + fm.descent(); // because fm.width(text) isn't rigth with Italic text
0739     height = fm.height();
0740 
0741     mPainter.save();
0742 
0743     if (mTextAlign & 0x01) { // (left, top) position = current logical position
0744         x = mLastPos.x();
0745         y = mLastPos.y();
0746     } else { // (left, top) position = parameters
0747         x = parm[1];
0748         y = parm[0];
0749     }
0750 
0751     if (mRotation) {
0752         mPainter.translate(parm[1], parm[0]);
0753         mPainter.rotate(mRotation);
0754         mPainter.translate(-parm[1], -parm[0]);
0755     }
0756 
0757     // alignment
0758     if (mTextAlign & 0x06) {
0759         x -= (width / 2);
0760     }
0761     if (mTextAlign & 0x08) {
0762         y -= (height - fm.descent());
0763     }
0764 
0765     mPainter.setPen(mTextColor);
0766     idxOffset = (parm[2] / 2) + 4 + (parm[2] & 1);
0767     if ((parm[2] > 1) && (num >= (idxOffset + parm[2])) && (parm[3] == 0)) {
0768         // offset for each char
0769         int left = x;
0770         mPainter.drawText(left, y, width, height, Qt::AlignLeft | Qt::AlignTop, QLatin1StringView(text.mid(0, 1)));
0771         for (int i = 1; i < parm[2]; ++i) {
0772             left += parm[idxOffset + i - 1];
0773             mPainter.drawText(left, y, width, height, Qt::AlignLeft | Qt::AlignTop, QLatin1StringView(text.mid(i, 1)));
0774         }
0775     } else {
0776         mPainter.drawText(x, y, width, height, Qt::AlignLeft | Qt::AlignTop, QLatin1StringView(text));
0777     }
0778 
0779     mPainter.restore();
0780 }
0781 
0782 //-----------------------------------------------------------------------------
0783 // Bitmap
0784 //-----------------------------------------------------------------------------
0785 void QWinMetaFile::dibBitBlt(long num, short *parm)
0786 {
0787     if (num > 9) { // DIB image
0788         QImage bmpSrc;
0789 
0790         if (dibToBmp(bmpSrc, (char *)&parm[8], (num - 8) * 2)) {
0791             long raster = toDWord(parm);
0792 
0793             mPainter.setCompositionMode(winToQtComposition(raster));
0794 
0795             // wmf file allow negative width or height
0796             mPainter.save();
0797             if (parm[5] < 0) { // width < 0 => horizontal flip
0798                 QTransform m(-1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F);
0799                 mPainter.setWorldTransform(m, true);
0800             }
0801             if (parm[4] < 0) { // height < 0 => vertical flip
0802                 QTransform m(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F);
0803                 mPainter.setWorldTransform(m, true);
0804             }
0805             mPainter.drawImage(parm[7], parm[6], bmpSrc, parm[3], parm[2], parm[5], parm[4]);
0806             mPainter.restore();
0807         }
0808     } else {
0809         qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::dibBitBlt without image: not implemented";
0810     }
0811 }
0812 
0813 //-----------------------------------------------------------------------------
0814 void QWinMetaFile::dibStretchBlt(long num, short *parm)
0815 {
0816     QImage bmpSrc;
0817 
0818     if (dibToBmp(bmpSrc, (char *)&parm[10], (num - 10) * 2)) {
0819         long raster = toDWord(parm);
0820 
0821         mPainter.setCompositionMode(winToQtComposition(raster));
0822 
0823         // wmf file allow negative width or height
0824         mPainter.save();
0825         if (parm[7] < 0) { // width < 0 => horizontal flip
0826             QTransform m(-1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F);
0827             mPainter.setWorldTransform(m, true);
0828         }
0829         if (parm[6] < 0) { // height < 0 => vertical flip
0830             QTransform m(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F);
0831             mPainter.setWorldTransform(m, true);
0832         }
0833         bmpSrc = bmpSrc.copy(parm[5], parm[4], parm[3], parm[2]);
0834         // TODO: scale the bitmap ( QImage::scale(parm[ 7 ], parm[ 6 ]) is actually too slow )
0835 
0836         mPainter.drawImage(parm[9], parm[8], bmpSrc);
0837         mPainter.restore();
0838     }
0839 }
0840 
0841 //-----------------------------------------------------------------------------
0842 void QWinMetaFile::stretchDib(long num, short *parm)
0843 {
0844     QImage bmpSrc;
0845 
0846     if (dibToBmp(bmpSrc, (char *)&parm[11], (num - 11) * 2)) {
0847         long raster = toDWord(parm);
0848 
0849         mPainter.setCompositionMode(winToQtComposition(raster));
0850 
0851         // wmf file allow negative width or height
0852         mPainter.save();
0853         if (parm[8] < 0) { // width < 0 => horizontal flip
0854             QTransform m(-1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F);
0855             mPainter.setWorldTransform(m, true);
0856         }
0857         if (parm[7] < 0) { // height < 0 => vertical flip
0858             QTransform m(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F);
0859             mPainter.setWorldTransform(m, true);
0860         }
0861         bmpSrc = bmpSrc.copy(parm[6], parm[5], parm[4], parm[3]);
0862         // TODO: scale the bitmap ( QImage::scale(parm[ 8 ], parm[ 7 ]) is actually too slow )
0863 
0864         mPainter.drawImage(parm[10], parm[9], bmpSrc);
0865         mPainter.restore();
0866     }
0867 }
0868 
0869 //-----------------------------------------------------------------------------
0870 void QWinMetaFile::dibCreatePatternBrush(long num, short *parm)
0871 {
0872     auto handle = new WinObjPatternBrushHandle;
0873     addHandle(handle);
0874     QImage bmpSrc;
0875 
0876     if (dibToBmp(bmpSrc, (char *)&parm[2], (num - 2) * 2)) {
0877         handle->image = bmpSrc;
0878         handle->brush.setTextureImage(handle->image);
0879     }
0880 }
0881 
0882 //-----------------------------------------------------------------------------
0883 // Object handle
0884 //-----------------------------------------------------------------------------
0885 void QWinMetaFile::selectObject(long, short *parm)
0886 {
0887     int idx = parm[0];
0888     if (idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[idx]) {
0889         mObjHandleTab[idx]->apply(mPainter);
0890     }
0891 }
0892 
0893 //-----------------------------------------------------------------------------
0894 void QWinMetaFile::deleteObject(long, short *parm)
0895 {
0896     deleteHandle(parm[0]);
0897 }
0898 
0899 //-----------------------------------------------------------------------------
0900 void QWinMetaFile::createEmptyObject(long, short *)
0901 {
0902     // allocation of an empty object (to keep object counting in sync)
0903     auto handle = new WinObjPenHandle;
0904     addHandle(handle);
0905     qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile: unimplemented createObject";
0906 }
0907 
0908 //-----------------------------------------------------------------------------
0909 void QWinMetaFile::createBrushIndirect(long, short *parm)
0910 {
0911     static Qt::BrushStyle hatchedStyleTab[] = {Qt::HorPattern, Qt::FDiagPattern, Qt::BDiagPattern, Qt::CrossPattern, Qt::DiagCrossPattern};
0912     static Qt::BrushStyle styleTab[] = {
0913         Qt::SolidPattern,
0914         Qt::NoBrush,
0915         Qt::FDiagPattern, /* hatched */
0916         Qt::Dense4Pattern, /* should be custom bitmap pattern */
0917         Qt::HorPattern, /* should be BS_INDEXED (?) */
0918         Qt::VerPattern, /* should be device-independent bitmap */
0919         Qt::Dense6Pattern, /* should be device-independent packed-bitmap */
0920         Qt::Dense2Pattern, /* should be BS_PATTERN8x8 */
0921         Qt::Dense3Pattern /* should be device-independent BS_DIBPATTERN8x8 */
0922     };
0923     Qt::BrushStyle style;
0924     short arg;
0925     auto handle = new WinObjBrushHandle;
0926     addHandle(handle);
0927 
0928     arg = parm[0];
0929     if (arg == 2) {
0930         arg = parm[3];
0931         if (arg >= 0 && arg < 5) {
0932             style = hatchedStyleTab[arg];
0933         } else {
0934             qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::createBrushIndirect: invalid hatched brush" << arg;
0935             style = Qt::SolidPattern;
0936         }
0937     } else if (arg >= 0 && arg < 9) {
0938         style = styleTab[arg];
0939     } else {
0940         qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::createBrushIndirect: invalid brush" << arg;
0941         style = Qt::SolidPattern;
0942     }
0943     handle->brush.setStyle(style);
0944     handle->brush.setColor(color(parm + 1));
0945 }
0946 
0947 //-----------------------------------------------------------------------------
0948 void QWinMetaFile::createPenIndirect(long, short *parm)
0949 {
0950     static Qt::PenStyle styleTab[] = {Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine, Qt::NoPen, Qt::SolidLine};
0951     Qt::PenStyle style;
0952     auto handle = new WinObjPenHandle;
0953     addHandle(handle);
0954 
0955     if (parm[0] >= 0 && parm[0] < 6) {
0956         style = styleTab[parm[0]];
0957     } else {
0958         qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::createPenIndirect: invalid pen" << parm[0];
0959         style = Qt::SolidLine;
0960     }
0961 
0962     handle->pen.setStyle(style);
0963     handle->pen.setColor(color(parm + 3));
0964     handle->pen.setCapStyle(Qt::RoundCap);
0965 
0966     // int width = 0;
0967     // TODO : width of pen proportional to device context width
0968     // DOESN'T WORK
0969     /*
0970         QRect devRec;
0971         devRec = mPainter.transformed( mBBox );
0972         width = ( parm[ 0 ] * devRec.width() ) / mBBox.width() ;
0973         qCDebug(KTNEFAPPS_LOG) <<"CreatePenIndirect:";
0974         qCDebug(KTNEFAPPS_LOG) <<"   log coord. :" << mBBox.width() <<"" << mBBox.height();
0975         qCDebug(KTNEFAPPS_LOG) <<"   log. pen :" << parm[ 1 ] <<"" << parm[ 2 ];
0976         qCDebug(KTNEFAPPS_LOG) <<"   dev. pen :" << width;
0977         handle->pen.setWidth( width );
0978     */
0979 }
0980 
0981 //-----------------------------------------------------------------------------
0982 void QWinMetaFile::createFontIndirect(long, short *parm)
0983 {
0984     auto handle = new WinObjFontHandle;
0985     addHandle(handle);
0986 
0987     QString family(QLatin1StringView((const char *)&parm[9]));
0988 
0989     mRotation = -parm[2] / 10; // text rotation (in 1/10 degree)
0990     // TODO: memorisation of rotation in object Font
0991     handle->font.setFamily(family);
0992     handle->font.setFixedPitch(((parm[8] & 0x01) == 0));
0993     // TODO: investigation why some test case need -2. (size of font in logical point)
0994     handle->font.setPointSize(qAbs(parm[0]) - 2);
0995     handle->font.setWeight(static_cast<QFont::Weight>((parm[4] >> 3)));
0996     handle->font.setItalic((parm[5] & 0x01));
0997     handle->font.setUnderline((parm[5] & 0x100));
0998 }
0999 
1000 //-----------------------------------------------------------------------------
1001 // Misc
1002 //-----------------------------------------------------------------------------
1003 void QWinMetaFile::noop(long, short *)
1004 {
1005 }
1006 
1007 void QWinMetaFile::end(long, short *)
1008 {
1009     // end of file :
1010     //    qCDebug(KTNEFAPPS_LOG) <<"END bbox=(" << mBBox.left() <<";" << mBBox.top() <<";" << mBBox.width() <<";" << mBBox.height() <<")";
1011 }
1012 
1013 //-----------------------------------------------------------------------------
1014 unsigned short QWinMetaFile::calcCheckSum(WmfPlaceableHeader *apmfh)
1015 {
1016     WORD *lpWord;
1017     WORD wResult;
1018     WORD i;
1019 
1020     // Start with the first word
1021     wResult = *(lpWord = (WORD *)(apmfh));
1022     // XOR in each of the other 9 words
1023     for (i = 1; i <= 9; ++i) {
1024         wResult ^= lpWord[i];
1025     }
1026     return wResult;
1027 }
1028 
1029 //-----------------------------------------------------------------------------
1030 int QWinMetaFile::findFunc(unsigned short aFunc) const
1031 {
1032     int i;
1033 
1034     for (i = 0; metaFuncTab[i].name; ++i) {
1035         if (metaFuncTab[i].func == aFunc) {
1036             return i;
1037         }
1038     }
1039 
1040     // here : unknown function
1041     return i;
1042 }
1043 
1044 //-----------------------------------------------------------------------------
1045 QPolygon *QWinMetaFile::pointArray(short num, short *parm)
1046 {
1047     int i;
1048 
1049     mPoints.resize(num);
1050 
1051     for (i = 0; i < num; ++i, parm += 2) {
1052         mPoints.setPoint(i, parm[0], parm[1]);
1053     }
1054 
1055     return &mPoints;
1056 }
1057 
1058 //-----------------------------------------------------------------------------
1059 unsigned int QWinMetaFile::toDWord(short *parm)
1060 {
1061     unsigned int l;
1062 
1063 #if !defined(WORDS_BIGENDIAN)
1064     l = *(unsigned int *)(parm);
1065 #else
1066     char *bytes;
1067     char swap[4];
1068     bytes = (char *)parm;
1069     swap[0] = bytes[2];
1070     swap[1] = bytes[3];
1071     swap[2] = bytes[0];
1072     swap[3] = bytes[1];
1073     l = *(unsigned int *)(swap);
1074 #endif
1075 
1076     return l;
1077 }
1078 
1079 //-----------------------------------------------------------------------------
1080 QColor QWinMetaFile::color(short *parm)
1081 {
1082     unsigned int colorRef;
1083     int red;
1084     int green;
1085     int blue;
1086 
1087     colorRef = toDWord(parm) & 0xffffff;
1088     red = colorRef & 255;
1089     green = (colorRef >> 8) & 255;
1090     blue = (colorRef >> 16) & 255;
1091 
1092     return {red, green, blue};
1093 }
1094 
1095 //-----------------------------------------------------------------------------
1096 void QWinMetaFile::xyToAngle(int xStart, int yStart, int xEnd, int yEnd, int &angleStart, int &angleLength)
1097 {
1098     float aStart;
1099     float aLength;
1100 
1101     aStart = atan2((double)yStart, (double)xStart);
1102     aLength = atan2((double)yEnd, (double)xEnd) - aStart;
1103 
1104     angleStart = (int)(aStart * 2880 / 3.14166);
1105     angleLength = (int)(aLength * 2880 / 3.14166);
1106     if (angleLength < 0) {
1107         angleLength = 5760 + angleLength;
1108     }
1109 }
1110 
1111 //-----------------------------------------------------------------------------
1112 void QWinMetaFile::addHandle(WinObjHandle *handle)
1113 {
1114     int idx;
1115 
1116     for (idx = 0; idx < MAX_OBJHANDLE; idx++) {
1117         if (mObjHandleTab[idx] == nullptr) {
1118             break;
1119         }
1120     }
1121 
1122     if (idx < MAX_OBJHANDLE) {
1123         mObjHandleTab[idx] = handle;
1124     } else {
1125         qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile error: handle table full !";
1126     }
1127 }
1128 
1129 //-----------------------------------------------------------------------------
1130 void QWinMetaFile::deleteHandle(int idx)
1131 {
1132     if (idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[idx]) {
1133         delete mObjHandleTab[idx];
1134         mObjHandleTab[idx] = nullptr;
1135     }
1136 }
1137 
1138 //-----------------------------------------------------------------------------
1139 QPainter::CompositionMode QWinMetaFile::winToQtComposition(short parm) const
1140 {
1141     static const QPainter::CompositionMode opTab[] = {
1142         // ### untested (conversion from Qt::RasterOp)
1143         QPainter::CompositionMode_Source, // Qt::CopyROP
1144         QPainter::CompositionMode_Clear, // Qt::ClearROP
1145         QPainter::CompositionMode_SourceOut, // Qt::NandROP
1146         QPainter::CompositionMode_SourceOut, // Qt::NotAndROP
1147         QPainter::CompositionMode_DestinationOut, // Qt::NotCopyROP
1148         QPainter::CompositionMode_DestinationOut, // Qt::AndNotROP
1149         QPainter::CompositionMode_DestinationOut, // Qt::NotROP
1150         QPainter::CompositionMode_Xor, // Qt::XorROP
1151         QPainter::CompositionMode_Source, // Qt::NorROP
1152         QPainter::CompositionMode_SourceIn, // Qt::AndROP
1153         QPainter::CompositionMode_SourceIn, // Qt::NotXorROP
1154         QPainter::CompositionMode_Destination, // Qt::NopROP
1155         QPainter::CompositionMode_Destination, // Qt::NotOrROP
1156         QPainter::CompositionMode_Source, // Qt::CopyROP
1157         QPainter::CompositionMode_Source, // Qt::OrNotROP
1158         QPainter::CompositionMode_SourceOver, // Qt::OrROP
1159         QPainter::CompositionMode_Source // Qt::SetROP
1160     };
1161 
1162     if (parm > 0 && parm <= 16) {
1163         return opTab[parm];
1164     } else {
1165         return QPainter::CompositionMode_Source;
1166     }
1167 }
1168 
1169 //-----------------------------------------------------------------------------
1170 QPainter::CompositionMode QWinMetaFile::winToQtComposition(long parm) const
1171 {
1172     /* TODO: Ternary raster operations
1173     0x00C000CA  dest = (source AND pattern)
1174     0x00F00021  dest = pattern
1175     0x00FB0A09  dest = DPSnoo
1176     0x005A0049  dest = pattern XOR dest   */
1177     static const struct OpTab {
1178         long winRasterOp;
1179         QPainter::CompositionMode qtRasterOp;
1180     } opTab[] = {
1181         // ### untested (conversion from Qt::RasterOp)
1182         {0x00CC0020, QPainter::CompositionMode_Source}, // CopyROP
1183         {0x00EE0086, QPainter::CompositionMode_SourceOver}, // OrROP
1184         {0x008800C6, QPainter::CompositionMode_SourceIn}, // AndROP
1185         {0x00660046, QPainter::CompositionMode_Xor}, // XorROP
1186         {0x00440328, QPainter::CompositionMode_DestinationOut}, // AndNotROP
1187         {0x00330008, QPainter::CompositionMode_DestinationOut}, // NotCopyROP
1188         {0x001100A6, QPainter::CompositionMode_SourceOut}, // NandROP
1189         {0x00C000CA, QPainter::CompositionMode_Source}, // CopyROP
1190         {0x00BB0226, QPainter::CompositionMode_Destination}, // NotOrROP
1191         {0x00F00021, QPainter::CompositionMode_Source}, // CopyROP
1192         {0x00FB0A09, QPainter::CompositionMode_Source}, // CopyROP
1193         {0x005A0049, QPainter::CompositionMode_Source}, // CopyROP
1194         {0x00550009, QPainter::CompositionMode_DestinationOut}, // NotROP
1195         {0x00000042, QPainter::CompositionMode_Clear}, // ClearROP
1196         {0x00FF0062, QPainter::CompositionMode_Source} // SetROP
1197     };
1198 
1199     int i;
1200     for (i = 0; i < 15; ++i) {
1201         if (opTab[i].winRasterOp == parm) {
1202             break;
1203         }
1204     }
1205 
1206     if (i < 15) {
1207         return opTab[i].qtRasterOp;
1208     } else {
1209         return QPainter::CompositionMode_Source;
1210     }
1211 }
1212 
1213 //-----------------------------------------------------------------------------
1214 bool QWinMetaFile::dibToBmp(QImage &bmp, const char *dib, long size)
1215 {
1216     using BMPFILEHEADER = struct _BMPFILEHEADER {
1217         WORD bmType;
1218         DWORD bmSize;
1219         WORD bmReserved1;
1220         WORD bmReserved2;
1221         DWORD bmOffBits;
1222     };
1223 
1224     int sizeBmp = size + 14;
1225     QByteArray pattern; // BMP header and DIB data
1226     pattern.fill(0, sizeBmp); // resize and fill
1227     pattern.insert(14, QByteArray::fromRawData(dib, size));
1228 
1229     // add BMP header
1230     BMPFILEHEADER *bmpHeader;
1231     bmpHeader = (BMPFILEHEADER *)(pattern.constData());
1232     bmpHeader->bmType = 0x4D42;
1233     bmpHeader->bmSize = sizeBmp;
1234 
1235     if (!bmp.loadFromData((const uchar *)bmpHeader, pattern.size(), "BMP")) {
1236         qCDebug(KTNEFAPPS_LOG) << "QWinMetaFile::dibToBmp: invalid bitmap";
1237         return false;
1238     } else {
1239         //        if ( bmp.save("/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP") )
1240         //        if ( bmp.load( "/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP" ) )
1241         //            fprintf(stderr, "Bitmap ok \n");
1242         return true;
1243     }
1244 }