Warning, file /office/calligra/filters/karbon/wmf/WmfImportParser.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2003 thierry lorthiois <lorthioist@wanadoo.fr> 0003 * SPDX-FileCopyrightText: 2007-2011 Jan Hambrecht <jaham@gmx.net> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "WmfImportParser.h" 0009 0010 #include "WmfImportDebug.h" 0011 0012 #include <WmfEnums.h> 0013 #include <WmfDeviceContext.h> 0014 0015 #include <KoXmlWriter.h> 0016 #include <KoUnit.h> 0017 0018 #include <QBuffer> 0019 0020 #include <math.h> 0021 0022 /* 0023 bug : see motar.wmf 0024 */ 0025 0026 #define DEG2RAD(angle) angle * M_PI / 180.0 0027 #define RAD2DEG(angle) angle / M_PI * 180.0 0028 0029 WMFImportParser::WMFImportParser(KoXmlWriter &svgWriter) 0030 : WmfAbstractBackend(), m_svgWriter(svgWriter) 0031 { 0032 } 0033 0034 WMFImportParser::~WMFImportParser() 0035 { 0036 } 0037 0038 //----------------------------------------------------------------------------- 0039 // Virtual Painter 0040 0041 bool WMFImportParser::begin(const QRect &boundingBox) 0042 { 0043 m_scaleX = m_scaleY = 1; 0044 0045 m_pageSize = boundingBox.size(); 0046 0047 if (!isStandard()) { 0048 // Placeable Wmf store the boundingRect() in pixel and the default DPI 0049 m_pageSize.rwidth() = INCH_TO_POINT((double)boundingBox.width() / defaultDpi()); 0050 m_pageSize.rheight() = INCH_TO_POINT((double)boundingBox.height() / defaultDpi()); 0051 } 0052 if ((boundingBox.width() != 0) && (boundingBox.height() != 0)) { 0053 m_scaleX = m_pageSize.width() / (double)boundingBox.width(); 0054 m_scaleY = m_pageSize.height() / (double)boundingBox.height(); 0055 } 0056 0057 // standard header: 0058 m_svgWriter.addCompleteElement("<?xml version=\"1.0\" standalone=\"no\"?>\n"); 0059 m_svgWriter.addCompleteElement("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" " \ 0060 "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"); 0061 0062 // add some PR. one line is more than enough. 0063 m_svgWriter.addCompleteElement("<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon -->\n"); 0064 m_svgWriter.startElement("svg"); 0065 m_svgWriter.addAttribute("xmlns", "http://www.w3.org/2000/svg"); 0066 m_svgWriter.addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); 0067 m_svgWriter.addAttribute("width", m_pageSize.width()); 0068 m_svgWriter.addAttribute("height", m_pageSize.height()); 0069 0070 debugWmf << "bounding rect =" << boundingBox; 0071 debugWmf << "page size =" << m_pageSize; 0072 debugWmf << "scale x =" << m_scaleX; 0073 debugWmf << "scale y =" << m_scaleY; 0074 0075 m_window.org = boundingBox.topLeft(); 0076 //m_viewport.org = boundingBox.topLeft(); 0077 m_window.ext = boundingBox.size(); 0078 m_window.extIsValid = true; 0079 m_viewport.ext = m_pageSize; 0080 m_viewport.extIsValid = true; 0081 0082 updateTransform(); 0083 0084 return true; 0085 } 0086 0087 bool WMFImportParser::end() 0088 { 0089 m_svgWriter.endElement(); // svg 0090 return true; 0091 } 0092 0093 void WMFImportParser::save() 0094 { 0095 } 0096 0097 void WMFImportParser::restore() 0098 { 0099 } 0100 0101 void WMFImportParser::setWindowOrg(int left, int top) 0102 { 0103 debugWmf << left << top; 0104 if (QPoint(left, top) != m_window.org) { 0105 m_window.org.setX(left); 0106 m_window.org.setY(top); 0107 updateTransform(); 0108 } 0109 } 0110 0111 void WMFImportParser::setWindowExt(int width, int height) 0112 { 0113 debugWmf << width << height; 0114 // the wmf file can change width/height during the drawing 0115 if (QSize(width, height) != m_window.ext) { 0116 m_window.ext = QSizeF(width, height); 0117 m_window.extIsValid = true; 0118 updateTransform(); 0119 } 0120 } 0121 0122 void WMFImportParser::setViewportOrg(int left, int top) 0123 { 0124 debugWmf << left << top; 0125 if (QPoint(left, top) != m_viewport.org) { 0126 m_viewport.org.setX(left); 0127 m_viewport.org.setY(top); 0128 updateTransform(); 0129 } 0130 } 0131 0132 void WMFImportParser::setViewportExt(int width, int height) 0133 { 0134 debugWmf << width << height; 0135 if ((width != 0) && (height != 0)) { 0136 m_viewport.ext = QSizeF(width, height); 0137 m_viewport.extIsValid = true; 0138 updateTransform(); 0139 } 0140 } 0141 0142 void WMFImportParser::setMatrix(Libwmf::WmfDeviceContext &/*context*/, const QMatrix &matrix, 0143 bool combine) 0144 { 0145 if (combine) 0146 m_matrix = matrix * m_matrix; 0147 else 0148 m_matrix = matrix; 0149 0150 debugWmf << "matrix =" << matrix; 0151 debugWmf << "combine =" << combine; 0152 } 0153 0154 void WMFImportParser::setPixel(Libwmf::WmfDeviceContext &context, int x, int y, const QColor &color) 0155 { 0156 Q_UNUSED(context); 0157 Q_UNUSED(x); 0158 Q_UNUSED(y); 0159 Q_UNUSED(color); 0160 0161 // Not Yet Implemented 0162 } 0163 0164 void WMFImportParser::lineTo(Libwmf::WmfDeviceContext &context, int left, int top) 0165 { 0166 const QString strokeStyle = saveStroke(context); 0167 0168 static int lineIndex = 0; 0169 0170 const QPointF p1 = coord(context.currentPosition); 0171 const QPointF p2 = coord(QPoint(left, top)); 0172 0173 m_svgWriter.startElement("line"); 0174 m_svgWriter.addAttribute("id", QString("line%1").arg(++lineIndex)); 0175 m_svgWriter.addAttribute("x1", p1.x()); 0176 m_svgWriter.addAttribute("y1", p1.y()); 0177 m_svgWriter.addAttribute("x2", p2.x()); 0178 m_svgWriter.addAttribute("y2", p2.y()); 0179 m_svgWriter.addAttribute("style", strokeStyle+"fill:none"); 0180 m_svgWriter.endElement(); // line 0181 0182 context.currentPosition = QPoint(left, top); 0183 } 0184 0185 void WMFImportParser::drawRect(Libwmf::WmfDeviceContext &context, int left, int top, int width, int height) 0186 { 0187 QRectF bound = boundBox(left, top, width, height); 0188 0189 const QString fillStyle = saveFill(context); 0190 const QString strokeStyle = saveStroke(context); 0191 0192 static int rectIndex = 0; 0193 0194 m_svgWriter.startElement("rect"); 0195 m_svgWriter.addAttribute("id", QString("rect%1").arg(++rectIndex)); 0196 m_svgWriter.addAttribute("x", bound.x()); 0197 m_svgWriter.addAttribute("y", bound.y()); 0198 m_svgWriter.addAttribute("width", bound.width()); 0199 m_svgWriter.addAttribute("height", bound.height()); 0200 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0201 m_svgWriter.endElement(); // rect 0202 } 0203 0204 void WMFImportParser::drawRoundRect(Libwmf::WmfDeviceContext &context, int left, int top, int width, int height, int roundw, int roundh) 0205 { 0206 QRectF bound = boundBox(left, top, width, height); 0207 // roundw and roundh are in percent of width and height 0208 const qreal rx = qAbs(roundw)/100. * bound.width(); 0209 const qreal ry = qAbs(roundh)/100. * bound.height(); 0210 0211 const QString fillStyle = saveFill(context); 0212 const QString strokeStyle = saveStroke(context); 0213 0214 static int roundRectIndex = 0; 0215 0216 m_svgWriter.startElement("rect"); 0217 m_svgWriter.addAttribute("id", QString("roundRect%1").arg(++roundRectIndex)); 0218 m_svgWriter.addAttribute("x", bound.x()); 0219 m_svgWriter.addAttribute("y", bound.y()); 0220 m_svgWriter.addAttribute("width", bound.width()); 0221 m_svgWriter.addAttribute("height", bound.height()); 0222 m_svgWriter.addAttribute("rx", 0.5*rx); 0223 m_svgWriter.addAttribute("ry", 0.5*ry); 0224 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0225 m_svgWriter.endElement(); // rect 0226 } 0227 0228 void WMFImportParser::drawEllipse(Libwmf::WmfDeviceContext &context, int left, int top, int width, int height) 0229 { 0230 QRectF bound = boundBox(left, top, width, height); 0231 0232 const QString fillStyle = saveFill(context); 0233 const QString strokeStyle = saveStroke(context); 0234 0235 static int ellipseIndex = 0; 0236 0237 m_svgWriter.startElement("ellipse"); 0238 m_svgWriter.addAttribute("id", QString("ellipse%1").arg(++ellipseIndex)); 0239 m_svgWriter.addAttribute("cx", bound.center().x()); 0240 m_svgWriter.addAttribute("cy", bound.center().y()); 0241 m_svgWriter.addAttribute("rx", 0.5*bound.width()); 0242 m_svgWriter.addAttribute("ry", 0.5*bound.height()); 0243 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0244 m_svgWriter.endElement(); // ellipse 0245 } 0246 0247 void WMFImportParser::drawArc(Libwmf::WmfDeviceContext &context, int x, int y, int w, int h, int aStart, int aLen) 0248 { 0249 const qreal a1 = DEG2RAD((aStart * 180) / 2880.0); 0250 const qreal a2 = DEG2RAD((aLen * 180) / 2880.0); 0251 const int largeArc = a2 > M_PI ? 1 : 0; 0252 0253 QRectF bound = boundBox(x, y, w, h); 0254 0255 const qreal rx = 0.5*bound.width(); 0256 const qreal ry = 0.5*bound.height(); 0257 const QPointF p1 = bound.center() + QPointF(rx*cos(a1), -ry*sin(a1)); 0258 const QPointF p2 = bound.center() + QPointF(rx*cos(a1+a2), -ry*sin(a1+a2)); 0259 0260 QString path = 0261 QString("M%1,%2 ").arg(p1.x()).arg(p1.y()) + 0262 QString("A%1,%2 0 %5 0 %3,%4").arg(rx).arg(ry).arg(p2.x()).arg(p2.y()).arg(largeArc); 0263 0264 const QString strokeStyle = saveStroke(context); 0265 0266 static int arcIndex = 0; 0267 0268 m_svgWriter.startElement("path"); 0269 m_svgWriter.addAttribute("id", QString("arc%1").arg(++arcIndex)); 0270 m_svgWriter.addAttribute("d", path); 0271 m_svgWriter.addAttribute("style", strokeStyle+"fill:none"); 0272 m_svgWriter.endElement(); // path 0273 } 0274 0275 void WMFImportParser::drawPie(Libwmf::WmfDeviceContext &context, int x, int y, int w, int h, int aStart, int aLen) 0276 { 0277 const qreal a1 = DEG2RAD((aStart * 180) / 2880.0); 0278 const qreal a2 = DEG2RAD((aLen * 180) / 2880.0); 0279 const int largeArc = a2 > M_PI ? 1 : 0; 0280 0281 QRectF bound = boundBox(x, y, w, h); 0282 0283 const qreal rx = 0.5*bound.width(); 0284 const qreal ry = 0.5*bound.height(); 0285 const QPointF p1 = bound.center() + QPointF(rx*cos(a1), -ry*sin(a1)); 0286 const QPointF p2 = bound.center() + QPointF(rx*cos(a1+a2), -ry*sin(a1+a2)); 0287 0288 QString path = 0289 QString("M%1,%2 ").arg(bound.center().x()).arg(bound.center().y()) + 0290 QString("L%1,%2 ").arg(p1.x()).arg(p1.y()) + 0291 QString("A%1,%2 0 %5 0 %3,%4 ").arg(rx).arg(ry).arg(p2.x()).arg(p2.y()).arg(largeArc) + 0292 QString("L%1,%2").arg(bound.center().x()).arg(bound.center().y()); 0293 0294 const QString fillStyle = saveFill(context); 0295 const QString strokeStyle = saveStroke(context); 0296 0297 static int pieIndex = 0; 0298 0299 m_svgWriter.startElement("path"); 0300 m_svgWriter.addAttribute("id", QString("pie%1").arg(++pieIndex)); 0301 m_svgWriter.addAttribute("d", path); 0302 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0303 m_svgWriter.endElement(); // path 0304 } 0305 0306 void WMFImportParser::drawChord(Libwmf::WmfDeviceContext &context, int x, int y, int w, int h, int aStart, int aLen) 0307 { 0308 const qreal a1 = DEG2RAD((aStart * 180) / 2880.0); 0309 const qreal a2 = DEG2RAD((aLen * 180) / 2880.0); 0310 const int largeArc = a2 > M_PI ? 1 : 0; 0311 0312 QRectF bound = boundBox(x, y, w, h); 0313 0314 const qreal rx = 0.5*bound.width(); 0315 const qreal ry = 0.5*bound.height(); 0316 const QPointF p1 = bound.center() + QPointF(rx*cos(a1), -ry*sin(a1)); 0317 const QPointF p2 = bound.center() + QPointF(rx*cos(a1+a2), -ry*sin(a1+a2)); 0318 0319 QString path = 0320 QString("M%1,%2 ").arg(p1.x()).arg(p1.y()) + 0321 QString("A%1,%2 0 %5 0 %3,%4 ").arg(rx).arg(ry).arg(p2.x()).arg(p2.y()).arg(largeArc) + 0322 QString("L%1,%2").arg(p1.x()).arg(p1.y()); 0323 0324 const QString fillStyle = saveFill(context); 0325 const QString strokeStyle = saveStroke(context); 0326 0327 static int chordKIndex = 0; 0328 0329 m_svgWriter.startElement("path"); 0330 m_svgWriter.addAttribute("id", QString("chord%1").arg(++chordKIndex)); 0331 m_svgWriter.addAttribute("d", path); 0332 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0333 m_svgWriter.endElement(); // path 0334 } 0335 0336 void WMFImportParser::drawPolyline(Libwmf::WmfDeviceContext &context, const QPolygon &pa) 0337 { 0338 QString points; 0339 const int pointCount = pa.size(); 0340 if (pointCount <= 1) 0341 return; 0342 0343 QPointF p; 0344 // There exists a problem on msvc with for(each) and QVector<QPoint> 0345 for (int i = 0; i < pa.count(); ++i) { 0346 const QPoint &point(pa[i]); 0347 p = coord(point); 0348 points += QString("%1,%2 ").arg(p.x()).arg(p.y()); 0349 } 0350 0351 const QString strokeStyle = saveStroke(context); 0352 0353 static int polylineIndex = 0; 0354 0355 m_svgWriter.startElement("polyline"); 0356 m_svgWriter.addAttribute("id", QString("polyline%1").arg(++polylineIndex)); 0357 m_svgWriter.addAttribute("points", points); 0358 m_svgWriter.addAttribute("style", strokeStyle+"fill:none"); 0359 m_svgWriter.endElement(); // polyline 0360 } 0361 0362 void WMFImportParser::drawPolygon(Libwmf::WmfDeviceContext &context, const QPolygon &pa) 0363 { 0364 QString points; 0365 const int pointCount = pa.size(); 0366 if (pointCount <= 1) 0367 return; 0368 0369 QPointF p; 0370 // There exists a problem on msvc with for(each) and QVector<QPoint> 0371 for (int i = 0; i < pa.count(); ++i) { 0372 const QPoint &point(pa[i]); 0373 p = coord(point); 0374 points += QString("%1,%2 ").arg(p.x()).arg(p.y()); 0375 } 0376 0377 const QString fillStyle = saveFill(context); 0378 const QString strokeStyle = saveStroke(context); 0379 0380 static int polygonIndex = 0; 0381 0382 m_svgWriter.startElement("polygon"); 0383 m_svgWriter.addAttribute("id", QString("polygon%1").arg(++polygonIndex)); 0384 m_svgWriter.addAttribute("points", points); 0385 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0386 m_svgWriter.endElement(); // polygon 0387 } 0388 0389 void WMFImportParser::drawPolyPolygon(Libwmf::WmfDeviceContext &context, QList<QPolygon>& listPa) 0390 { 0391 if (listPa.isEmpty()) 0392 return; 0393 0394 QString path; 0395 QPointF p; 0396 foreach(const QPolygon &poly, listPa) { 0397 int pointCount = poly.size(); 0398 if(pointCount <= 1) 0399 continue; 0400 p = coord(poly[0]); 0401 path += QString("M%1,%2 L").arg(p.x()).arg(p.y()); 0402 for(int i = 1; i < pointCount; ++i) { 0403 p = coord(poly[i]); 0404 path += QString("%1,%2 ").arg(p.x()).arg(p.y()); 0405 } 0406 path.append("Z "); 0407 } 0408 0409 const QString fillStyle = saveFill(context); 0410 const QString strokeStyle = saveStroke(context); 0411 0412 static int polyPolygonIndex = 0; 0413 0414 m_svgWriter.startElement("path"); 0415 m_svgWriter.addAttribute("id", QString("polyPolygon%1").arg(++polyPolygonIndex)); 0416 m_svgWriter.addAttribute("d", path); 0417 m_svgWriter.addAttribute("style", strokeStyle+fillStyle); 0418 m_svgWriter.endElement(); // path 0419 } 0420 0421 void WMFImportParser::drawImage(Libwmf::WmfDeviceContext &/*context*/, int x, int y, const QImage &rawImage, int sx, int sy, int sw, int sh) 0422 { 0423 QPoint imgOrg(qMax(sx, 0), qMax(sy, 0)); 0424 QSize imgExt = QSize(rawImage.width()-imgOrg.x(), rawImage.height()-imgOrg.y()); 0425 if (sw > 0) { 0426 imgExt.rwidth() = qMin(imgExt.width(), sw); 0427 } 0428 if (sh > 0) { 0429 imgExt.rheight() = qMin(imgExt.height(), sh); 0430 } 0431 QImage image = rawImage.copy(QRect(imgOrg, imgExt)); 0432 0433 QByteArray ba; 0434 QBuffer buffer(&ba); 0435 if(!buffer.open(QIODevice::WriteOnly)) 0436 return; 0437 if (!image.save(&buffer, "PNG")) 0438 return; 0439 0440 static int imageIndex = 0; 0441 0442 const QPointF pos = coord(QPoint(x, y)); 0443 const QSizeF s = size(image.size()); 0444 0445 m_svgWriter.startElement("image"); 0446 m_svgWriter.addAttribute("id", QString("image%1").arg(++imageIndex)); 0447 m_svgWriter.addAttribute("x", pos.x()); 0448 m_svgWriter.addAttribute("y", pos.y()); 0449 m_svgWriter.addAttribute("width", s.width()); 0450 m_svgWriter.addAttribute("height", s.height()); 0451 m_svgWriter.addAttribute("xlink:href", "data:image/png;base64," + ba.toBase64()); 0452 m_svgWriter.endElement(); // image 0453 } 0454 0455 void WMFImportParser::patBlt(Libwmf::WmfDeviceContext &/*context*/, int x, int y, int width, int height, quint32 rasterOperation) 0456 { 0457 // Not Yet Implemented 0458 Q_UNUSED(x); 0459 Q_UNUSED(y); 0460 Q_UNUSED(width); 0461 Q_UNUSED(height); 0462 Q_UNUSED(rasterOperation); 0463 } 0464 0465 void WMFImportParser::drawText(Libwmf::WmfDeviceContext &context, int x, int y, const QString& text) 0466 { 0467 if (context.textAlign & TA_UPDATECP) { 0468 // (left, top) position = current logical position 0469 x = context.currentPosition.x(); 0470 y = context.currentPosition.y(); 0471 } 0472 0473 QFontMetrics metrics(context.font); 0474 0475 if (context.textAlign & TA_BOTTOM) { 0476 y -= metrics.descent(); 0477 } else if(context.textAlign & TA_BASELINE) { 0478 // nothing to do here 0479 } else { // TA_TOP 0480 // this the is the default 0481 y += metrics.ascent(); 0482 } 0483 0484 static int textIndex = 0; 0485 0486 const QPointF pos = coord(QPoint(x, y)); 0487 0488 m_svgWriter.startElement("text"); 0489 m_svgWriter.addAttribute("id", QString("text%1").arg(++textIndex)); 0490 m_svgWriter.addAttribute("x", pos.x()); 0491 m_svgWriter.addAttribute("y", pos.y()); 0492 if (context.textAlign & TA_CENTER) 0493 m_svgWriter.addAttribute("text-anchor", "middle"); 0494 else if (context.textAlign & TA_RIGHT) 0495 m_svgWriter.addAttribute("text-anchor", "end"); 0496 m_svgWriter.addAttribute("font-family", context.font.family()); 0497 // adjust font size 0498 m_svgWriter.addAttributePt("font-size", size(QSize(0, context.font.pointSize())).height()); 0499 if (context.font.bold()) 0500 m_svgWriter.addAttribute("font-weight", "bold"); 0501 if (context.font.italic()) 0502 m_svgWriter.addAttribute("font-style", "italic"); 0503 if (context.font.underline()) 0504 m_svgWriter.addAttribute("text-decoration", "underline"); 0505 m_svgWriter.addAttribute("stroke", context.foregroundTextColor.name()); 0506 0507 if (context.escapement) { 0508 // we rotate around the anchor point 0509 // rotation is in 1/10th of a degree 0510 QString transform = 0511 QString("translate(%1,%2) ").arg(pos.x()).arg(pos.y()) + 0512 QString("rotate(%1) ").arg(qreal(context.escapement) / -10.0) + 0513 QString("translate(%1,%2)").arg(-pos.x()).arg(-pos.y()); 0514 m_svgWriter.addAttribute("transform", transform); 0515 } 0516 0517 m_svgWriter.addTextNode(text); 0518 0519 m_svgWriter.endElement(); // text 0520 } 0521 0522 //----------------------------------------------------------------------------- 0523 // Utilities 0524 0525 QString WMFImportParser::saveStroke(Libwmf::WmfDeviceContext &context) 0526 { 0527 if(context.pen.style() == Qt::NoPen) { 0528 return "stroke:none;"; 0529 } 0530 0531 const qreal width = context.pen.width() > qreal(1.0) ? qMax(qreal(1.0), context.pen.width() * m_scaleX) : qreal(1.0); 0532 0533 QString strokeStyle; 0534 0535 strokeStyle += QString("stroke:%1;").arg(context.pen.color().name()); 0536 strokeStyle += QString("stroke-width:%1;").arg(width); 0537 if (context.pen.capStyle() == Qt::FlatCap) 0538 strokeStyle += "stroke-linecap:butt;"; 0539 else if (context.pen.capStyle() == Qt::RoundCap) 0540 strokeStyle += "stroke-linecap:round;"; 0541 else if (context.pen.capStyle() == Qt::SquareCap) 0542 strokeStyle += "stroke-linecap:square;"; 0543 0544 if (context.pen.joinStyle() == Qt::MiterJoin) { 0545 strokeStyle += "stroke-linejoin:miter;"; 0546 strokeStyle += QString("stroke-miterlimit:%1;").arg(context.pen.miterLimit()); 0547 } else if (context.pen.joinStyle() == Qt::RoundJoin) 0548 strokeStyle += "stroke-linejoin:round;"; 0549 else if (context.pen.joinStyle() == Qt::BevelJoin) 0550 strokeStyle += "stroke-linejoin:bevel;"; 0551 0552 // dash 0553 if (context.pen.style() > Qt::SolidLine) { 0554 qreal dashFactor = width; 0555 0556 if (context.pen.dashOffset() != 0) 0557 strokeStyle += QString("stroke-dashoffset:%1;").arg(dashFactor * context.pen.dashOffset()); 0558 0559 QString dashStr; 0560 const QVector<qreal> dashes = context.pen.dashPattern(); 0561 int dashCount = dashes.size(); 0562 for (int i = 0; i < dashCount; ++i) { 0563 if (i > 0) 0564 dashStr += ","; 0565 dashStr += QString("%1").arg(dashes[i] * dashFactor); 0566 } 0567 strokeStyle += QString("stroke-dasharray:%1;").arg(dashStr); 0568 } 0569 0570 return strokeStyle; 0571 } 0572 0573 QString WMFImportParser::saveFill(Libwmf::WmfDeviceContext &context) 0574 { 0575 if (context.brush.style() == Qt::NoBrush) { 0576 return "fill:none;"; 0577 } 0578 0579 QString fillStyle; 0580 0581 if (context.brush.style() == Qt::SolidPattern) { 0582 fillStyle = QString("fill:%1;").arg(context.brush.color().name()); 0583 if (context.brush.color().alphaF() < 1.0) 0584 fillStyle += QString("fill-opacity:%1;").arg(context.brush.color().alphaF()); 0585 0586 return fillStyle; 0587 } 0588 0589 static int fillIndex = 0; 0590 QString fillId = QString("fill%1").arg(++fillIndex); 0591 0592 switch (context.brush.style()) { 0593 case Qt::TexturePattern: { 0594 QImage texture = context.brush.textureImage(); 0595 m_svgWriter.startElement("pattern"); 0596 m_svgWriter.addAttribute("id", fillId); 0597 m_svgWriter.addAttribute("x", 0); 0598 m_svgWriter.addAttribute("y", 0); 0599 m_svgWriter.addAttribute("width", texture.size().width()); 0600 m_svgWriter.addAttribute("height", texture.size().height()); 0601 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0602 0603 m_svgWriter.addAttribute("viewBox", QString("0 0 %1 %2").arg(texture.size().width()).arg(texture.size().height())); 0604 0605 m_svgWriter.startElement("image"); 0606 m_svgWriter.addAttribute("x", "0"); 0607 m_svgWriter.addAttribute("y", "0"); 0608 m_svgWriter.addAttribute("width", QString("%1px").arg(texture.size().width())); 0609 m_svgWriter.addAttribute("height", QString("%1px").arg(texture.size().height())); 0610 0611 QByteArray ba; 0612 QBuffer buffer(&ba); 0613 buffer.open(QIODevice::WriteOnly); 0614 if (texture.save(&buffer, "PNG")) { 0615 m_svgWriter.addAttribute("xlink:href", "data:image/png;base64," + ba.toBase64()); 0616 } 0617 0618 m_svgWriter.endElement(); // image 0619 m_svgWriter.endElement(); // pattern 0620 break; 0621 } 0622 case Qt::HorPattern: 0623 m_svgWriter.startElement("pattern"); 0624 m_svgWriter.addAttribute("id", fillId); 0625 m_svgWriter.addAttribute("x", 0); 0626 m_svgWriter.addAttribute("y", 0); 0627 m_svgWriter.addAttribute("width", 30); 0628 m_svgWriter.addAttribute("height", 30); 0629 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0630 m_svgWriter.startElement("path"); 0631 m_svgWriter.addAttribute("d", "M0,5 L30,5 M0,15 L30,15 M0,25 L30,25"); 0632 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0633 m_svgWriter.endElement(); // path 0634 m_svgWriter.endElement(); // pattern 0635 break; 0636 case Qt::VerPattern: 0637 m_svgWriter.startElement("pattern"); 0638 m_svgWriter.addAttribute("id", fillId); 0639 m_svgWriter.addAttribute("x", 0); 0640 m_svgWriter.addAttribute("y", 0); 0641 m_svgWriter.addAttribute("width", 30); 0642 m_svgWriter.addAttribute("height", 30); 0643 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0644 m_svgWriter.startElement("path"); 0645 m_svgWriter.addAttribute("d", "M5,0 L5,30 M15,0 L15,30 M25,0 L25,30"); 0646 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0647 m_svgWriter.endElement(); // path 0648 m_svgWriter.endElement(); // pattern 0649 break; 0650 case Qt::CrossPattern: 0651 m_svgWriter.startElement("pattern"); 0652 m_svgWriter.addAttribute("id", fillId); 0653 m_svgWriter.addAttribute("x", 0); 0654 m_svgWriter.addAttribute("y", 0); 0655 m_svgWriter.addAttribute("width", 30); 0656 m_svgWriter.addAttribute("height", 30); 0657 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0658 m_svgWriter.startElement("path"); 0659 m_svgWriter.addAttribute("d", "M5,0 L5,30 M15,0 L15,30 M25,0 L25,30 M0,5 L30,5 M0,15 L30,15 M0,25 L30,25"); 0660 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0661 m_svgWriter.endElement(); // path 0662 m_svgWriter.endElement(); // pattern 0663 break; 0664 case Qt::BDiagPattern: 0665 m_svgWriter.startElement("pattern"); 0666 m_svgWriter.addAttribute("id", fillId); 0667 m_svgWriter.addAttribute("x", 0); 0668 m_svgWriter.addAttribute("y", 0); 0669 m_svgWriter.addAttribute("width", 30); 0670 m_svgWriter.addAttribute("height", 30); 0671 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0672 m_svgWriter.startElement("path"); 0673 m_svgWriter.addAttribute("d", "M0,30 L30,0 M0,15 L15,0 M15,30 L30,15"); 0674 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0675 m_svgWriter.endElement(); // path 0676 m_svgWriter.endElement(); // pattern 0677 break; 0678 case Qt::FDiagPattern: 0679 m_svgWriter.startElement("pattern"); 0680 m_svgWriter.addAttribute("id", fillId); 0681 m_svgWriter.addAttribute("x", 0); 0682 m_svgWriter.addAttribute("y", 0); 0683 m_svgWriter.addAttribute("width", 30); 0684 m_svgWriter.addAttribute("height", 30); 0685 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0686 m_svgWriter.startElement("path"); 0687 m_svgWriter.addAttribute("d", "M0,00 L30,30 M0,15 L15,30 M15,0 L30,15"); 0688 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0689 m_svgWriter.endElement(); // path 0690 m_svgWriter.endElement(); // pattern 0691 break; 0692 case Qt::DiagCrossPattern: 0693 m_svgWriter.startElement("pattern"); 0694 m_svgWriter.addAttribute("id", fillId); 0695 m_svgWriter.addAttribute("x", 0); 0696 m_svgWriter.addAttribute("y", 0); 0697 m_svgWriter.addAttribute("width", 30); 0698 m_svgWriter.addAttribute("height", 30); 0699 m_svgWriter.addAttribute("patternUnits", "userSpaceOnUse"); 0700 m_svgWriter.startElement("path"); 0701 m_svgWriter.addAttribute("d", "M0,30 L30,0 M0,15 L15,0 M15,30 L30,15 M0,00 L30,30 M0,15 L15,30 M15,0 L30,15"); 0702 m_svgWriter.addAttribute("style", "stroke:black;stroke-width:1"); 0703 m_svgWriter.endElement(); // path 0704 m_svgWriter.endElement(); // pattern 0705 break; 0706 default: 0707 debugWmf << "unsupported brush style:" << context.brush.style(); 0708 return QString(); 0709 } 0710 0711 fillStyle = QString("fill:url(#%1);").arg(fillId); 0712 0713 if (context.polyFillMode == Libwmf::ALTERNATE) 0714 fillStyle += "fill-rule:evenodd;"; 0715 0716 return fillStyle; 0717 } 0718 0719 void WMFImportParser::setCompositionMode(QPainter::CompositionMode) 0720 { 0721 //TODO 0722 } 0723 0724 QRectF WMFImportParser::boundBox(int left, int top, int width, int height) 0725 { 0726 const int l = qMin(left, left+width); 0727 const int t = qMin(top, top+height); 0728 const int w = qAbs(width); 0729 const int h = qAbs(height); 0730 0731 return QRectF(coord(QPoint(l,t)), size(QSize(w, h))); 0732 } 0733 0734 QPointF WMFImportParser::coord(const QPoint &p) 0735 { 0736 const qreal dx = m_viewport.org.x()-m_window.org.x(); 0737 const qreal dy = m_viewport.org.y()-m_window.org.y(); 0738 const qreal x = (p.x() + dx) * m_scaleX; 0739 const qreal y = (p.y() + dy) * m_scaleY; 0740 return QPointF(x, y); 0741 } 0742 0743 QSizeF WMFImportParser::size(const QSize &s) 0744 { 0745 return QSizeF(m_scaleX *s.width(), m_scaleY*s.height()); 0746 } 0747 0748 void WMFImportParser::updateTransform() 0749 { 0750 if (m_window.extIsValid && m_viewport.extIsValid) { 0751 m_scaleX = m_viewport.ext.width() / m_window.ext.width(); 0752 m_scaleY = m_viewport.ext.height() / m_window.ext.height(); 0753 } 0754 debugWmf << "window:" << QRectF(m_window.org, m_window.ext); 0755 debugWmf << "viewport:" << QRectF(m_viewport.org, m_viewport.ext); 0756 debugWmf << "scale:" << m_scaleX << m_scaleY; 0757 }