56
58
// --------------------------------------------------------------------
60
class IpeRenderData : public IpeBitmap::MRenderData {
62
virtual ~IpeRenderData() { /* nothing */ }
66
// --------------------------------------------------------------------
58
68
IpeCanvasPainter::IpeCanvasPainter(const IpeStyleSheet *sheet,
59
IpeCanvasPaintServices *services,
69
IpeCanvasFonts *fonts,
60
70
QPixmap *pixmap, QPainter *painter,
61
double zoom, bool pretty)
62
: IpePainter(sheet), iServices(services),
63
iPixmap(pixmap), iPainter(painter), iZoom(zoom), iPretty(pretty)
71
double zoom, bool pretty,
73
: IpePainter(sheet), iFonts(fonts),
74
iPixmap(pixmap), iPainter(painter), iZoom(zoom), iPretty(pretty),
75
iMaxBitmapSize(maxBitmapSize)
67
78
iPainter->setFont(QApplication::font());
68
80
// these symbolic dash styles are on fixed indices
69
81
for (int i = 0; i < 4; ++i)
71
83
StyleSheet()->Find(IpeAttribute(IpeAttribute::EDashStyle, true, i+1));
74
void IpeCanvasPainter::BeginPath(const IpeVector &v)
76
iV.push_back(QPt(Matrix() * v));
77
iType.push_back(EBeginPath);
80
void IpeCanvasPainter::BeginClosedPath(const IpeVector &v)
82
iV.push_back(QPt(Matrix() * v));
83
iType.push_back(EBeginClosedPath);
86
void IpeCanvasPainter::LineTo(const IpeVector &v)
86
void IpeCanvasPainter::DoMoveTo(const IpeVector &v)
88
if (iType.size() > 0 && iType.back() != EEndClosedPath)
89
iType.push_back(EEndPath);
90
iV.push_back(QPt(Matrix() * v));
91
iType.push_back(EMoveTo);
94
void IpeCanvasPainter::DoLineTo(const IpeVector &v)
88
96
iV.push_back(QPt(Matrix() * v));
89
97
iType.push_back(ELineTo);
92
void IpeCanvasPainter::CurveTo(const IpeVector &v1, const IpeVector &v2,
100
void IpeCanvasPainter::DoCurveTo(const IpeVector &v1, const IpeVector &v2,
95
103
iV.push_back(QPt(Matrix() * v1));
96
104
iV.push_back(QPt(Matrix() * v2));
292
void IpeCanvasPainter::DrawBitmap(IpeBitmap bitmap)
298
void IpeCanvasPainter::DoDrawBitmap(IpeBitmap bitmap)
294
if (!bitmap.RenderData())
295
iServices->CvSvcSetRenderData(bitmap);
300
if (!bitmap.RenderData()) {
301
// todo: should we remember if this failed?
302
IpeBuffer data = bitmap.PixelData();
303
if (data.size() > 0) {
304
IpeRenderData *render = new IpeRenderData;
305
// warning: data buffer must remain alive as long as img is
306
QImage img((uchar *) data.data(), bitmap.Width(), bitmap.Height(), 32,
307
0, 0, QImage::IgnoreEndian);
308
if (img.width() > iMaxBitmapSize || img.height() > iMaxBitmapSize) {
309
int wid = img.width();
310
int ht = img.height();
313
factor = wid / double(iMaxBitmapSize);
315
factor = ht / double(iMaxBitmapSize);
316
wid = int(wid / factor + 0.5);
317
ht = int(ht / factor + 0.5);
318
render->iImage = img.smoothScale(wid, ht);
320
render->iImage = img.copy();
321
// img no longer needed
322
bitmap.SetRenderData(render);
297
326
if (bitmap.RenderData()) {
298
QImage *qimg = static_cast<QImage *>(bitmap.RenderData());
299
IpeMatrix tf = Matrix() * IpeMatrix(1.0 / qimg->width(), 0.0,
300
0.0, -1.0 / qimg->height(),
327
IpeRenderData *render = static_cast<IpeRenderData *>(bitmap.RenderData());
328
IpeMatrix tf = Matrix() * IpeMatrix(1.0 / render->iImage.width(), 0.0,
329
0.0, -1.0 / render->iImage.height(),
303
332
m.setMatrix(tf.iA[0], tf.iA[1], tf.iA[2], tf.iA[3], tf.iA[4], tf.iA[5]);
304
333
iPainter->setWorldMatrix(m, true);
305
iPainter->drawImage(0, 0, *qimg);
334
iPainter->drawImage(0, 0, render->iImage);
306
335
iPainter->resetXForm();
310
void IpeCanvasPainter::DrawText(const IpeText *text)
339
void IpeCanvasPainter::DoDrawText(const IpeText *text)
312
341
if (Stroke().IsNullOrVoid())
314
343
// 'stroke' must be an absolute color
315
344
assert(Stroke().IsAbsolute());
317
IpeColor stroke = StyleSheet()->Repository()->ToColor(Stroke());
318
QColor col(int(stroke.iRed * 255), int(stroke.iGreen * 255),
319
int(stroke.iBlue * 255));
322
QRgb rgb = col.rgb();
346
// Current origin is lower left corner of text box
324
348
// Draw bounding box rectangle
349
if (!iPretty && !iDimmed) {
327
351
pen.setColor(Qt::green);
328
352
pen.setStyle(Qt::DotLine);
352
376
if (s.length() < olen)
354
iPainter->setPen(col);
379
IpeColor stroke = StyleSheet()->Repository()->ToColor(Stroke());
380
QColor col(int(stroke.iRed * 255), int(stroke.iGreen * 255),
381
int(stroke.iBlue * 255));
382
iPainter->setPen(iDimmed ? col.light() : col);
355
384
// QRect r = iPainter->fontMetrics().boundingRect(s);
356
385
QPoint pt = QPt(Matrix().Translation());
357
386
pt.setY(pt.y() - iPainter->fontMetrics().descent());
358
387
//if (text->IsMiniPage())
359
388
//pt.setY(pt.y() + 15.0);
360
389
iPainter->drawText(pt, s);
365
Matrix() * IpeMatrix(xf->iStretch.iX, 0, 0, xf->iStretch.iY, 0, 0);
366
for (IpeText::PdfCharSeq::const_iterator it = xf->iRender.begin();
367
it != xf->iRender.end(); ++it) {
368
IpeVector pos = m1 * it->iPos;
369
QRgb cRgb = (it->iRgb == 0) ? rgb : it->iRgb;
370
// compute world transformation
371
IpeMatrix m = m1 * IpeLinear(it->iMatrix[0], it->iMatrix[1],
372
it->iMatrix[2], it->iMatrix[3]);
373
iServices->CvSvcRenderCharacter(iPixmap, it->iFontObject, m,
374
pos, cRgb, it->iCharCode, it->iUnicode);
377
for (IpeText::PdfSegSeq::const_iterator it = xf->iLines.begin();
378
it != xf->iLines.end(); ++it) {
380
QColor qstroke(QRgb(it->iRgb));
381
pen.setColor(qstroke);
382
double wid = iZoom * it->iWidth;
383
pen.setWidth(uint(wid + 0.5));
384
iPainter->setPen(pen);
385
iPainter->moveTo(QPt(m1 * it->iSeg.iP));
386
iPainter->lineTo(QPt(m1 * it->iSeg.iQ));
391
Transform(IpeMatrix(xf->iStretch.iX, 0, 0, xf->iStretch.iY, 0, 0));
392
Execute(xf->iStream);
396
// --------------------------------------------------------------------
398
//! Clear PDF argument stack
399
void IpeCanvasPainter::ClearArgs()
401
while (!iArgs.empty()) {
407
void IpeCanvasPainter::Execute(const IpeBuffer &buffer)
409
IpeBufferSource source(buffer);
410
IpePdfParser parser(source);
413
iStrokeRgb = 0x000000;
414
while (!parser.Eos()) {
415
IpePdfToken tok = parser.Token();
416
if (tok.iType != IpePdfToken::EOp) {
417
const IpePdfObj *obj = parser.GetObject();
419
break; // no further parsing attempted
420
iArgs.push_back(obj);
422
// its an operator, execute it
423
IpeString op = tok.iString;
449
else if (op != "ET") {
451
for (uint i = 0; i < iArgs.size(); ++i)
452
a += iArgs[i]->Repr() + " ";
453
ipeDebug("Op %s (%s)", op.CString(), a.CString());
461
void IpeCanvasPainter::Opg(bool stroke)
463
if (iArgs.size() != 1 || !iArgs[0]->Number())
465
int gr = int(iArgs[0]->Number()->Value() * 255);
467
iStrokeRgb = qRgb(gr, gr, gr);
469
iFillRgb = qRgb(gr, gr, gr);
473
void IpeCanvasPainter::Oprg(bool stroke)
475
if (iArgs.size() != 3 || !iArgs[0]->Number() || !iArgs[1]->Number()
476
|| !iArgs[2]->Number())
478
int r = int(iArgs[0]->Number()->Value() * 255);
479
int g = int(iArgs[1]->Number()->Value() * 255);
480
int b = int(iArgs[2]->Number()->Value() * 255);
485
iStrokeRgb = col.rgb();
487
iFillRgb = col.rgb();
490
void IpeCanvasPainter::Opcm()
492
if (iArgs.size() != 6)
495
for (int i = 0; i < 6; ++i) {
496
if (!iArgs[i]->Number())
498
m.iA[i] = iArgs[i]->Number()->Value();
503
void IpeCanvasPainter::Opw()
505
if (iArgs.size() != 1 || !iArgs[0]->Number())
507
iLineWid = iArgs[0]->Number()->Value();
511
void IpeCanvasPainter::Opm()
513
if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
515
IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
519
void IpeCanvasPainter::Opl()
521
if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
523
IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
526
pen.setColor(QRgb(iStrokeRgb));
527
pen.setWidth(uint(iZoom * iLineWid + 0.5));
528
iPainter->setPen(pen);
529
iPainter->moveTo(QPt(Matrix() * iMoveTo));
530
iPainter->lineTo(QPt(Matrix() * t));
533
void IpeCanvasPainter::OpBT()
536
iTextPos = IpeVector::Zero;
539
void IpeCanvasPainter::OpTf()
541
if (iArgs.size() != 2 || !iArgs[0]->Name() || !iArgs[1]->Number())
543
IpeString name = iArgs[0]->Name()->Value();
544
iFontSize = iArgs[1]->Number()->Value();
547
int font = IpeLex(name.substr(1)).GetInt();
548
// ipeDebug("Setting font %d at %g", font, iFontSize);
549
IpeLinear m = Matrix().Linear() * IpeLinear(iFontSize, 0, 0, iFontSize);
550
iFont = iFonts->GetSize(font, m);
553
void IpeCanvasPainter::OpTd()
555
if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
557
IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
558
iTextPos = iTextPos + t;
561
void IpeCanvasPainter::OpTJ()
563
if (!iFont || iArgs.size() != 1 || !iArgs[0]->Array())
565
IpeVector pos = iTextPos;
566
for (int i = 0; i < iArgs[0]->Array()->Count(); ++i) {
567
const IpePdfObj *obj = iArgs[0]->Array()->Obj(i, 0);
569
pos.iX -= 0.001 * iFontSize * obj->Number()->Value();
570
} else if (obj->String()) {
571
IpeString s = obj->String()->Value();
572
for (int j = 0; j < s.size(); ++j) {
574
QPoint pt = QPt(Matrix() * pos);
575
DrawChar(ch, iFillRgb, pt.x(), pt.y());
576
pos.iX += 0.001 * iFontSize * iFont->Face()->Width(ch);
582
// --------------------------------------------------------------------
585
/*! Glyph is drawn with hotspot at position (x,y) (on the pixmap) */
586
bool IpeCanvasPainter::DrawChar(int ch, QRgb rgb, int x, int y)
591
int w = iPixmap->width();
592
int h = iPixmap->height();
594
// generate the glyph pixmap
595
int xOffset, yOffset, gw, gh;
596
uchar *p = iFont->GetGlyph(ch, xOffset, yOffset, gw, gh);
600
// compute: (x0,y0) = position in destination pixmap
601
// (x1,y1) = position in glyph image
602
// (w0,h0) = size of image transfer
603
int x0, y0, x1, y1, w0, h0;
630
bitBlt(&dst, x1, y1, iPixmap, x0, y0, w0, h0);
631
QImage image = dst.convertToImage();
633
if (iFonts->AntiAlias()) {
637
// stuff the glyph pixmap into the image
638
for (int yy = 0; yy < gh; ++yy) {
639
uint *dst = (uint *) image.scanLine(yy);
640
for (int xx = 0; xx < gw; ++xx) {
641
int pix = *p++ & 0xff;
642
int pix1 = 0xff - pix;
645
int newr = (pix * r + pix1 * qRed(bg)) / 255;
646
int newg = (pix * g + pix1 * qGreen(bg)) / 255;
647
int newb = (pix * b + pix1 * qBlue(bg)) / 255;
648
*dst = qRgb(newr, newg, newb);
655
for (int yy = 0; yy < gh; ++yy) {
656
uint *dst = (uint *) image.scanLine(yy);
657
for (int xx = 0; xx < gw; xx += 8) {
659
for (int xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
668
dst.convertFromImage(image);
669
bitBlt(iPixmap, x0, y0, &dst, x1, y1, w0, h0);
390
673
// --------------------------------------------------------------------