00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <kdebug.h>
00021 #include <klocale.h>
00022
00023 #include "kis_debug_areas.h"
00024 #include "kis_paint_device.h"
00025 #include "kis_selection.h"
00026 #include "kis_transform_worker.h"
00027 #include "kis_progress_display_interface.h"
00028 #include "kis_iterators_pixel.h"
00029 #include "kis_filter_strategy.h"
00030 #include "kis_layer.h"
00031 #include "kis_painter.h"
00032
00033 KisTransformWorker::KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale,
00034 double xshear, double yshear, double rotation,
00035 Q_INT32 xtranslate, Q_INT32 ytranslate,
00036 KisProgressDisplayInterface *progress, KisFilterStrategy *filter, bool fixBorderAlpha)
00037 {
00038 m_dev= dev;
00039 m_xscale = xscale;
00040 m_yscale = yscale;
00041 m_xshear = xshear;
00042 m_yshear = yshear;
00043 m_rotation = rotation,
00044 m_xtranslate = xtranslate;
00045 m_ytranslate = ytranslate;
00046 m_progress = progress;
00047 m_filter = filter;
00048 m_fixBorderAlpha = fixBorderAlpha;
00049 }
00050
00051 void KisTransformWorker::rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00052 {
00053 KisSelectionSP dstSelection;
00054 Q_INT32 pixelSize = src->pixelSize();
00055 QRect r;
00056 KisColorSpace *cs = src->colorSpace();
00057
00058 if(src->hasSelection())
00059 {
00060 r = src->selection()->selectedExactRect();
00061 dstSelection = dst->selection();
00062 }
00063 else
00064 {
00065 r = src->exactBounds();
00066 dstSelection = new KisSelection(dst);
00067 }
00068
00069 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), r.top(), r.width(), true);
00070 KisHLineIterator vit = dst->createHLineIterator(r.x(), r.top(), r.width(), true);
00071 KisHLineIterator dstSelIt = dstSelection->createHLineIterator(r.x(), r.top(), r.width(), true);
00072 for (Q_INT32 i = 0; i < r.height(); ++i) {
00073 while (!hit.isDone()) {
00074 if (hit.isSelected()) {
00075 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00076
00077
00078 cs->setAlpha(hit.rawData(), 0, 1);
00079 }
00080 *(dstSelIt.rawData()) = hit.selectedness();
00081 ++hit;
00082 ++vit;
00083 ++dstSelIt;
00084 }
00085 hit.nextRow();
00086 vit.nextRow();
00087 dstSelIt.nextRow();
00088
00089
00090 m_progressStep += r.width();
00091 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00092 {
00093 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00094 emit notifyProgress(m_lastProgressReport);
00095 }
00096 if (m_cancelRequested) {
00097 break;
00098 }
00099 }
00100 }
00101
00102 void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00103 {
00104 KisSelectionSP dstSelection;
00105 Q_INT32 pixelSize = src->pixelSize();
00106 QRect r;
00107 KisColorSpace *cs = src->colorSpace();
00108
00109 if(src->hasSelection())
00110 {
00111 r = src->selection()->selectedExactRect();
00112 dstSelection = dst->selection();
00113 }
00114 else
00115 {
00116 r = src->exactBounds();
00117 dstSelection = new KisSelection(dst);
00118 }
00119
00120 for (Q_INT32 y = r.bottom(); y >= r.top(); --y) {
00121 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
00122 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
00123 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(-y, r.x(), r.width(), true);
00124
00125 while (!hit.isDone()) {
00126 if (hit.isSelected()) {
00127 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00128
00129
00130 cs->setAlpha(hit.rawData(), 0, 1);
00131 }
00132 *(dstSelIt.rawData()) = hit.selectedness();
00133 ++hit;
00134 ++vit;
00135 ++dstSelIt;
00136 }
00137
00138
00139 m_progressStep += r.width();
00140 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00141 {
00142 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00143 emit notifyProgress(m_lastProgressReport);
00144 }
00145 if (m_cancelRequested) {
00146 break;
00147 }
00148 }
00149 }
00150
00151 void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00152 {
00153 kdDebug() << "rotateLeft90 called\n";
00154 KisSelectionSP dstSelection;
00155 Q_INT32 pixelSize = src->pixelSize();
00156 QRect r;
00157 KisColorSpace *cs = src->colorSpace();
00158
00159 if(src->hasSelection())
00160 {
00161 r = src->selection()->selectedExactRect();
00162 dstSelection = dst->selection();
00163 }
00164 else
00165 {
00166 r = src->exactBounds();
00167 dstSelection = new KisSelection(dst);
00168 }
00169 Q_INT32 x = 0;
00170
00171 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00172
00173 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
00174 KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
00175 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
00176
00177 hit += r.width() - 1;
00178 while (!vit.isDone()) {
00179 if (hit.isSelected()) {
00180 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00181
00182
00183 cs->setAlpha(hit.rawData(), 0, 1);
00184 }
00185 *(dstSelIt.rawData()) = hit.selectedness();
00186 --hit;
00187 ++vit;
00188 ++dstSelIt;
00189 }
00190 ++x;
00191
00192
00193 m_progressStep += r.width();
00194 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00195 {
00196 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00197 emit notifyProgress(m_lastProgressReport);
00198 }
00199 if (m_cancelRequested) {
00200 break;
00201 }
00202 }
00203 }
00204
00205 void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00206 {
00207 kdDebug() << "Rotating 180\n";
00208 KisSelectionSP dstSelection;
00209 Q_INT32 pixelSize = src->pixelSize();
00210 QRect r;
00211 KisColorSpace *cs = src->colorSpace();
00212
00213 if(src->hasSelection())
00214 {
00215 r = src->selection()->selectedExactRect();
00216 dstSelection = dst->selection();
00217 }
00218 else
00219 {
00220 r = src->exactBounds();
00221 dstSelection = new KisSelection(dst);
00222 }
00223
00224 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00225 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), true);
00226 KisHLineIterator dstIt = dst->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
00227 KisHLineIterator dstSelIt = dstSelection->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
00228
00229 srcIt += r.width() - 1;
00230 while (!dstIt.isDone()) {
00231 if (srcIt.isSelected()) {
00232 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
00233
00234
00235 cs->setAlpha(srcIt.rawData(), 0, 1);
00236 }
00237 *(dstSelIt.rawData()) = srcIt.selectedness();
00238 --srcIt;
00239 ++dstIt;
00240 ++dstSelIt;
00241 }
00242
00243
00244 m_progressStep += r.width();
00245 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00246 {
00247 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00248 emit notifyProgress(m_lastProgressReport);
00249 }
00250 if (m_cancelRequested) {
00251 break;
00252 }
00253 }
00254 }
00255
00256 template <class iter> iter createIterator(KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len);
00257
00258 template <> KisHLineIteratorPixel createIterator <KisHLineIteratorPixel>
00259 (KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len)
00260 {
00261 return dev->createHLineIterator(start, lineNum, len, true);
00262 }
00263
00264 template <> KisVLineIteratorPixel createIterator <KisVLineIteratorPixel>
00265 (KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len)
00266 {
00267 return dev->createVLineIterator(lineNum, start, len, true);
00268 }
00269
00270 template <class iter> void calcDimensions (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines);
00271
00272 template <> void calcDimensions <KisHLineIteratorPixel>
00273 (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines)
00274 {
00275 if(dev->hasSelection())
00276 {
00277 QRect r = dev->selection()->selectedExactRect();
00278 r.rect(&srcStart, &firstLine, &srcLen, &numLines);
00279 }
00280 else
00281 dev->exactBounds(srcStart, firstLine, srcLen, numLines);
00282 }
00283
00284 template <> void calcDimensions <KisVLineIteratorPixel>
00285 (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines)
00286 {
00287 if(dev->hasSelection())
00288 {
00289 QRect r = dev->selection()->selectedExactRect();
00290 r.rect(&firstLine, &srcStart, &numLines, &srcLen);
00291 }
00292 else
00293 dev->exactBounds(firstLine, srcStart, numLines, srcLen);
00294 }
00295
00296 struct FilterValues
00297 {
00298 Q_UINT8 numWeights;
00299 Q_UINT8 *weight;
00300 ~FilterValues() {delete [] weight;}
00301 };
00302
00303 template <class T> void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, double floatscale, double shear, Q_INT32 dx, KisFilterStrategy *filterStrategy, bool fixBorderAlpha)
00304 {
00305 Q_INT32 lineNum,srcStart,firstLine,srcLen,numLines;
00306 Q_INT32 center, begin, end;
00307 Q_UINT8 *data;
00308 Q_UINT8 pixelSize = src->pixelSize();
00309 KisSelectionSP dstSelection;
00310 KisColorSpace * cs = src->colorSpace();
00311 Q_INT32 scale;
00312 Q_INT32 scaleDenom;
00313 Q_INT32 shearFracOffset;
00314
00315 if(src->hasSelection())
00316 dstSelection = dst->selection();
00317 else
00318 dstSelection = new KisSelection(dst);
00319
00320 calcDimensions <T>(src, srcStart, srcLen, firstLine, numLines);
00321
00322 scale = int(floatscale*srcLen);
00323 scaleDenom = srcLen;
00324
00325 if(scaleDenom == 0)
00326 return;
00327
00328 Q_INT32 support = filterStrategy->intSupport();
00329 Q_INT32 dstLen, dstStart;
00330 Q_INT32 invfscale = 256;
00331
00332
00333 if(abs(scale) < scaleDenom)
00334 {
00335 support *= scaleDenom;
00336 support /= scale;
00337
00338 invfscale *= scale;
00339 invfscale /= scaleDenom;
00340 if(scale < 0)
00341 {
00342 support = -support;
00343 invfscale = -invfscale;
00344 }
00345 }
00346
00347
00348 if(scale < 0)
00349 dstLen = - scale;
00350 else
00351 dstLen = scale;
00352
00353
00354 Q_INT32 extraLen = (support+256)>>8 + 1;
00355
00356 Q_UINT8 *tmpLine = new Q_UINT8[(srcLen +2*extraLen)* pixelSize];
00357 Q_CHECK_PTR(tmpLine);
00358
00359 Q_UINT8 *tmpSel = new Q_UINT8[srcLen+2*extraLen];
00360 Q_CHECK_PTR(tmpSel);
00361
00362
00363 const Q_UINT8 **colors = new const Q_UINT8 *[2*support+1];
00364
00365
00366 FilterValues *filterWeights = new FilterValues[256];
00367
00368 for(int center = 0; center<256; ++center)
00369 {
00370 Q_INT32 begin = (255 + center - support)>>8;
00371 Q_INT32 span = ((center + support)>>8) - begin + 1;
00372 Q_INT32 t = (((begin<<8) - center) * invfscale)>>8;
00373 Q_INT32 dt = invfscale;
00374 filterWeights[center].weight = new Q_UINT8[span];
00375
00376 Q_UINT32 sum=0;
00377 for(int num = 0; num<span; ++num)
00378 {
00379 Q_UINT32 tmpw = filterStrategy->intValueAt(t) * invfscale;
00380
00381 tmpw >>=8;
00382 filterWeights[center].weight[num] = tmpw;
00383
00384 t += dt;
00385 sum+=tmpw;
00386 }
00387
00388 if(sum!=255)
00389 {
00390 double fixfactor= 255.0/sum;
00391 sum=0;
00392 for(int num = 0; num<span; ++num)
00393 {
00394 filterWeights[center].weight[num] = int(filterWeights[center].weight[num] * fixfactor);
00395 sum+=filterWeights[center].weight[num];
00396 }
00397 }
00398
00399
00400 int num = 0;
00401 while(sum<255 && num*2<span)
00402 {
00403 filterWeights[center].weight[span/2 + num]++;
00404 ++sum;
00405 if(sum<255 && num<span/2)
00406 {
00407 filterWeights[center].weight[span/2 - num - 1]++;
00408 ++sum;
00409 }
00410 ++num;
00411 }
00412
00413
00414 filterWeights[center].numWeights = span;
00415 }
00416
00417 for(lineNum = firstLine; lineNum < firstLine+numLines; lineNum++)
00418 {
00419 if(scale < 0)
00420 dstStart = srcStart * scale / scaleDenom - dstLen + dx;
00421 else
00422 dstStart = (srcStart) * scale / scaleDenom + dx;
00423
00424 shearFracOffset = -int( 256 * (lineNum * shear - floor(lineNum * shear)));
00425 dstStart += int(floor(lineNum * shear));
00426
00427
00428 T srcIt = createIterator <T>(src, srcStart - extraLen, lineNum, srcLen+2*extraLen);
00429 Q_INT32 i = 0;
00430 while(!srcIt.isDone())
00431 {
00432 Q_UINT8 *data;
00433
00434 data = srcIt.rawData();
00435 memcpy(&tmpLine[i*pixelSize], data, pixelSize);
00436
00437 if(srcIt.isSelected())
00438 {
00439
00440 cs->setAlpha(data, 0, 1);
00441 tmpSel[i] = 255;
00442 }
00443 else {
00444 tmpSel[i] = 0;
00445 }
00446 ++srcIt;
00447 i++;
00448 }
00449
00450 T dstIt = createIterator <T>(dst, dstStart, lineNum, dstLen);
00451 T dstSelIt = createIterator <T>(dstSelection, dstStart, lineNum, dstLen);
00452
00453 i=0;
00454 while(!dstIt.isDone())
00455 {
00456 if(scaleDenom<2500)
00457 center = ((i<<8) * scaleDenom) / scale;
00458 else
00459 {
00460 if(scaleDenom<46000)
00461 center = ((i * scaleDenom) / scale)<<8;
00462 else
00463 center = ((i<<8)/scale * scaleDenom) / scale;
00464 }
00465
00466 if(scale < 0)
00467 center += srcLen<<8;
00468
00469 center += 128*scaleDenom/scale;
00470 center += (extraLen<<8) + shearFracOffset;
00471
00472
00473 begin = (255 + center - support)>>8;
00474 end = (center + support)>>8;
00475
00477 Q_UINT8 selectedness = tmpSel[center>>8];
00478 if(selectedness)
00479 {
00480 int num=0;
00481 for(int srcpos = begin; srcpos <= end; ++srcpos)
00482 {
00483 colors[num] = &tmpLine[srcpos*pixelSize];
00484 num++;
00485 }
00486 data = dstIt.rawData();
00487 cs->mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data);
00488
00489
00490 if(fixBorderAlpha && (i==0 || i==dstLen-1))
00491 cs->setAlpha(data, cs->getAlpha(&tmpLine[(center>>8)*pixelSize]), 1);
00492
00493 data = dstSelIt.rawData();
00494 *data = selectedness;
00495 }
00496
00497 ++dstSelIt;
00498 ++dstIt;
00499 i++;
00500 }
00501
00502
00503 m_progressStep += dstLen;
00504 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00505 {
00506 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00507 emit notifyProgress(m_lastProgressReport);
00508 }
00509 if (m_cancelRequested) {
00510 break;
00511 }
00512 }
00513 delete [] colors;
00514 delete [] tmpLine;
00515 delete [] tmpSel;
00516 delete [] filterWeights;
00517 }
00518
00519 bool KisTransformWorker::run()
00520 {
00521
00522 m_cancelRequested = false;
00523 if(m_progress)
00524 m_progress->setSubject(this, true, true);
00525 m_progressTotalSteps = 0;
00526 m_progressStep = 0;
00527 QRect r;
00528 if(m_dev->hasSelection())
00529 r = m_dev->selection()->selectedExactRect();
00530 else
00531 r = m_dev->exactBounds();
00532
00533 KisPaintDeviceSP tmpdev1 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev1");;
00534 KisPaintDeviceSP tmpdev2 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00535 KisPaintDeviceSP tmpdev3 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00536 KisPaintDeviceSP srcdev = m_dev;
00537
00538 double xscale = m_xscale;
00539 double yscale = m_yscale;
00540 double xshear = m_xshear;
00541 double yshear = m_yshear;
00542 double rotation = m_rotation;
00543 Q_INT32 xtranslate = m_xtranslate;
00544 Q_INT32 ytranslate = m_ytranslate;
00545
00546 if(rotation < 0.0)
00547 rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI;
00548 else
00549 rotation = fmod(rotation, 2*M_PI);
00550 int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3;
00551
00552
00553 double tmp;
00554 switch(rotQuadrant)
00555 {
00556 default:
00557 case 0:
00558 m_progressTotalSteps = 0;
00559 break;
00560 case 1:
00561 rotation -= M_PI/2;
00562 tmp = xscale;
00563 xscale=yscale;
00564 yscale=tmp;
00565 m_progressTotalSteps = r.width() * r.height();
00566 break;
00567 case 2:
00568 rotation -= M_PI;
00569 m_progressTotalSteps = r.width() * r.height();
00570 break;
00571 case 3:
00572 rotation -= -M_PI/2 + 2*M_PI;
00573 tmp = xscale;
00574 xscale = yscale;
00575 yscale = tmp;
00576 m_progressTotalSteps = r.width() * r.height();
00577 break;
00578 }
00579
00580
00581 yshear = sin(rotation);
00582 xshear = -tan(rotation/2);
00583 xtranslate -= int(xshear*ytranslate);
00584
00585
00586 m_progressTotalSteps += int(yscale * r.width() * r.height());
00587 m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear));
00588
00589 m_lastProgressReport=0;
00590
00591
00592 switch(rotQuadrant)
00593 {
00594 default:
00595 case 0:
00596 break;
00597 case 1:
00598 rotateRight90(srcdev, tmpdev1);
00599 srcdev = tmpdev1;
00600 break;
00601 case 2:
00602 rotate180(srcdev, tmpdev1);
00603 srcdev = tmpdev1;
00604 break;
00605 case 3:
00606 rotateLeft90(srcdev, tmpdev1);
00607 srcdev = tmpdev1;
00608 break;
00609 }
00610
00611
00612 if(rotation == 0.0 && xscale == 1.0 && yscale == 1.0)
00613 {
00614 if(rotQuadrant==0)
00615 {
00616
00617
00618 rotateNone(srcdev, tmpdev1);
00619 srcdev = tmpdev1;
00620 }
00621 if(m_dev->hasSelection())
00622 m_dev->selection()->clear();
00623
00624 srcdev->move(srcdev->getX() + xtranslate, srcdev->getY() + ytranslate);
00625 rotateNone(srcdev, m_dev);
00626
00627
00628 emit notifyProgressDone();
00629 m_dev->emitSelectionChanged();
00630
00631 return m_cancelRequested;
00632 }
00633
00634 if ( m_cancelRequested) {
00635 emit notifyProgressDone();
00636 return false;
00637 }
00638
00639 transformPass <KisHLineIteratorPixel>(srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter, m_fixBorderAlpha);
00640 if(m_dev->hasSelection())
00641 m_dev->selection()->clear();
00642
00643 if ( m_cancelRequested) {
00644 emit notifyProgressDone();
00645 return false;
00646 }
00647
00648
00649 transformPass <KisVLineIteratorPixel>(tmpdev2.data(), tmpdev3.data(), yscale, yshear, ytranslate, m_filter, m_fixBorderAlpha);
00650
00651 if(m_dev->hasSelection())
00652 m_dev->selection()->clear();
00653
00654 if ( m_cancelRequested) {
00655 emit notifyProgressDone();
00656 return false;
00657 }
00658
00659 if (xshear != 0.0)
00660 transformPass <KisHLineIteratorPixel>(tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter, m_fixBorderAlpha);
00661 else
00662 {
00663
00664 tmpdev3->move(tmpdev3->getX() + xtranslate, tmpdev3->getY());
00665 rotateNone(tmpdev3, m_dev);
00666 }
00667
00668 if (m_dev->parentLayer()) {
00669 m_dev->parentLayer()->setDirty();
00670 }
00671
00672 emit notifyProgressDone();
00673 m_dev->emitSelectionChanged();
00674
00675 return m_cancelRequested;
00676 }