chalk

kis_transform_worker.cpp
1/*
2 * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de> filters
3 * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
4 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org> right angle rotators
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20#include <kdebug.h>
21#include <tdelocale.h>
22
23#include "kis_debug_areas.h"
24#include "kis_paint_device.h"
25#include "kis_selection.h"
26#include "kis_transform_worker.h"
27#include "kis_progress_display_interface.h"
28#include "kis_iterators_pixel.h"
29#include "kis_filter_strategy.h"
30#include "kis_layer.h"
31#include "kis_painter.h"
32
33KisTransformWorker::KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale,
34 double xshear, double yshear, double rotation,
35 TQ_INT32 xtranslate, TQ_INT32 ytranslate,
36 KisProgressDisplayInterface *progress, KisFilterStrategy *filter, bool fixBorderAlpha)
37{
38 m_dev= dev;
39 m_xscale = xscale;
40 m_yscale = yscale;
41 m_xshear = xshear;
42 m_yshear = yshear;
43 m_rotation = rotation,
44 m_xtranslate = xtranslate;
45 m_ytranslate = ytranslate;
46 m_progress = progress;
47 m_filter = filter;
48 m_fixBorderAlpha = fixBorderAlpha;
49}
50
51void KisTransformWorker::rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst)
52{
53 KisSelectionSP dstSelection;
54 TQ_INT32 pixelSize = src->pixelSize();
55 TQRect r;
56 KisColorSpace *cs = src->colorSpace();
57
58 if(src->hasSelection())
59 {
60 r = src->selection()->selectedExactRect();
61 dstSelection = dst->selection();
62 }
63 else
64 {
65 r = src->exactBounds();
66 dstSelection = new KisSelection(dst); // essentially a dummy to be deleted
67 }
68
69 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), r.top(), r.width(), true);
70 KisHLineIterator vit = dst->createHLineIterator(r.x(), r.top(), r.width(), true);
71 KisHLineIterator dstSelIt = dstSelection->createHLineIterator(r.x(), r.top(), r.width(), true);
72 for (TQ_INT32 i = 0; i < r.height(); ++i) {
73 while (!hit.isDone()) {
74 if (hit.isSelected()) {
75 memcpy(vit.rawData(), hit.rawData(), pixelSize);
76
77 // XXX: Should set alpha = alpha*(1-selectedness)
78 cs->setAlpha(hit.rawData(), 0, 1);
79 }
80 *(dstSelIt.rawData()) = hit.selectedness();
81 ++hit;
82 ++vit;
83 ++dstSelIt;
84 }
85 hit.nextRow();
86 vit.nextRow();
87 dstSelIt.nextRow();
88
89 //progress info
90 m_progressStep += r.width();
91 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
92 {
93 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
94 emit notifyProgress(m_lastProgressReport);
95 }
96 if (m_cancelRequested) {
97 break;
98 }
99 }
100}
101
102void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
103{
104 KisSelectionSP dstSelection;
105 TQ_INT32 pixelSize = src->pixelSize();
106 TQRect r;
107 KisColorSpace *cs = src->colorSpace();
108
109 if(src->hasSelection())
110 {
111 r = src->selection()->selectedExactRect();
112 dstSelection = dst->selection();
113 }
114 else
115 {
116 r = src->exactBounds();
117 dstSelection = new KisSelection(dst); // essentially a dummy to be deleted
118 }
119
120 for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) {
121 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
122 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
123 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(-y, r.x(), r.width(), true);
124
125 while (!hit.isDone()) {
126 if (hit.isSelected()) {
127 memcpy(vit.rawData(), hit.rawData(), pixelSize);
128
129 // XXX: Should set alpha = alpha*(1-selectedness)
130 cs->setAlpha(hit.rawData(), 0, 1);
131 }
132 *(dstSelIt.rawData()) = hit.selectedness();
133 ++hit;
134 ++vit;
135 ++dstSelIt;
136 }
137
138 //progress info
139 m_progressStep += r.width();
140 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
141 {
142 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
143 emit notifyProgress(m_lastProgressReport);
144 }
145 if (m_cancelRequested) {
146 break;
147 }
148 }
149}
150
151void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
152{
153 kdDebug() << "rotateLeft90 called\n";
154 KisSelectionSP dstSelection;
155 TQ_INT32 pixelSize = src->pixelSize();
156 TQRect r;
157 KisColorSpace *cs = src->colorSpace();
158
159 if(src->hasSelection())
160 {
161 r = src->selection()->selectedExactRect();
162 dstSelection = dst->selection();
163 }
164 else
165 {
166 r = src->exactBounds();
167 dstSelection = new KisSelection(dst); // essentially a dummy to be deleted
168 }
169 TQ_INT32 x = 0;
170
171 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
172 // Read the horizontal line from back to front, write onto the vertical column
173 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
174 KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
175 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
176
177 hit += r.width() - 1;
178 while (!vit.isDone()) {
179 if (hit.isSelected()) {
180 memcpy(vit.rawData(), hit.rawData(), pixelSize);
181
182 // XXX: Should set alpha = alpha*(1-selectedness)
183 cs->setAlpha(hit.rawData(), 0, 1);
184 }
185 *(dstSelIt.rawData()) = hit.selectedness();
186 --hit;
187 ++vit;
188 ++dstSelIt;
189 }
190 ++x;
191
192 //progress info
193 m_progressStep += r.width();
194 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
195 {
196 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
197 emit notifyProgress(m_lastProgressReport);
198 }
199 if (m_cancelRequested) {
200 break;
201 }
202 }
203}
204
205void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst)
206{
207 kdDebug() << "Rotating 180\n";
208 KisSelectionSP dstSelection;
209 TQ_INT32 pixelSize = src->pixelSize();
210 TQRect r;
211 KisColorSpace *cs = src->colorSpace();
212
213 if(src->hasSelection())
214 {
215 r = src->selection()->selectedExactRect();
216 dstSelection = dst->selection();
217 }
218 else
219 {
220 r = src->exactBounds();
221 dstSelection = new KisSelection(dst); // essentially a dummy to be deleted
222 }
223
224 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
225 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), true);
226 KisHLineIterator dstIt = dst->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
227 KisHLineIterator dstSelIt = dstSelection->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
228
229 srcIt += r.width() - 1;
230 while (!dstIt.isDone()) {
231 if (srcIt.isSelected()) {
232 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
233
234 // XXX: Should set alpha = alpha*(1-selectedness)
235 cs->setAlpha(srcIt.rawData(), 0, 1);
236 }
237 *(dstSelIt.rawData()) = srcIt.selectedness();
238 --srcIt;
239 ++dstIt;
240 ++dstSelIt;
241 }
242
243 //progress info
244 m_progressStep += r.width();
245 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
246 {
247 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
248 emit notifyProgress(m_lastProgressReport);
249 }
250 if (m_cancelRequested) {
251 break;
252 }
253 }
254}
255
256template <class iter> iter createIterator(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len);
257
258template <> KisHLineIteratorPixel createIterator <KisHLineIteratorPixel>
259(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len)
260{
261 return dev->createHLineIterator(start, lineNum, len, true);
262}
263
264template <> KisVLineIteratorPixel createIterator <KisVLineIteratorPixel>
265(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len)
266{
267 return dev->createVLineIterator(lineNum, start, len, true);
268}
269
270template <class iter> void calcDimensions (KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines);
271
272template <> void calcDimensions <KisHLineIteratorPixel>
273(KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines)
274{
275 if(dev->hasSelection())
276 {
277 TQRect r = dev->selection()->selectedExactRect();
278 r.rect(&srcStart, &firstLine, &srcLen, &numLines);
279 }
280 else
281 dev->exactBounds(srcStart, firstLine, srcLen, numLines);
282}
283
284template <> void calcDimensions <KisVLineIteratorPixel>
285(KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines)
286{
287 if(dev->hasSelection())
288 {
289 TQRect r = dev->selection()->selectedExactRect();
290 r.rect(&firstLine, &srcStart, &numLines, &srcLen);
291 }
292 else
293 dev->exactBounds(firstLine, srcStart, numLines, srcLen);
294}
295
296struct FilterValues
297{
298 TQ_UINT8 numWeights;
299 TQ_UINT8 *weight;
300 ~FilterValues() {delete [] weight;}
301};
302
303template <class T> void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, double floatscale, double shear, TQ_INT32 dx, KisFilterStrategy *filterStrategy, bool fixBorderAlpha)
304{
305 TQ_INT32 lineNum,srcStart,firstLine,srcLen,numLines;
306 TQ_INT32 center, begin, end; /* filter calculation variables */
307 TQ_UINT8 *data;
308 TQ_UINT8 pixelSize = src->pixelSize();
309 KisSelectionSP dstSelection;
310 KisColorSpace * cs = src->colorSpace();
311 TQ_INT32 scale;
312 TQ_INT32 scaleDenom;
313 TQ_INT32 shearFracOffset;
314
315 if(src->hasSelection())
316 dstSelection = dst->selection();
317 else
318 dstSelection = new KisSelection(dst); // essentially a dummy to be deleted
319
320 calcDimensions <T>(src, srcStart, srcLen, firstLine, numLines);
321
322 scale = int(floatscale*srcLen);
323 scaleDenom = srcLen;
324
325 if(scaleDenom == 0)
326 return;
327
328 TQ_INT32 support = filterStrategy->intSupport();
329 TQ_INT32 dstLen, dstStart;
330 TQ_INT32 invfscale = 256;
331
332 // handle magnification/minification
333 if(abs(scale) < scaleDenom)
334 {
335 support *= scaleDenom;
336 support /= scale;
337
338 invfscale *= scale;
339 invfscale /= scaleDenom;
340 if(scale < 0) // handle mirroring
341 {
342 support = -support;
343 invfscale = -invfscale;
344 }
345 }
346
347 // handle mirroring
348 if(scale < 0)
349 dstLen = - scale;
350 else
351 dstLen = scale;
352
353 // Calculate extra length (in each side) needed due to shear
354 TQ_INT32 extraLen = (support+256)>>8 + 1;
355
356 TQ_UINT8 *tmpLine = new TQ_UINT8[(srcLen +2*extraLen)* pixelSize];
357 TQ_CHECK_PTR(tmpLine);
358
359 TQ_UINT8 *tmpSel = new TQ_UINT8[srcLen+2*extraLen];
360 TQ_CHECK_PTR(tmpSel);
361
362 //allocate space for colors
363 const TQ_UINT8 **colors = new const TQ_UINT8 *[2*support+1];
364
365 // Precalculate weights
366 FilterValues *filterWeights = new FilterValues[256];
367
368 for(int center = 0; center<256; ++center)
369 {
370 TQ_INT32 begin = (255 + center - support)>>8; // takes ceiling by adding 255
371 TQ_INT32 span = ((center + support)>>8) - begin + 1; // takes floor to get end. Subtracts begin to get span
372 TQ_INT32 t = (((begin<<8) - center) * invfscale)>>8;
373 TQ_INT32 dt = invfscale;
374 filterWeights[center].weight = new TQ_UINT8[span];
375//printf("%d (",center);
376 TQ_UINT32 sum=0;
377 for(int num = 0; num<span; ++num)
378 {
379 TQ_UINT32 tmpw = filterStrategy->intValueAt(t) * invfscale;
380
381 tmpw >>=8;
382 filterWeights[center].weight[num] = tmpw;
383//printf(" %d=%d,%d",t,filterWeights[center].weight[num],tmpw);
384 t += dt;
385 sum+=tmpw;
386 }
387//printf(" )%d sum =%d",span,sum);
388 if(sum!=255)
389 {
390 double fixfactor= 255.0/sum;
391 sum=0;
392 for(int num = 0; num<span; ++num)
393 {
394 filterWeights[center].weight[num] = int(filterWeights[center].weight[num] * fixfactor);
395 sum+=filterWeights[center].weight[num];
396 }
397 }
398
399//printf(" sum2 =%d",sum);
400 int num = 0;
401 while(sum<255 && num*2<span)
402 {
403 filterWeights[center].weight[span/2 + num]++;
404 ++sum;
405 if(sum<255 && num<span/2)
406 {
407 filterWeights[center].weight[span/2 - num - 1]++;
408 ++sum;
409 }
410 ++num;
411 }
412//printf(" sum3 =%d\n",sum);
413
414 filterWeights[center].numWeights = span;
415 }
416
417 for(lineNum = firstLine; lineNum < firstLine+numLines; lineNum++)
418 {
419 if(scale < 0)
420 dstStart = srcStart * scale / scaleDenom - dstLen + dx;
421 else
422 dstStart = (srcStart) * scale / scaleDenom + dx;
423
424 shearFracOffset = -int( 256 * (lineNum * shear - floor(lineNum * shear)));
425 dstStart += int(floor(lineNum * shear));
426
427 // Build a temporary line
428 T srcIt = createIterator <T>(src, srcStart - extraLen, lineNum, srcLen+2*extraLen);
429 TQ_INT32 i = 0;
430 while(!srcIt.isDone())
431 {
432 TQ_UINT8 *data;
433
434 data = srcIt.rawData();
435 memcpy(&tmpLine[i*pixelSize], data, pixelSize);
436
437 if(srcIt.isSelected())
438 {
439 // XXX: Should set alpha = alpha*(1-selectedness)
440 cs->setAlpha(data, 0, 1);
441 tmpSel[i] = 255;
442 }
443 else {
444 tmpSel[i] = 0;
445 }
446 ++srcIt;
447 i++;
448 }
449
450 T dstIt = createIterator <T>(dst, dstStart, lineNum, dstLen);
451 T dstSelIt = createIterator <T>(dstSelection, dstStart, lineNum, dstLen);
452
453 i=0;
454 while(!dstIt.isDone())
455 {
456 if(scaleDenom<2500)
457 center = ((i<<8) * scaleDenom) / scale;
458 else
459 {
460 if(scaleDenom<46000) // real limit is actually 46340 pixels
461 center = ((i * scaleDenom) / scale)<<8;
462 else
463 center = ((i<<8)/scale * scaleDenom) / scale; // XXX fails for sizes over 2^23 pixels src width
464 }
465
466 if(scale < 0)
467 center += srcLen<<8;
468
469 center += 128*scaleDenom/scale;//xxx doesn't work for scale<0;
470 center += (extraLen<<8) + shearFracOffset;
471
472 // find contributing pixels
473 begin = (255 + center - support)>>8; // takes ceiling by adding 255
474 end = (center + support)>>8; // takes floor
475
477 TQ_UINT8 selectedness = tmpSel[center>>8];
478 if(selectedness)
479 {
480 int num=0;
481 for(int srcpos = begin; srcpos <= end; ++srcpos)
482 {
483 colors[num] = &tmpLine[srcpos*pixelSize];
484 num++;
485 }
486 data = dstIt.rawData();
487 cs->mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data);
488
489 //possibly fix the alpha of the border if user wants it
490 if(fixBorderAlpha && (i==0 || i==dstLen-1))
491 cs->setAlpha(data, cs->getAlpha(&tmpLine[(center>>8)*pixelSize]), 1);
492
493 data = dstSelIt.rawData();
494 *data = selectedness;
495 }
496
497 ++dstSelIt;
498 ++dstIt;
499 i++;
500 }
501
502 //progress info
503 m_progressStep += dstLen;
504 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
505 {
506 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
507 emit notifyProgress(m_lastProgressReport);
508 }
509 if (m_cancelRequested) {
510 break;
511 }
512 }
513 delete [] colors;
514 delete [] tmpLine;
515 delete [] tmpSel;
516 delete [] filterWeights;
517}
518
519bool KisTransformWorker::run()
520{
521 //progress info
522 m_cancelRequested = false;
523 if(m_progress)
524 m_progress->setSubject(this, true, true);
525 m_progressTotalSteps = 0;
526 m_progressStep = 0;
527 TQRect r;
528 if(m_dev->hasSelection())
529 r = m_dev->selection()->selectedExactRect();
530 else
531 r = m_dev->exactBounds();
532
533 KisPaintDeviceSP tmpdev1 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev1");;
534 KisPaintDeviceSP tmpdev2 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
535 KisPaintDeviceSP tmpdev3 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
536 KisPaintDeviceSP srcdev = m_dev;
537
538 double xscale = m_xscale;
539 double yscale = m_yscale;
540 double xshear = m_xshear;
541 double yshear = m_yshear;
542 double rotation = m_rotation;
543 TQ_INT32 xtranslate = m_xtranslate;
544 TQ_INT32 ytranslate = m_ytranslate;
545
546 if(rotation < 0.0)
547 rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI;
548 else
549 rotation = fmod(rotation, 2*M_PI);
550 int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3;
551
552 // Figure out how we will do the initial right angle rotations
553 double tmp;
554 switch(rotQuadrant)
555 {
556 default: // just to shut up the compiler
557 case 0:
558 m_progressTotalSteps = 0;
559 break;
560 case 1:
561 rotation -= M_PI/2;
562 tmp = xscale;
563 xscale=yscale;
564 yscale=tmp;
565 m_progressTotalSteps = r.width() * r.height();
566 break;
567 case 2:
568 rotation -= M_PI;
569 m_progressTotalSteps = r.width() * r.height();
570 break;
571 case 3:
572 rotation -= -M_PI/2 + 2*M_PI;
573 tmp = xscale;
574 xscale = yscale;
575 yscale = tmp;
576 m_progressTotalSteps = r.width() * r.height();
577 break;
578 }
579
580 // Calculate some auxillary values
581 yshear = sin(rotation);
582 xshear = -tan(rotation/2);
583 xtranslate -= int(xshear*ytranslate);
584
585 // Calculate progress steps
586 m_progressTotalSteps += int(yscale * r.width() * r.height());
587 m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear));
588
589 m_lastProgressReport=0;
590
591 // Now that we have everything in place it's time to do the actual right angle rotations
592 switch(rotQuadrant)
593 {
594 default: // just to shut up the compiler
595 case 0:
596 break;
597 case 1:
598 rotateRight90(srcdev, tmpdev1);
599 srcdev = tmpdev1;
600 break;
601 case 2:
602 rotate180(srcdev, tmpdev1);
603 srcdev = tmpdev1;
604 break;
605 case 3:
606 rotateLeft90(srcdev, tmpdev1);
607 srcdev = tmpdev1;
608 break;
609 }
610
611 // Handle simple move case possibly with rotation of 90,180,270
612 if(rotation == 0.0 && xscale == 1.0 && yscale == 1.0)
613 {
614 if(rotQuadrant==0)
615 {
616 // Though not nessesay in the general case because we make several passes
617 // We need to move (not just copy) the data to a temp dev so we can move them back
618 rotateNone(srcdev, tmpdev1);
619 srcdev = tmpdev1;
620 }
621 if(m_dev->hasSelection())
622 m_dev->selection()->clear();
623
624 srcdev->move(srcdev->getX() + xtranslate, srcdev->getY() + ytranslate);
625 rotateNone(srcdev, m_dev);
626
627 //progress info
628 emit notifyProgressDone();
629 m_dev->emitSelectionChanged();
630
631 return m_cancelRequested;
632 }
633
634 if ( m_cancelRequested) {
635 emit notifyProgressDone();
636 return false;
637 }
638
639 transformPass <KisHLineIteratorPixel>(srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter, m_fixBorderAlpha);
640 if(m_dev->hasSelection())
641 m_dev->selection()->clear();
642
643 if ( m_cancelRequested) {
644 emit notifyProgressDone();
645 return false;
646 }
647
648 // Now do the second pass
649 transformPass <KisVLineIteratorPixel>(tmpdev2.data(), tmpdev3.data(), yscale, yshear, ytranslate, m_filter, m_fixBorderAlpha);
650
651 if(m_dev->hasSelection())
652 m_dev->selection()->clear();
653
654 if ( m_cancelRequested) {
655 emit notifyProgressDone();
656 return false;
657 }
658
659 if (xshear != 0.0)
660 transformPass <KisHLineIteratorPixel>(tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter, m_fixBorderAlpha);
661 else
662 {
663 // No need to filter again when we are only scaling
664 tmpdev3->move(tmpdev3->getX() + xtranslate, tmpdev3->getY());
665 rotateNone(tmpdev3, m_dev);
666 }
667
668 if (m_dev->parentLayer()) {
669 m_dev->parentLayer()->setDirty();
670 }
671 //progress info
672 emit notifyProgressDone();
673 m_dev->emitSelectionChanged();
674
675 return m_cancelRequested;
676}
A colorspace is the definition of a certain color model in Chalk.
virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const =0
Mix the colors given their weights and return in dst The sum of weights is assumed 255.
virtual TQ_UINT8 getAlpha(const TQ_UINT8 *pixel) const =0
Get the alpha value of the given pixel, downscaled to an 8-bit value.
virtual void setAlpha(TQ_UINT8 *pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const =0
Set the alpha channel of the given run of pixels to the given value.
The pixel iterators are high level iterarators.
A paint device contains the actual pixel data and offers methods to read and write pixels.
KisVLineIteratorPixel createVLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable)
This function return an iterator which points to the first pixel of a vertical line.
KisSelectionSP selection()
Get the current selection or create one if this paintdevice hasn't got a selection yet.
virtual TQ_INT32 pixelSize() const
Return the number of bytes a pixel takes.
KisHLineIteratorPixel createHLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable)
This function return an iterator which points to the first pixel of a horizontal line.
bool hasSelection()
Whether there is a valid selection for this paintdevice.
virtual void exactBounds(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const
Get the exact bounds of this paint device.
KisSelection contains a byte-map representation of a layer, where the value of a byte signifies wheth...