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"
31#include "kis_painter.h"
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)
43 m_rotation = rotation,
44 m_xtranslate = xtranslate;
45 m_ytranslate = ytranslate;
46 m_progress = progress;
48 m_fixBorderAlpha = fixBorderAlpha;
51void KisTransformWorker::rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst)
53 KisSelectionSP dstSelection;
54 TQ_INT32 pixelSize = src->pixelSize();
58 if(src->hasSelection())
60 r = src->selection()->selectedExactRect();
61 dstSelection = dst->selection();
65 r = src->exactBounds();
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);
80 *(dstSelIt.rawData()) = hit.selectedness();
90 m_progressStep += r.width();
91 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
93 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
94 emit notifyProgress(m_lastProgressReport);
96 if (m_cancelRequested) {
102void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
104 KisSelectionSP dstSelection;
105 TQ_INT32 pixelSize = src->pixelSize();
109 if(src->hasSelection())
111 r = src->selection()->selectedExactRect();
112 dstSelection = dst->selection();
116 r = src->exactBounds();
120 for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) {
122 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(),
true);
123 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(-y, r.x(), r.width(),
true);
125 while (!hit.isDone()) {
126 if (hit.isSelected()) {
127 memcpy(vit.rawData(), hit.rawData(), pixelSize);
132 *(dstSelIt.rawData()) = hit.selectedness();
139 m_progressStep += r.width();
140 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
142 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
143 emit notifyProgress(m_lastProgressReport);
145 if (m_cancelRequested) {
151void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
153 kdDebug() <<
"rotateLeft90 called\n";
154 KisSelectionSP dstSelection;
155 TQ_INT32 pixelSize = src->pixelSize();
159 if(src->hasSelection())
161 r = src->selection()->selectedExactRect();
162 dstSelection = dst->selection();
166 r = src->exactBounds();
171 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
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);
177 hit += r.width() - 1;
178 while (!vit.isDone()) {
179 if (hit.isSelected()) {
180 memcpy(vit.rawData(), hit.rawData(), pixelSize);
185 *(dstSelIt.rawData()) = hit.selectedness();
193 m_progressStep += r.width();
194 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
196 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
197 emit notifyProgress(m_lastProgressReport);
199 if (m_cancelRequested) {
205void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst)
207 kdDebug() <<
"Rotating 180\n";
208 KisSelectionSP dstSelection;
209 TQ_INT32 pixelSize = src->pixelSize();
213 if(src->hasSelection())
215 r = src->selection()->selectedExactRect();
216 dstSelection = dst->selection();
220 r = src->exactBounds();
224 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
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);
229 srcIt += r.width() - 1;
230 while (!dstIt.isDone()) {
231 if (srcIt.isSelected()) {
232 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
235 cs->
setAlpha(srcIt.rawData(), 0, 1);
237 *(dstSelIt.rawData()) = srcIt.selectedness();
244 m_progressStep += r.width();
245 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
247 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
248 emit notifyProgress(m_lastProgressReport);
250 if (m_cancelRequested) {
256template <
class iter> iter createIterator(
KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len);
259(
KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len)
264template <> KisVLineIteratorPixel createIterator <KisVLineIteratorPixel>
265(
KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len)
270template <
class iter>
void calcDimensions (
KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines);
272template <>
void calcDimensions <KisHLineIteratorPixel>
273(
KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines)
277 TQRect r = dev->
selection()->selectedExactRect();
278 r.rect(&srcStart, &firstLine, &srcLen, &numLines);
281 dev->
exactBounds(srcStart, firstLine, srcLen, numLines);
284template <>
void calcDimensions <KisVLineIteratorPixel>
285(
KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines)
289 TQRect r = dev->
selection()->selectedExactRect();
290 r.rect(&firstLine, &srcStart, &numLines, &srcLen);
293 dev->
exactBounds(firstLine, srcStart, numLines, srcLen);
300 ~FilterValues() {
delete [] weight;}
303template <
class T>
void KisTransformWorker::transformPass(
KisPaintDevice *src,
KisPaintDevice *dst,
double floatscale,
double shear, TQ_INT32 dx, KisFilterStrategy *filterStrategy,
bool fixBorderAlpha)
305 TQ_INT32 lineNum,srcStart,firstLine,srcLen,numLines;
306 TQ_INT32 center, begin, end;
309 KisSelectionSP dstSelection;
313 TQ_INT32 shearFracOffset;
320 calcDimensions <T>(src, srcStart, srcLen, firstLine, numLines);
322 scale = int(floatscale*srcLen);
328 TQ_INT32 support = filterStrategy->intSupport();
329 TQ_INT32 dstLen, dstStart;
330 TQ_INT32 invfscale = 256;
333 if(abs(scale) < scaleDenom)
335 support *= scaleDenom;
339 invfscale /= scaleDenom;
343 invfscale = -invfscale;
354 TQ_INT32 extraLen = (support+256)>>8 + 1;
356 TQ_UINT8 *tmpLine =
new TQ_UINT8[(srcLen +2*extraLen)* pixelSize];
357 TQ_CHECK_PTR(tmpLine);
359 TQ_UINT8 *tmpSel =
new TQ_UINT8[srcLen+2*extraLen];
360 TQ_CHECK_PTR(tmpSel);
363 const TQ_UINT8 **colors =
new const TQ_UINT8 *[2*support+1];
366 FilterValues *filterWeights =
new FilterValues[256];
368 for(
int center = 0; center<256; ++center)
370 TQ_INT32 begin = (255 + center - support)>>8;
371 TQ_INT32 span = ((center + support)>>8) - begin + 1;
372 TQ_INT32 t = (((begin<<8) - center) * invfscale)>>8;
373 TQ_INT32 dt = invfscale;
374 filterWeights[center].weight =
new TQ_UINT8[span];
377 for(
int num = 0; num<span; ++num)
379 TQ_UINT32 tmpw = filterStrategy->intValueAt(t) * invfscale;
382 filterWeights[center].weight[num] = tmpw;
390 double fixfactor= 255.0/sum;
392 for(
int num = 0; num<span; ++num)
394 filterWeights[center].weight[num] = int(filterWeights[center].weight[num] * fixfactor);
395 sum+=filterWeights[center].weight[num];
401 while(sum<255 && num*2<span)
403 filterWeights[center].weight[span/2 + num]++;
405 if(sum<255 && num<span/2)
407 filterWeights[center].weight[span/2 - num - 1]++;
414 filterWeights[center].numWeights = span;
417 for(lineNum = firstLine; lineNum < firstLine+numLines; lineNum++)
420 dstStart = srcStart * scale / scaleDenom - dstLen + dx;
422 dstStart = (srcStart) * scale / scaleDenom + dx;
424 shearFracOffset = -int( 256 * (lineNum * shear - floor(lineNum * shear)));
425 dstStart += int(floor(lineNum * shear));
428 T srcIt = createIterator <T>(src, srcStart - extraLen, lineNum, srcLen+2*extraLen);
430 while(!srcIt.isDone())
434 data = srcIt.rawData();
435 memcpy(&tmpLine[i*pixelSize], data, pixelSize);
437 if(srcIt.isSelected())
450 T dstIt = createIterator <T>(dst, dstStart, lineNum, dstLen);
451 T dstSelIt = createIterator <T>(dstSelection, dstStart, lineNum, dstLen);
454 while(!dstIt.isDone())
457 center = ((i<<8) * scaleDenom) / scale;
461 center = ((i * scaleDenom) / scale)<<8;
463 center = ((i<<8)/scale * scaleDenom) / scale;
469 center += 128*scaleDenom/scale;
470 center += (extraLen<<8) + shearFracOffset;
473 begin = (255 + center - support)>>8;
474 end = (center + support)>>8;
477 TQ_UINT8 selectedness = tmpSel[center>>8];
481 for(
int srcpos = begin; srcpos <= end; ++srcpos)
483 colors[num] = &tmpLine[srcpos*pixelSize];
486 data = dstIt.rawData();
487 cs->
mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data);
490 if(fixBorderAlpha && (i==0 || i==dstLen-1))
493 data = dstSelIt.rawData();
494 *data = selectedness;
503 m_progressStep += dstLen;
504 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
506 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
507 emit notifyProgress(m_lastProgressReport);
509 if (m_cancelRequested) {
516 delete [] filterWeights;
519bool KisTransformWorker::run()
522 m_cancelRequested =
false;
524 m_progress->setSubject(
this,
true,
true);
525 m_progressTotalSteps = 0;
528 if(m_dev->hasSelection())
529 r = m_dev->selection()->selectedExactRect();
531 r = m_dev->exactBounds();
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;
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;
547 rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI;
549 rotation = fmod(rotation, 2*M_PI);
550 int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3;
558 m_progressTotalSteps = 0;
565 m_progressTotalSteps = r.width() * r.height();
569 m_progressTotalSteps = r.width() * r.height();
572 rotation -= -M_PI/2 + 2*M_PI;
576 m_progressTotalSteps = r.width() * r.height();
581 yshear = sin(rotation);
582 xshear = -tan(rotation/2);
583 xtranslate -= int(xshear*ytranslate);
586 m_progressTotalSteps += int(yscale * r.width() * r.height());
587 m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear));
589 m_lastProgressReport=0;
598 rotateRight90(srcdev, tmpdev1);
602 rotate180(srcdev, tmpdev1);
606 rotateLeft90(srcdev, tmpdev1);
612 if(rotation == 0.0 && xscale == 1.0 && yscale == 1.0)
618 rotateNone(srcdev, tmpdev1);
621 if(m_dev->hasSelection())
622 m_dev->selection()->clear();
624 srcdev->move(srcdev->getX() + xtranslate, srcdev->getY() + ytranslate);
625 rotateNone(srcdev, m_dev);
628 emit notifyProgressDone();
629 m_dev->emitSelectionChanged();
631 return m_cancelRequested;
634 if ( m_cancelRequested) {
635 emit notifyProgressDone();
639 transformPass <KisHLineIteratorPixel>(srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter, m_fixBorderAlpha);
640 if(m_dev->hasSelection())
641 m_dev->selection()->clear();
643 if ( m_cancelRequested) {
644 emit notifyProgressDone();
649 transformPass <KisVLineIteratorPixel>(tmpdev2.data(), tmpdev3.data(), yscale, yshear, ytranslate, m_filter, m_fixBorderAlpha);
651 if(m_dev->hasSelection())
652 m_dev->selection()->clear();
654 if ( m_cancelRequested) {
655 emit notifyProgressDone();
660 transformPass <KisHLineIteratorPixel>(tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter, m_fixBorderAlpha);
664 tmpdev3->move(tmpdev3->getX() + xtranslate, tmpdev3->getY());
665 rotateNone(tmpdev3, m_dev);
668 if (m_dev->parentLayer()) {
669 m_dev->parentLayer()->setDirty();
672 emit notifyProgressDone();
673 m_dev->emitSelectionChanged();
675 return m_cancelRequested;
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...