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(©Parm[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 }