2
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
3
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
4
* Copyright (c) 2004 Clarence Dang <dang@kde.org>
5
* Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
6
* Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
7
* Copyright (c) 2008 Lukas Tvrdy <lukast.dev@gmail.com>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
#include "kis_painter.h"
36
#include <QStringList>
37
#include <QUndoCommand>
39
#include <kis_debug.h>
42
#include <ksharedconfig.h>
43
#include <kconfiggroup.h>
45
#include <KoColorSpace.h>
47
#include <KoCompositeOp.h>
49
#include "kis_image.h"
50
#include "filter/kis_filter.h"
51
#include "kis_layer.h"
52
#include "kis_paint_device.h"
53
#include "kis_fixed_paint_device.h"
54
#include "kis_transaction.h"
55
#include "kis_types.h"
57
#include "kis_iterators_pixel.h"
58
#include "kis_random_accessor.h"
59
#include "kis_paintop.h"
60
#include "kis_selection.h"
61
#include "kis_fill_painter.h"
62
#include "filter/kis_filter_configuration.h"
63
#include "kis_pixel_selection.h"
64
#include "kis_paint_information.h"
65
#include "kis_paintop_registry.h"
66
#include "kis_perspective_math.h"
68
// Maximum distance from a Bezier control point to the line through the start
69
// and end points for the curve to be considered flat.
70
#define BEZIER_FLATNESS_THRESHOLD 0.5
72
struct KisPainter::Private {
73
KisPaintDeviceSP device;
74
KisSelectionSP selection;
75
KisTransaction* transaction;
76
KoUpdater* progressUpdater;
83
KoColor backgroundColor;
85
const KisFilterConfiguration* generator;
86
KisPaintLayer* sourceLayer;
88
StrokeStyle strokeStyle;
89
bool antiAliasPolygonFill;
90
const KisPattern* pattern;
91
QPointF duplicateOffset;
94
const KoColorSpace* colorSpace;
95
KoColorProfile* profile;
96
const KoCompositeOp* compositeOp;
97
QBitArray channelFlags;
98
bool useBoundingDirtyRect;
99
const KoAbstractGradient* gradient;
100
KisPaintOpPresetSP paintOpPreset;
101
QImage polygonMaskImage;
102
QPainter* maskPainter;
103
KisFillPainter* fillPainter;
104
qint32 maskImageWidth;
105
qint32 maskImageHeight;
109
KisPainter::KisPainter()
115
KisPainter::KisPainter(KisPaintDeviceSP device)
123
KisPainter::KisPainter(KisPaintDeviceSP device, KisSelectionSP selection)
129
d->selection = selection;
132
void KisPainter::init()
138
d->opacity = OPACITY_OPAQUE_U8;
140
d->fillStyle = FillStyleNone;
141
d->strokeStyle = StrokeStyleBrush;
142
d->antiAliasPolygonFill = true;
144
d->progressUpdater = 0;
148
d->maskImageWidth = 255;
149
d->maskImageHeight = 255;
150
d->alphaLocked = false;
152
KConfigGroup cfg = KGlobal::config()->group("");
153
d->useBoundingDirtyRect = cfg.readEntry("aggregate_dirty_regions", true);
156
KisPainter::~KisPainter()
158
QUndoCommand* cmd = end();
162
delete d->maskPainter;
163
delete d->fillPainter;
167
void KisPainter::begin(KisPaintDeviceSP device)
169
begin(device, d->selection);
172
void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection)
175
d->selection = selection;
176
Q_ASSERT(device->colorSpace());
178
delete d->transaction;
182
d->colorSpace = device->colorSpace();
183
d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER);
184
d->pixelSize = device->pixelSize();
186
QUndoCommand *KisPainter::end()
188
return endTransaction();
191
void KisPainter::beginTransaction(const QString& customName)
193
delete d->transaction;
194
d->transaction = new KisTransaction(customName, d->device);
195
Q_CHECK_PTR(d->transaction);
198
void KisPainter::beginTransaction(KisTransaction* command)
200
delete d->transaction;
201
d->transaction = command;
205
QUndoCommand* KisPainter::endTransaction()
207
if (!d->transaction) return 0;
210
d->device->disconnect(d->transaction);
212
QUndoCommand *command = d->transaction;
217
QRegion KisPainter::dirtyRegion()
219
if (d->useBoundingDirtyRect) {
220
QRegion r(d->dirtyRect);
221
d->dirtyRegion = QRegion();
222
d->dirtyRect = QRect();
225
QRegion r = d->dirtyRegion;
226
d->dirtyRegion = QRegion();
232
QRegion KisPainter::addDirtyRect(const QRect & rc)
234
QRect r = rc.normalized();
236
if (!r.isValid() || r.width() <= 0 || r.height() <= 0) {
237
return d->dirtyRegion;
240
if (d->useBoundingDirtyRect) {
241
d->dirtyRect = d->dirtyRect.united(r);
242
return QRegion(d->dirtyRect);
244
d->dirtyRegion += QRegion(r);
245
return d->dirtyRegion;
249
void KisPainter::bitBlt(qint32 dx, qint32 dy, const KisPaintDeviceSP srcdev, const KisFixedPaintDeviceSP selection, qint32 sx, qint32 sy, qint32 sw, qint32 sh)
251
if (sw == 0 || sh == 0) return;
252
if (srcdev.isNull()) return;
253
if (d->device.isNull()) return;
255
Q_ASSERT(srcdev->pixelSize() == d->pixelSize);
256
Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
258
QRect srcRect = QRect(sx, sy, sw, sh);
260
// In case of COMPOSITE_COPY restricting bitblt to extent can
261
// have unexpected behavior since it would reduce the area that
263
if (d->compositeOp->id() != COMPOSITE_COPY) {
264
srcRect &= srcdev->extent();
267
if (srcRect.isEmpty()) {
271
dx += srcRect.x() - sx;
272
dy += srcRect.y() - sy;
276
sw = srcRect.width();
277
sh = srcRect.height();
279
quint8 * srcBytes = new quint8[ sw * sh * srcdev->pixelSize()];
280
srcdev->readBytes(srcBytes,sx,sy,sw,sh);
282
quint8 * dstBytes = new quint8[ sw * sh * d->device->pixelSize()];
283
d->device->readBytes(dstBytes, dx,dy, sw, sh);
285
quint8 * selectionBytes = new quint8[ sw * sh * selection->pixelSize()];
286
selection->readBytes(selectionBytes, 0, 0, sw, sh);
288
d->colorSpace->bitBlt(dstBytes,
289
sw * d->device->pixelSize(),
290
srcdev->colorSpace(),
292
sw * srcdev->colorSpace()->pixelSize(),
294
sw * selection->pixelSize(),
301
d->device->writeBytes(dstBytes, dx, dy, sw, sh);
306
addDirtyRect(QRect(dx, dy, sw, sh));
311
void KisPainter::bitBlt(qint32 dx, qint32 dy,
312
const KisPaintDeviceSP srcdev,
313
qint32 sx, qint32 sy,
314
qint32 sw, qint32 sh)
316
if (sw == 0 || sh == 0) return;
317
if (srcdev.isNull()) return;
318
if (d->device.isNull()) return;
320
QRect srcRect = QRect(sx, sy, sw, sh);
322
// In case of COMPOSITE_COPY restricting bitblt to extent can
323
// have unexpected behavior since it would reduce the area that
325
if (d->compositeOp->id() != COMPOSITE_COPY) {
326
srcRect &= srcdev->extent();
329
if (srcRect.isEmpty()) {
333
dx += srcRect.x() - sx;
334
dy += srcRect.y() - sy;
338
sw = srcRect.width();
339
sh = srcRect.height();
341
const KoColorSpace * srcCs = srcdev->colorSpace();
345
qint32 rowsRemaining = sh;
347
KisRandomConstAccessorPixel srcIt = srcdev->createRandomConstAccessor(sx, sy);
348
KisRandomAccessorPixel dstIt = d->device->createRandomAccessor(dx, dy);
352
KisRandomConstAccessorPixel maskIt = d->selection->createRandomConstAccessor(dx, dy);
354
while (rowsRemaining > 0) {
358
qint32 columnsRemaining = sw;
359
qint32 numContiguousDstRows = d->device->numContiguousRows(dstY, dstX, dstX + sw - 1);
360
qint32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
361
qint32 numContiguousSelRows = d->selection->numContiguousRows(srcY, srcX, srcX + sw - 1);
363
qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
364
rows = qMin(rows, numContiguousSelRows);
365
rows = qMin(rows, rowsRemaining);
367
while (columnsRemaining > 0) {
369
qint32 numContiguousDstColumns = d->device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
370
qint32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
371
qint32 numContiguousSelColumns = d->selection->numContiguousColumns(srcX, srcY, srcY + rows - 1);
373
qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
374
columns = qMin(columns, numContiguousSelColumns);
375
columns = qMin(columns, columnsRemaining);
377
qint32 srcRowStride = srcdev->rowStride(srcX, srcY);
378
srcIt.moveTo(srcX, srcY);
380
qint32 dstRowStride = d->device->rowStride(dstX, dstY);
381
dstIt.moveTo(dstX, dstY);
383
qint32 maskRowStride = d->selection->rowStride(dstX, dstY);
384
maskIt.moveTo(dstX, dstY);
386
d->colorSpace->bitBlt(dstIt.rawData(),
400
columnsRemaining -= columns;
405
rowsRemaining -= rows;
409
while (rowsRemaining > 0) {
413
qint32 columnsRemaining = sw;
414
qint32 numContiguousDstRows = d->device->numContiguousRows(dstY, dstX, dstX + sw - 1);
415
qint32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
417
qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
418
rows = qMin(rows, rowsRemaining);
420
while (columnsRemaining > 0) {
422
qint32 numContiguousDstColumns = d->device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
423
qint32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
425
qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
426
columns = qMin(columns, columnsRemaining);
428
qint32 srcRowStride = srcdev->rowStride(srcX, srcY);
429
srcIt.moveTo(srcX, srcY);
431
qint32 dstRowStride = d->device->rowStride(dstX, dstY);
432
dstIt.moveTo(dstX, dstY);
434
d->colorSpace->bitBlt(dstIt.rawData(),
449
columnsRemaining -= columns;
454
rowsRemaining -= rows;
458
addDirtyRect(QRect(dx, dy, sw, sh));
461
void KisPainter::bitBlt(const QPoint & pos, const KisPaintDeviceSP src, const QRect & srcRect)
463
bitBlt(pos.x(), pos.y(), src, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
468
void KisPainter::bltFixed(qint32 dx, qint32 dy,
469
const KisFixedPaintDeviceSP srcDev,
470
qint32 sx, qint32 sy,
471
qint32 sw, qint32 sh)
473
if (sw == 0 || sh == 0) return;
474
if (srcDev.isNull()) return;
475
if (d->device.isNull()) return;
476
Q_ASSERT(srcDev->pixelSize() == d->pixelSize);
478
QRect srcRect = QRect(sx, sy, sw, sh);
480
if (srcRect.isEmpty()) {
484
if (!srcRect.contains(srcDev->bounds())) {
485
srcRect = srcDev->bounds();
488
dx += srcRect.x() - sx;
489
dy += srcRect.y() - sy;
493
sw = srcRect.width();
494
sh = srcRect.height();
496
const KoColorSpace * srcCs = d->colorSpace;
497
quint8* dstBytes = new quint8[sw * sh * d->device->pixelSize()];
498
d->device->readBytes(dstBytes, dx, dy, sw, sh);
502
quint8* selBytes = new quint8[sw * sh * d->selection->pixelSize()];
503
d->selection->readBytes(selBytes, dx, dy, sw, sh);
505
d->colorSpace->bitBlt(dstBytes,
506
sw * d->device->pixelSize(),
509
srcDev->bounds().width() * srcDev->pixelSize(),
511
sw * d->selection->pixelSize(),
520
d->colorSpace->bitBlt(dstBytes,
521
sw * d->device->pixelSize(),
524
srcDev->bounds().width() * srcDev->pixelSize(),
535
d->device->writeBytes(dstBytes, dx, dy, sw, sh);
539
addDirtyRect(QRect(dx, dy, sw, sh));
543
void KisPainter::bltFixed(qint32 dx, qint32 dy,
544
const KisFixedPaintDeviceSP srcDev,
545
const KisFixedPaintDeviceSP selection,
546
qint32 sx, qint32 sy,
547
qint32 sw, qint32 sh)
549
if (sw == 0 || sh == 0) return;
550
if (srcDev.isNull()) return;
551
if (d->device.isNull()) return;
552
Q_ASSERT(srcDev->pixelSize() == d->pixelSize);
553
Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
555
QRect srcRect = QRect(sx, sy, sw, sh);
557
if (srcRect.isEmpty()) {
561
if (!srcRect.contains(srcDev->bounds())) {
562
srcRect = srcDev->bounds();
565
dx += srcRect.x() - sx;
566
dy += srcRect.y() - sy;
570
sw = srcRect.width();
571
sh = srcRect.height();
573
const KoColorSpace * srcCs = d->colorSpace;
574
quint8* dstBytes = new quint8[sw * sh * d->device->pixelSize()];
575
d->device->readBytes(dstBytes, dx, dy, sw, sh);
577
quint8* selBytes = selection->data();
579
d->colorSpace->bitBlt(dstBytes,
580
sw * d->device->pixelSize(),
583
srcDev->bounds().width() * srcDev->pixelSize(),
585
sw * selection->pixelSize(),
593
d->device->writeBytes(dstBytes, dx, dy, sw, sh);
597
addDirtyRect(QRect(dx, dy, sw, sh));
601
void KisPainter::bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP src, const QRect & srcRect)
603
bltFixed(pos.x(), pos.y(), src, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
606
KisDistanceInformation KisPainter::paintLine(const KisPaintInformation &pi1,
607
const KisPaintInformation &pi2,
608
const KisDistanceInformation& savedDist)
610
if (!d->device) return KisDistanceInformation();
611
if (!d->paintOp || !d->paintOp->canPaint()) return KisDistanceInformation();
613
return d->paintOp->paintLine(pi1, pi2, savedDist);
616
void KisPainter::paintPolyline(const vQPointF &points,
617
int index, int numPoints)
619
if (index >= (int) points.count())
623
numPoints = points.count();
625
if (index + numPoints > (int) points.count())
626
numPoints = points.count() - index;
629
KisDistanceInformation saveDist;
630
for (int i = index; i < index + numPoints - 1; i++) {
631
saveDist = paintLine(points [index], points [index + 1], saveDist);
635
static void getBezierCurvePoints(const KisVector2D &pos1,
636
const KisVector2D &control1,
637
const KisVector2D &control2,
638
const KisVector2D &pos2,
641
LineEquation line = LineEquation::Through(pos1, pos2);
642
qreal d1 = line.absDistance(control1);
643
qreal d2 = line.absDistance(control2);
645
if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
646
points.push_back(toQPointF(pos1));
648
// Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
650
KisVector2D l2 = (pos1 + control1) / 2;
651
KisVector2D h = (control1 + control2) / 2;
652
KisVector2D l3 = (l2 + h) / 2;
653
KisVector2D r3 = (control2 + pos2) / 2;
654
KisVector2D r2 = (h + r3) / 2;
655
KisVector2D l4 = (l3 + r2) / 2;
657
getBezierCurvePoints(pos1, l2, l3, l4, points);
658
getBezierCurvePoints(l4, r2, r3, pos2, points);
662
void KisPainter::getBezierCurvePoints(const QPointF &pos1,
663
const QPointF &control1,
664
const QPointF &control2,
666
vQPointF& points) const
668
::getBezierCurvePoints(toKisVector2D(pos1), toKisVector2D(control1), toKisVector2D(control2), toKisVector2D(pos2), points);
671
KisDistanceInformation KisPainter::paintBezierCurve(const KisPaintInformation &pi1,
672
const QPointF &control1,
673
const QPointF &control2,
674
const KisPaintInformation &pi2,
675
const KisDistanceInformation& savedDist)
677
if (d->paintOp && d->paintOp->canPaint()) {
678
return d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, savedDist);
680
return KisDistanceInformation();
683
void KisPainter::paintRect(const QRectF &rect)
685
QRectF normalizedRect = rect.normalized();
689
points.push_back(normalizedRect.topLeft());
690
points.push_back(normalizedRect.bottomLeft());
691
points.push_back(normalizedRect.bottomRight());
692
points.push_back(normalizedRect.topRight());
694
paintPolygon(points);
697
void KisPainter::paintRect(const double x,
702
paintRect(QRectF(x, y, w, h));
705
void KisPainter::paintEllipse(const QRectF &rect)
707
QRectF r = rect.normalized(); // normalize before checking as negative width and height are empty too
708
if (r.isEmpty()) return;
710
// See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation.
711
// kappa = (4/3*(sqrt(2)-1))
712
const double kappa = 0.5522847498;
713
const double lx = (r.width() / 2) * kappa;
714
const double ly = (r.height() / 2) * kappa;
716
QPointF center = r.center();
718
QPointF p0(r.left(), center.y());
719
QPointF p1(r.left(), center.y() - ly);
720
QPointF p2(center.x() - lx, r.top());
721
QPointF p3(center.x(), r.top());
725
getBezierCurvePoints(p0, p1, p2, p3, points);
727
QPointF p4(center.x() + lx, r.top());
728
QPointF p5(r.right(), center.y() - ly);
729
QPointF p6(r.right(), center.y());
731
getBezierCurvePoints(p3, p4, p5, p6, points);
733
QPointF p7(r.right(), center.y() + ly);
734
QPointF p8(center.x() + lx, r.bottom());
735
QPointF p9(center.x(), r.bottom());
737
getBezierCurvePoints(p6, p7, p8, p9, points);
739
QPointF p10(center.x() - lx, r.bottom());
740
QPointF p11(r.left(), center.y() + ly);
742
getBezierCurvePoints(p9, p10, p11, p0, points);
744
paintPolygon(points);
747
void KisPainter::paintEllipse(const double x,
752
paintEllipse(QRectF(x, y, w, h));
755
double KisPainter::paintAt(const KisPaintInformation& pi)
757
if (!d->paintOp || !d->paintOp->canPaint()) return 0.0;
758
return d->paintOp->paintAt(pi);
761
void KisPainter::fillPolygon(const vQPointF& points, FillStyle fillStyle)
763
if (points.count() < 3) {
767
if (fillStyle == FillStyleNone) {
771
QPainterPath polygonPath;
773
polygonPath.moveTo(points.at(0));
775
for (int pointIndex = 1; pointIndex < points.count(); pointIndex++) {
776
polygonPath.lineTo(points.at(pointIndex));
779
polygonPath.closeSubpath();
781
d->fillStyle = fillStyle;
782
fillPainterPath(polygonPath);
785
void KisPainter::paintPolygon(const vQPointF& points)
787
if (d->fillStyle != FillStyleNone) {
788
fillPolygon(points, d->fillStyle);
791
if (d->strokeStyle != StrokeStyleNone) {
792
if (points.count() > 1) {
793
KisDistanceInformation distance;
795
for (int i = 0; i < points.count() - 1; i++) {
796
distance = paintLine(KisPaintInformation(points[i]), KisPaintInformation(points[i + 1]), distance);
798
paintLine(points[points.count() - 1], points[0], distance);
803
void KisPainter::paintPainterPath(const QPainterPath& path)
805
if (d->fillStyle != FillStyleNone) {
806
fillPainterPath(path);
809
QPointF lastPoint, nextPoint;
810
int elementCount = path.elementCount();
811
KisDistanceInformation saveDist;
812
for (int i = 0; i < elementCount; i++) {
813
QPainterPath::Element element = path.elementAt(i);
814
switch (element.type) {
815
case QPainterPath::MoveToElement:
816
lastPoint = QPointF(element.x, element.y);
818
case QPainterPath::LineToElement:
819
nextPoint = QPointF(element.x, element.y);
820
saveDist = paintLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint), saveDist);
821
lastPoint = nextPoint;
823
case QPainterPath::CurveToElement:
824
nextPoint = QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y);
825
saveDist = paintBezierCurve(KisPaintInformation(lastPoint),
826
QPointF(path.elementAt(i).x, path.elementAt(i).y),
827
QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y),
828
KisPaintInformation(nextPoint), saveDist);
829
lastPoint = nextPoint;
837
void KisPainter::fillPainterPath(const QPainterPath& path)
839
FillStyle fillStyle = d->fillStyle;
841
if (fillStyle == FillStyleNone) {
845
// Fill the polygon bounding rectangle with the required contents then we'll
846
// create a mask for the actual polygon coverage.
848
KisPaintDeviceSP polygon = new KisPaintDevice(d->device->colorSpace());
849
Q_CHECK_PTR(polygon);
851
if (!d->fillPainter) {
852
d->fillPainter = new KisFillPainter(polygon);
854
d->fillPainter->begin(polygon);
858
QRectF boundingRect = path.boundingRect();
861
fillRect.setLeft((qint32)floor(boundingRect.left()));
862
fillRect.setRight((qint32)ceil(boundingRect.right()));
863
fillRect.setTop((qint32)floor(boundingRect.top()));
864
fillRect.setBottom((qint32)ceil(boundingRect.bottom()));
866
// Expand the rectangle to allow for anti-aliasing.
867
fillRect.adjust(-1, -1, 1, 1);
869
// Clip to the image bounds.
870
if (d->bounds.isValid()) {
871
fillRect &= d->bounds;
877
case FillStyleGradient:
878
// Currently unsupported, fall through
879
case FillStyleStrokes:
880
// Currently unsupported, fall through
881
warnImage << "Unknown or unsupported fill style in fillPolygon\n";
882
case FillStyleForegroundColor:
883
d->fillPainter->fillRect(fillRect, paintColor(), OPACITY_OPAQUE_U8);
885
case FillStyleBackgroundColor:
886
d->fillPainter->fillRect(fillRect, backgroundColor(), OPACITY_OPAQUE_U8);
888
case FillStylePattern:
889
Q_ASSERT(d->pattern != 0);
890
d->fillPainter->fillRect(fillRect, d->pattern);
892
case FillStyleGenerator:
893
Q_ASSERT(d->generator != 0);
894
d->fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), generator());
898
if (d->polygonMaskImage.isNull() || (d->maskPainter == 0)) {
899
d->polygonMaskImage = QImage(d->maskImageWidth, d->maskImageHeight, QImage::Format_ARGB32);
900
d->maskPainter = new QPainter(&d->polygonMaskImage);
901
d->maskPainter->setRenderHint(QPainter::Antialiasing, antiAliasPolygonFill());
904
// Break the mask up into chunks so we don't have to allocate a potentially very large QImage.
905
const QColor opaqueColor(OPACITY_OPAQUE_U8, OPACITY_OPAQUE_U8, OPACITY_OPAQUE_U8, 255);
906
const QBrush brush(opaqueColor);
907
for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += d->maskImageWidth) {
908
for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += d->maskImageHeight) {
910
d->polygonMaskImage.fill(qRgba(OPACITY_TRANSPARENT_U8, OPACITY_TRANSPARENT_U8, OPACITY_TRANSPARENT_U8, 255));
911
d->maskPainter->translate(-x, -y);
912
d->maskPainter->fillPath(path, brush);
913
d->maskPainter->translate(x, y);
915
qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, d->maskImageWidth);
916
qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, d->maskImageHeight);
918
KisHLineIterator lineIt = polygon->createHLineIterator(x, y, rectWidth);
921
for (int row = y; row < y + rectHeight; row++) {
922
QRgb* line = reinterpret_cast<QRgb*>(d->polygonMaskImage.scanLine(row - y));
923
while (!lineIt.isDone()) {
924
tmp = qRed(line[lineIt.x() - x]);
925
polygon->colorSpace()->applyAlphaU8Mask(lineIt.rawData(),
935
QRect r = polygon->extent();
937
// The strokes for the outline may have already added updated the dirtyrect, but it can't hurt,
938
// and if we're painting without outlines, then there will be no dirty rect. Let's do it ourselves...
939
bitBlt(r.x(), r.y(), polygon, r.x(), r.y(), r.width(), r.height());
942
void KisPainter::drawLine(const QPointF & start, const QPointF & end)
944
drawThickLine(start, end, 1, 1);
947
void KisPainter::drawDDALine(const QPointF & start, const QPointF & end)
949
KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
950
int pixelSize = d->device->pixelSize();
952
// Width and height of the line
953
int xd = (int)(end.x() - start.x());
954
int yd = (int)(end.y() - start.y());
958
float fx = start.x();
959
float fy = start.y();
960
float m = (float)yd / (float)xd;
976
x = (int)(fx + 0.5f);
977
accessor.moveTo(x, y);
978
if (accessor.isSelected()) {
979
memcpy(accessor.rawData(), d->paintColor.data(), pixelSize);
993
y = (int)(fy + 0.5f);
994
accessor.moveTo(x, y);
995
if (accessor.isSelected()) {
996
memcpy(accessor.rawData(), d->paintColor.data(), pixelSize);
1003
void KisPainter::drawWobblyLine(const QPointF & start, const QPointF & end)
1005
KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1006
int pixelSize = d->device->pixelSize();
1007
KoColor mycolor(d->paintColor);
1014
// Width and height of the line
1020
float fx = (x = x1);
1021
float fy = (y = y1);
1022
float m = (float)yd / (float)xd;
1037
x = (int)(fx + 0.5f);
1038
float br1 = int(fx + 1) - fx;
1039
float br2 = fx - (int)fx;
1041
accessor.moveTo(x, y);
1042
if (accessor.isSelected()) {
1043
mycolor.setOpacity((quint8)(255*br1));
1044
memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1047
accessor.moveTo(x + 1, y);
1048
if (accessor.isSelected()) {
1049
mycolor.setOpacity((quint8)(255*br2));
1050
memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1064
y = (int)(fy + 0.5f);
1066
float br1 = int(fy + 1) - fy;
1067
float br2 = fy - (int)fy;
1069
accessor.moveTo(x, y);
1070
if (accessor.isSelected()) {
1071
mycolor.setOpacity((quint8)(255*br1));
1072
memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1075
accessor.moveTo(x, y + 1);
1076
if (accessor.isSelected()) {
1077
mycolor.setOpacity((quint8)(255*br2));
1078
memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1085
void KisPainter::drawWuLine(const QPointF & start, const QPointF & end)
1087
KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1088
int pixelSize = d->device->pixelSize();
1089
KoColor lineColor(d->paintColor);
1098
float xgap, ygap, xend, yend, yf, xf;
1099
float brightness1, brightness2;
1101
int ix1, ix2, iy1, iy2;
1103
const float MaxPixelValue = 255.0f;
1110
/* Horizontal line */
1111
int incr = (x1 < x2) ? 1 : -1;
1115
while (ix1 != ix2) {
1117
accessor.moveTo(ix1, iy1);
1118
if (accessor.isSelected()) {
1119
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1127
int incr = (y1 < y2) ? 1 : -1;
1131
while (iy1 != iy2) {
1133
accessor.moveTo(ix1, iy1);
1134
if (accessor.isSelected()) {
1135
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1141
if (fabs(xd) > fabs(yd)) {
1143
// line have to be paint from left to right
1146
tmp = x1; x1 = x2; x2 = tmp;
1147
tmp = y1; y1 = y2; y2 = tmp;
1152
// nearest X,Y interger coordinates
1153
xend = static_cast<int>(x1 + 0.5f);
1154
yend = y1 + grad * (xend - x1);
1156
xgap = invertFrac(x1 + 0.5f);
1158
ix1 = static_cast<int>(xend);
1159
iy1 = static_cast<int>(yend);
1161
// calc the intensity of the other end point pixel pair.
1162
brightness1 = invertFrac(yend) * xgap;
1163
brightness2 = frac(yend) * xgap;
1165
c1 = (int)(brightness1 * MaxPixelValue);
1166
c2 = (int)(brightness2 * MaxPixelValue);
1168
accessor.moveTo(ix1, iy1);
1169
if (accessor.isSelected()) {
1170
lineColor.setOpacity(c1);
1171
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1174
accessor.moveTo(ix1, iy1 + 1);
1175
if (accessor.isSelected()) {
1176
lineColor.setOpacity(c2);
1177
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1180
// calc first Y-intersection for main loop
1183
xend = trunc(x2 + 0.5f);
1184
yend = y2 + grad * (xend - x2);
1186
xgap = invertFrac(x2 - 0.5f);
1188
ix2 = static_cast<int>(xend);
1189
iy2 = static_cast<int>(yend);
1191
brightness1 = invertFrac(yend) * xgap;
1192
brightness2 = frac(yend) * xgap;
1194
c1 = (int)(brightness1 * MaxPixelValue);
1195
c2 = (int)(brightness2 * MaxPixelValue);
1197
accessor.moveTo(ix2, iy2);
1198
if (accessor.isSelected()) {
1199
lineColor.setOpacity(c1);
1200
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1203
accessor.moveTo(ix2, iy2 + 1);
1204
if (accessor.isSelected()) {
1205
lineColor.setOpacity(c2);
1206
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1210
for (int x = ix1 + 1; x <= ix2 - 1; x++) {
1211
brightness1 = invertFrac(yf);
1212
brightness2 = frac(yf);
1213
c1 = (int)(brightness1 * MaxPixelValue);
1214
c2 = (int)(brightness2 * MaxPixelValue);
1216
accessor.moveTo(x, int (yf));
1217
if (accessor.isSelected()) {
1218
lineColor.setOpacity(c1);
1219
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1222
accessor.moveTo(x, int (yf) + 1);
1223
if (accessor.isSelected()) {
1224
lineColor.setOpacity(c2);
1225
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1232
// line have to be painted from left to right
1235
tmp = x1; x1 = x2; x2 = tmp;
1236
tmp = y1; y1 = y2; y2 = tmp;
1243
// nearest X,Y interger coordinates
1244
yend = static_cast<int>(y1 + 0.5f);
1245
xend = x1 + grad * (yend - y1);
1247
ygap = invertFrac(y1 + 0.5f);
1249
ix1 = static_cast<int>(xend);
1250
iy1 = static_cast<int>(yend);
1252
// calc the intensity of the other end point pixel pair.
1253
brightness1 = invertFrac(xend) * ygap;
1254
brightness2 = frac(xend) * ygap;
1256
c1 = (int)(brightness1 * MaxPixelValue);
1257
c2 = (int)(brightness2 * MaxPixelValue);
1259
accessor.moveTo(ix1, iy1);
1260
if (accessor.isSelected()) {
1261
lineColor.setOpacity(c1);
1262
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1265
accessor.moveTo(x1 + 1, y1);
1266
if (accessor.isSelected()) {
1267
lineColor.setOpacity(c2);
1268
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1271
// calc first Y-intersection for main loop
1274
yend = trunc(y2 + 0.5f);
1275
xend = x2 + grad * (yend - y2);
1277
ygap = invertFrac(y2 - 0.5f);
1279
ix2 = static_cast<int>(xend);
1280
iy2 = static_cast<int>(yend);
1282
brightness1 = invertFrac(xend) * ygap;
1283
brightness2 = frac(xend) * ygap;
1285
c1 = (int)(brightness1 * MaxPixelValue);
1286
c2 = (int)(brightness2 * MaxPixelValue);
1288
accessor.moveTo(ix2, iy2);
1289
if (accessor.isSelected()) {
1290
lineColor.setOpacity(c1);
1291
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1294
accessor.moveTo(ix2 + 1, iy2);
1295
if (accessor.isSelected()) {
1296
lineColor.setOpacity(c2);
1297
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1301
for (int y = iy1 + 1; y <= iy2 - 1; y++) {
1302
brightness1 = invertFrac(xf);
1303
brightness2 = frac(xf);
1304
c1 = (int)(brightness1 * MaxPixelValue);
1305
c2 = (int)(brightness2 * MaxPixelValue);
1307
accessor.moveTo(int (xf), y);
1308
if (accessor.isSelected()) {
1309
lineColor.setOpacity(c1);
1310
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1313
accessor.moveTo(int (xf) + 1, y);
1314
if (accessor.isSelected()) {
1315
lineColor.setOpacity(c2);
1316
memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1325
void KisPainter::drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth)
1327
KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1328
int pixelSize = d->device->pixelSize();
1329
KoColorSpace * cs = d->device->colorSpace();
1331
KoColor c1(d->paintColor);
1332
KoColor c2(d->paintColor);
1333
KoColor c3(d->paintColor);
1337
float grada, gradb, dxa, dxb, dya, dyb, adya, adyb, fraca, fracb,
1338
xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dx, dy;
1339
int x, y, ix1, ix2, iy1, iy2;
1343
int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b;
1344
int tp0, tn0, tp1, tn1;
1347
float opacity = 1.0;
1349
tp0 = startWidth / 2;
1350
tn0 = startWidth / 2;
1351
if (startWidth % 2 == 0) // even width startWidth
1356
if (endWidth % 2 == 0) // even width endWidth
1364
dx = x1 - x0; // run of general line
1365
dy = y1 - y0; // rise of general line
1367
if (dy < 0) dy = -dy;
1368
if (dx < 0) dx = -dx;
1370
if (dx > dy) { // horizontalish
1372
x0a = x0; y0a = y0 - tn0;
1373
x0b = x0; y0b = y0 + tp0;
1374
x1a = x1; y1a = y1 - tn1;
1375
x1b = x1; y1b = y1 + tp1;
1377
x0a = x0 - tn0; y0a = y0;
1378
x0b = x0 + tp0; y0b = y0;
1379
x1a = x1 - tn1; y1a = y1;
1380
x1b = x1 + tp1; y1b = y1;
1383
if (horizontal) { // draw endpoints
1384
for (int i = y0a; i <= y0b; i++) {
1385
accessor.moveTo(x0, i);
1386
if (accessor.isSelected()) {
1387
memcpy(accessor.rawData(), c1.data(), pixelSize);
1390
for (int i = y1a; i <= y1b; i++) {
1391
accessor.moveTo(x1, i);
1392
if (accessor.isSelected()) {
1393
memcpy(accessor.rawData(), c1.data(), pixelSize);
1398
for (int i = x0a; i <= x0b; i++) {
1399
accessor.moveTo(i, y0);
1400
if (accessor.isSelected()) {
1401
memcpy(accessor.rawData(), c1.data(), pixelSize);
1404
for (int i = x1a; i <= x1b; i++) {
1405
accessor.moveTo(i, y1);
1406
if (accessor.isSelected()) {
1407
memcpy(accessor.rawData(), c1.data(), pixelSize);
1412
//antialias endpoints
1413
if (x1 != x0 && y1 != y0) {
1415
accessor.moveTo(x0a, y0a - 1);
1416
if (accessor.isSelected()) {
1417
qreal alpha = cs->opacityF(accessor.rawData());
1418
opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
1419
col1.setOpacity(opacity);
1420
memcpy(accessor.rawData(), col1.data(), pixelSize);
1423
accessor.moveTo(x1b, y1b + 1);
1424
if (accessor.isSelected()) {
1425
qreal alpha = cs->opacityF(accessor.rawData());
1426
opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
1427
col1.setOpacity(opacity);
1428
memcpy(accessor.rawData(), col1.data(), pixelSize);
1432
accessor.moveTo(x0a - 1, y0a);
1433
if (accessor.isSelected()) {
1434
qreal alpha = cs->opacityF(accessor.rawData());
1435
opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
1436
col1.setOpacity(opacity);
1437
memcpy(accessor.rawData(), col1.data(), pixelSize);
1440
accessor.moveTo(x1b + 1, y1b);
1441
if (accessor.isSelected()) {
1442
qreal alpha = cs->opacityF(accessor.rawData());
1443
opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
1444
col1.setOpacity(opacity);
1445
memcpy(accessor.rawData(), col1.data(), pixelSize);
1450
dxa = x1a - x0a; // run of a
1451
dya = y1a - y0a; // rise of a
1452
dxb = x1b - x0b; // run of b
1453
dyb = y1b - y0b; // rise of b
1455
if (dya < 0) adya = -dya;
1457
if (dyb < 0) adyb = -dyb;
1461
if (horizontal) { // horizontal-ish lines
1465
xt = x1a; x1a = x0a; x0a = xt;
1466
yt = y1a; y1a = y0a; y0a = yt;
1467
xt = x1b; x1b = x0b; x0b = xt;
1468
yt = y1b; y1b = y0b; y0b = yt;
1469
xt = x1; x1 = x0; x0 = xt;
1470
yt = y1; y1 = y0; y0 = yt;
1472
tmp = c1; c1 = c2; c2 = tmp;
1473
wt = startWidth; startWidth = endWidth; endWidth = wt;
1485
for (x = ix1 + 1; x <= ix2 - 1; x++) {
1486
fraca = yfa - int (yfa);
1490
fracb = yfb - int (yfb);
1494
// color first pixel of bottom line
1495
opacity = ((x - ix1) / dx) * c2.opacityF() + (1 - (x - ix1) / dx) * c1.opacityF();
1496
c3.setOpacity(opacity);
1498
accessor.moveTo(x, (int)yfa);
1499
if (accessor.isSelected()) {
1500
qreal alpha = cs->opacityF(accessor.rawData());
1501
opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
1502
col1.setOpacity(opacity);
1503
memcpy(accessor.rawData(), col1.data(), pixelSize);
1506
// color first pixel of top line
1507
if (!(startWidth == 1 && endWidth == 1)) {
1508
accessor.moveTo(x, (int)yfb);
1509
if (accessor.isSelected()) {
1510
qreal alpha = cs->opacityF(accessor.rawData());
1511
opacity = b1b * c3.opacityF() + (1 - b1b) * alpha;
1512
col1.setOpacity(opacity);
1513
memcpy(accessor.rawData(), col1.data(), pixelSize);
1517
// color second pixel of bottom line
1518
if (grada != 0 && grada != 1) { // if not flat or exact diagonal
1519
accessor.moveTo(x, int (yfa) + 1);
1520
if (accessor.isSelected()) {
1521
qreal alpha = cs->opacityF(accessor.rawData());
1522
opacity = b2a * c3.opacityF() + (1 - b2a) * alpha;
1523
col2.setOpacity(opacity);
1524
memcpy(accessor.rawData(), col2.data(), pixelSize);
1529
// color second pixel of top line
1530
if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
1531
accessor.moveTo(x, int (yfb) + 1);
1532
if (accessor.isSelected()) {
1533
qreal alpha = cs->opacityF(accessor.rawData());
1534
opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
1535
col2.setOpacity(opacity);
1536
memcpy(accessor.rawData(), col2.data(), pixelSize);
1541
// fill remaining pixels
1542
if (!(startWidth == 1 && endWidth == 1)) {
1544
for (int i = yfa + 1; i <= yfb; i++) {
1545
accessor.moveTo(x, i);
1546
if (accessor.isSelected()) {
1547
memcpy(accessor.rawData(), c3.data(), pixelSize);
1551
for (int i = yfa + 1; i >= yfb; i--) {
1552
accessor.moveTo(x, i);
1553
if (accessor.isSelected()) {
1554
memcpy(accessor.rawData(), c3.data(), pixelSize);
1563
} else { // vertical-ish lines
1566
xt = x1a; x1a = x0a; x0a = xt;
1567
yt = y1a; y1a = y0a; y0a = yt;
1568
xt = x1b; x1b = x0b; x0b = xt;
1569
yt = y1b; y1b = y0b; y0b = yt;
1570
xt = x1; x1 = x0; x0 = xt;
1571
yt = y1; y1 = y0; y0 = yt;
1574
tmp = c1; c1 = c2; c2 = tmp;
1575
wt = startWidth; startWidth = endWidth; endWidth = wt;
1587
for (y = iy1 + 1; y <= iy2 - 1; y++) {
1588
fraca = xfa - int (xfa);
1592
fracb = xfb - int (xfb);
1596
// color first pixel of left line
1597
opacity = ((y - iy1) / dy) * c2.opacityF() + (1 - (y - iy1) / dy) * c1.opacityF();
1598
c3.setOpacity(opacity);
1600
accessor.moveTo(int (xfa), y);
1601
if (accessor.isSelected()) {
1602
qreal alpha = cs->opacityF(accessor.rawData());
1603
opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
1604
col1.setOpacity(opacity);
1605
memcpy(accessor.rawData(), col1.data(), pixelSize);
1608
// color first pixel of right line
1609
if (!(startWidth == 1 && endWidth == 1)) {
1610
accessor.moveTo(int(xfb), y);
1611
if (accessor.isSelected()) {
1612
qreal alpha = cs->opacityF(accessor.rawData());
1613
opacity = b1b * c3.opacityF() + (1 - b1b) * alpha;
1614
col1.setOpacity(opacity);
1615
memcpy(accessor.rawData(), col1.data(), pixelSize);
1619
// color second pixel of left line
1620
if (grada != 0 && grada != 1) { // if not flat or exact diagonal
1621
accessor.moveTo(int(xfa) + 1, y);
1622
if (accessor.isSelected()) {
1623
qreal alpha = cs->opacityF(accessor.rawData());
1624
opacity = b2a * c3.opacityF() + (1 - b2a) * alpha;
1625
col2.setOpacity(opacity);
1626
memcpy(accessor.rawData(), col2.data(), pixelSize);
1631
// color second pixel of right line
1632
if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
1633
accessor.moveTo(int(xfb) + 1, y);
1634
if (accessor.isSelected()) {
1635
qreal alpha = cs->opacityF(accessor.rawData());
1636
opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
1637
col2.setOpacity(opacity);
1638
memcpy(accessor.rawData(), col2.data(), pixelSize);
1642
// fill remaining pixels between current xfa,xfb
1643
if (!(startWidth == 1 && endWidth == 1)) {
1645
for (int i = (int) xfa + 1; i <= (int) xfb; i++) {
1646
accessor.moveTo(i, y);
1647
if (accessor.isSelected()) {
1648
memcpy(accessor.rawData(), c3.data(), pixelSize);
1652
for (int i = (int) xfb; i <= (int) xfa + 1; i++) {
1653
accessor.moveTo(i, y);
1654
if (accessor.isSelected()) {
1655
memcpy(accessor.rawData(), c3.data(), pixelSize);
1669
void KisPainter::setProgress(KoUpdater * progressUpdater)
1671
d->progressUpdater = progressUpdater;
1674
const KisPaintDeviceSP KisPainter::device() const
1678
KisPaintDeviceSP KisPainter::device()
1683
void KisPainter::setChannelFlags(QBitArray channelFlags)
1685
Q_ASSERT(d->channelFlags.isEmpty() || (uint)d->channelFlags.size() == d->colorSpace->channelCount());
1686
d->channelFlags = channelFlags;
1687
setLockAlpha(d->alphaLocked);
1690
QBitArray KisPainter::channelFlags()
1692
return d->channelFlags;
1695
void KisPainter::setPattern(const KisPattern * pattern)
1697
d->pattern = pattern;
1700
const KisPattern * KisPainter::pattern() const
1705
void KisPainter::setPaintColor(const KoColor& color)
1707
d->paintColor = color;
1709
d->paintColor.convertTo(d->device->colorSpace());
1713
const KoColor &KisPainter::paintColor() const
1715
return d->paintColor;
1718
void KisPainter::setBackgroundColor(const KoColor& color)
1720
d->backgroundColor = color;
1722
d->backgroundColor.convertTo(d->device->colorSpace());
1726
const KoColor &KisPainter::backgroundColor() const
1728
return d->backgroundColor;
1731
void KisPainter::setFillColor(const KoColor& color)
1733
d->fillColor = color;
1736
const KoColor &KisPainter::fillColor() const
1738
return d->fillColor;
1741
void KisPainter::setGenerator(const KisFilterConfiguration * generator)
1743
d->generator = generator;
1746
const KisFilterConfiguration * KisPainter::generator() const
1748
return d->generator;
1751
void KisPainter::setFillStyle(FillStyle fillStyle)
1753
d->fillStyle = fillStyle;
1756
KisPainter::FillStyle KisPainter::fillStyle() const
1758
return d->fillStyle;
1761
void KisPainter::setAntiAliasPolygonFill(bool antiAliasPolygonFill)
1763
d->antiAliasPolygonFill = antiAliasPolygonFill;
1766
bool KisPainter::antiAliasPolygonFill()
1768
return d->antiAliasPolygonFill;
1771
void KisPainter::setStrokeStyle(KisPainter::StrokeStyle strokeStyle)
1773
d->strokeStyle = strokeStyle;
1775
KisPainter::StrokeStyle KisPainter::strokeStyle() const
1777
return d->strokeStyle;
1780
void KisPainter::setOpacity(quint8 opacity)
1782
d->opacity = opacity;
1785
quint8 KisPainter::opacity() const
1790
void KisPainter::setBounds(const QRect & bounds)
1795
QRect KisPainter::bounds()
1800
void KisPainter::setCompositeOp(const KoCompositeOp * op)
1802
d->compositeOp = op;
1805
const KoCompositeOp * KisPainter::compositeOp()
1807
return d->compositeOp;
1810
void KisPainter::setCompositeOp(const QString& op)
1812
d->compositeOp = d->colorSpace->compositeOp(op);
1815
void KisPainter::setSelection(KisSelectionSP selection)
1817
d->selection = selection;
1820
KisSelectionSP KisPainter::selection()
1822
return d->selection;
1825
KoUpdater * KisPainter::progressUpdater()
1827
return d->progressUpdater;
1830
void KisPainter::setGradient(const KoAbstractGradient* gradient)
1832
d->gradient = gradient;
1835
const KoAbstractGradient* KisPainter::gradient()
1840
void KisPainter::setPaintOpPreset(KisPaintOpPresetSP preset, KisImageWSP image)
1842
d->paintOpPreset = preset;
1844
d->paintOp = KisPaintOpRegistry::instance()->paintOp(preset, this, image);
1847
KisPaintOpPresetSP KisPainter::preset() const
1849
return d->paintOpPreset;
1852
KisPaintOp* KisPainter::paintOp() const
1858
void KisPainter::setMaskImageSize(qint32 width, qint32 height)
1861
d->maskImageWidth = qBound(1, width, 256);
1862
d->maskImageHeight = qBound(1, height, 256);
1864
d->polygonMaskImage = QImage();
1867
void KisPainter::setLockAlpha(bool protect)
1869
d->alphaLocked = protect;
1870
if (d->channelFlags.isEmpty()) {
1871
d->channelFlags = d->colorSpace->channelFlags(true, !d->alphaLocked, true, true);
1874
Q_ASSERT((uint)d->channelFlags.size() == d->colorSpace->channelCount());
1875
QList<KoChannelInfo*> channels = d->colorSpace->channels();
1876
foreach (KoChannelInfo* channel, channels) {
1877
if (channel->channelType() == KoChannelInfo::ALPHA) {
1878
d->channelFlags.setBit(channel->index(), !d->alphaLocked);
1884
bool KisPainter::alphaLocked() const
1886
return d->alphaLocked;