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