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
00032 KisTransformWorker::KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale,
00033 double xshear, double yshear, double rotation,
00034 Q_INT32 xtranslate, Q_INT32 ytranslate,
00035 KisProgressDisplayInterface *progress, KisFilterStrategy *filter)
00036 {
00037 m_dev= dev;
00038 m_xscale = xscale;
00039 m_yscale = yscale;
00040 m_xshear = xshear;
00041 m_yshear = yshear;
00042 m_rotation = rotation,
00043 m_xtranslate = xtranslate;
00044 m_ytranslate = ytranslate;
00045 m_progress = progress;
00046 m_filter = filter;
00047 }
00048
00049 void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00050 {
00051 KisSelectionSP dstSelection;
00052 Q_INT32 pixelSize = src->pixelSize();
00053 QRect r;
00054 KisColorSpace *cs = src->colorSpace();
00055
00056 if(src->hasSelection())
00057 {
00058 r = src->selection()->selectedExactRect();
00059 dstSelection = dst->selection();
00060 }
00061 else
00062 {
00063 r = src->exactBounds();
00064 dstSelection = new KisSelection(dst);
00065 }
00066
00067 for (Q_INT32 y = r.bottom(); y >= r.top(); --y) {
00068 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
00069 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
00070 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(-y, r.x(), r.width(), true);
00071
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 }
00085 }
00086
00087 void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00088 {
00089 kdDebug() << "rotateLeft90 called\n";
00090 KisSelectionSP dstSelection;
00091 Q_INT32 pixelSize = src->pixelSize();
00092 QRect r;
00093 KisColorSpace *cs = src->colorSpace();
00094
00095 if(src->hasSelection())
00096 {
00097 r = src->selection()->selectedExactRect();
00098 dstSelection = dst->selection();
00099 }
00100 else
00101 {
00102 r = src->exactBounds();
00103 dstSelection = new KisSelection(dst);
00104 }
00105 Q_INT32 x = 0;
00106
00107 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00108
00109 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true);
00110 KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
00111 KisVLineIterator dstSelIt = dstSelection->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
00112
00113 hit += r.width() - 1;
00114 while (!vit.isDone()) {
00115 if (hit.isSelected()) {
00116 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00117
00118
00119 cs->setAlpha(hit.rawData(), 0, 1);
00120 }
00121 *(dstSelIt.rawData()) = hit.selectedness();
00122 --hit;
00123 ++vit;
00124 ++dstSelIt;
00125 }
00126 ++x;
00127 }
00128 }
00129
00130 void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst)
00131 {
00132 KisSelectionSP dstSelection;
00133 Q_INT32 pixelSize = src->pixelSize();
00134 QRect r;
00135 KisColorSpace *cs = src->colorSpace();
00136
00137 if(src->hasSelection())
00138 {
00139 r = src->selection()->selectedExactRect();
00140 dstSelection = dst->selection();
00141 }
00142 else
00143 {
00144 r = src->exactBounds();
00145 dstSelection = new KisSelection(dst);
00146 }
00147
00148 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00149 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), true);
00150 KisHLineIterator dstIt = dst->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
00151 KisHLineIterator dstSelIt = dstSelection->createHLineIterator(-r.x() - r.width(), -y, r.width(), true);
00152
00153 srcIt += r.width() - 1;
00154 while (!dstIt.isDone()) {
00155 if (srcIt.isSelected()) {
00156 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
00157
00158
00159 cs->setAlpha(srcIt.rawData(), 0, 1);
00160 }
00161 *(dstSelIt.rawData()) = srcIt.selectedness();
00162 --srcIt;
00163 ++dstIt;
00164 ++dstSelIt;
00165 }
00166 }
00167 }
00168
00169 template <class iter> iter createIterator(KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len);
00170
00171 template <> KisHLineIteratorPixel createIterator <KisHLineIteratorPixel>
00172 (KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len)
00173 {
00174 return dev->createHLineIterator(start, lineNum, len, true);
00175 }
00176
00177 template <> KisVLineIteratorPixel createIterator <KisVLineIteratorPixel>
00178 (KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len)
00179 {
00180 return dev->createVLineIterator(lineNum, start, len, true);
00181 }
00182
00183 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);
00184
00185 template <> void calcDimensions <KisHLineIteratorPixel>
00186 (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines, Q_INT32 &srcStartData, Q_INT32 &srcLenData)
00187 {
00188 dev->exactBounds(srcStartData, firstLine, srcLenData, numLines);
00189 if(dev->hasSelection())
00190 {
00191 QRect r = dev->selection()->selectedExactRect();
00192 r.rect(&srcStart, &firstLine, &srcLen, &numLines);
00193 }
00194 else
00195 {
00196 srcStart = srcStartData;
00197 srcLen = srcLenData;
00198 }
00199 }
00200
00201 template <> void calcDimensions <KisVLineIteratorPixel>
00202 (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines, Q_INT32 &srcStartData, Q_INT32 &srcLenData)
00203 {
00204 dev->exactBounds(firstLine, srcStartData, numLines, srcLenData);
00205 if(dev->hasSelection())
00206 {
00207 QRect r = dev->selection()->selectedExactRect();
00208 r.rect(&firstLine, &srcStart, &numLines, &srcLen);
00209 }
00210 else
00211 {
00212 srcStart = srcStartData;
00213 srcLen = srcLenData;
00214 }
00215 }
00216
00217 struct FilterValues
00218 {
00219 Q_UINT8 numWeights;
00220 Q_UINT8 *weight;
00221 ~FilterValues() {delete [] weight;}
00222 };
00223
00224 template <class T> void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, double floatscale, double shear, Q_INT32 dx, KisFilterStrategy *filterStrategy)
00225 {
00226 Q_INT32 lineNum,srcStart,firstLine,srcLen,numLines,srcStartData,srcLenData;
00227 Q_INT32 center, begin, end;
00228 Q_UINT8 *data;
00229 Q_UINT8 pixelSize = src->pixelSize();
00230 KisSelectionSP dstSelection;
00231 KisColorSpace * cs = src->colorSpace();
00232 Q_INT32 scale;
00233 Q_INT32 scaleDenom;
00234 Q_INT32 shearFracOffset;
00235
00236 if(src->hasSelection())
00237 dstSelection = dst->selection();
00238 else
00239 dstSelection = new KisSelection(dst);
00240
00241 calcDimensions <T>(src, srcStart, srcLen, firstLine, numLines,srcStartData,srcLenData);
00242
00243 scale = int(floatscale*srcLen);
00244 scaleDenom = srcLen;
00245
00246 if(scaleDenom == 0)
00247 return;
00248
00249 Q_INT32 support = filterStrategy->intSupport();
00250 Q_INT32 dstLen, dstStart;
00251 Q_INT32 invfscale = 256;
00252
00253
00254 if(abs(scale) < scaleDenom)
00255 {
00256 support *= scaleDenom;
00257 support /= scale;
00258
00259 invfscale *= scale;
00260 invfscale /= scaleDenom;
00261 if(scale < 0)
00262 {
00263 support = -support;
00264 invfscale = -invfscale;
00265 }
00266 }
00267
00268
00269 if(scale < 0)
00270 dstLen = - scale;
00271 else
00272 dstLen = scale;
00273
00274
00275 Q_INT32 extraLen = (support+256)>>8 + 1;
00276
00277 Q_UINT8 *tmpLine = new Q_UINT8[(srcLen +2*extraLen)* pixelSize];
00278 Q_CHECK_PTR(tmpLine);
00279
00280 Q_UINT8 *tmpSel = new Q_UINT8[srcLen+2*extraLen];
00281 Q_CHECK_PTR(tmpSel);
00282
00283
00284 const Q_UINT8 **colors = new const Q_UINT8 *[2*support+1];
00285
00286
00287 FilterValues *filterWeights = new FilterValues[256];
00288
00289 for(int center = 0; center<256; ++center)
00290 {
00291 Q_INT32 begin = (255 + center - support)>>8;
00292 Q_INT32 span = ((center + support)>>8) - begin + 1;
00293 Q_INT32 t = (((begin<<8) - center) * invfscale)>>8;
00294 Q_INT32 dt = invfscale;
00295 filterWeights[center].weight = new Q_UINT8[span];
00296
00297 Q_UINT32 sum=0;
00298 for(int num = 0; num<span; ++num)
00299 {
00300 Q_UINT32 tmpw = filterStrategy->intValueAt(t) * invfscale;
00301
00302 tmpw >>=8;
00303 filterWeights[center].weight[num] = tmpw;
00304
00305 t += dt;
00306 sum+=tmpw;
00307 }
00308
00309 if(sum!=255)
00310 {
00311 double fixfactor= 255.0/sum;
00312 sum=0;
00313 for(int num = 0; num<span; ++num)
00314 {
00315 filterWeights[center].weight[num] = int(filterWeights[center].weight[num] * fixfactor);
00316 sum+=filterWeights[center].weight[num];
00317 }
00318 }
00319
00320
00321 int num = 0;
00322 while(sum<255 && num*2<span)
00323 {
00324 filterWeights[center].weight[span/2 + num]++;
00325 ++sum;
00326 if(sum<255 && num<span/2)
00327 {
00328 filterWeights[center].weight[span/2 - num - 1]++;
00329 ++sum;
00330 }
00331 ++num;
00332 }
00333
00334
00335 filterWeights[center].numWeights = span;
00336 }
00337
00338 for(lineNum = firstLine; lineNum < firstLine+numLines; lineNum++)
00339 {
00340 if(scale < 0)
00341 dstStart = srcStart * scale / scaleDenom - dstLen + dx;
00342 else
00343 dstStart = (srcStart) * scale / scaleDenom + dx;
00344
00345 shearFracOffset = -int( 256 * (lineNum * shear - floor(lineNum * shear)));
00346 dstStart += int(floor(lineNum * shear));
00347
00348
00349 T srcIt = createIterator <T>(src, QMAX(srcStart - extraLen, srcStartData), lineNum, srcLen+2*extraLen);
00350 Q_INT32 i = 0;
00351 Q_INT32 x = srcStart - extraLen;
00352 while(i < srcLen + 2*extraLen)
00353 {
00354 Q_UINT8 *data;
00355
00356 data = srcIt.rawData();
00357 memcpy(&tmpLine[i*pixelSize], data, pixelSize);
00358 if(srcIt.isSelected())
00359 {
00360 tmpSel[i] = 255;
00361 }
00362 else
00363 {
00364 tmpSel[i] = 0;
00365 }
00366 if(x >= srcStartData && x < srcStartData + srcLenData - 1)
00367 {
00368
00369 cs->setAlpha(data, 0, 1);
00370 ++srcIt;
00371 }
00372 i++;
00373 x++;
00374 }
00375
00376 T dstIt = createIterator <T>(dst, dstStart, lineNum, dstLen);
00377 T dstSelIt = createIterator <T>(dstSelection, dstStart, lineNum, dstLen);
00378
00379 i=0;
00380 while(!dstIt.isDone())
00381 {
00382 if(scaleDenom<2500)
00383 center = ((i<<8) * scaleDenom) / scale;
00384 else
00385 {
00386 if(scaleDenom<46000)
00387 center = ((i * scaleDenom) / scale)<<8;
00388 else
00389 center = ((i<<8)/scale * scaleDenom) / scale;
00390 }
00391
00392 if(scale < 0)
00393 center += srcLen<<8;
00394
00395 center += 128*scaleDenom/scale;
00396 center += (extraLen<<8) + shearFracOffset;
00397
00398
00399 begin = (255 + center - support)>>8;
00400 end = (center + support)>>8;
00401
00403 Q_UINT8 selectedness = tmpSel[center>>8];
00404 if(selectedness)
00405 {
00406 int num=0;
00407 for(int srcpos = begin; srcpos <= end; ++srcpos)
00408 {
00409 colors[num] = &tmpLine[srcpos*pixelSize];
00410 num++;
00411 }
00412 data = dstIt.rawData();
00413 cs->mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data);
00414 data = dstSelIt.rawData();
00415 *data = selectedness;
00416 }
00417
00418 ++dstSelIt;
00419 ++dstIt;
00420 i++;
00421 }
00422
00423
00424 m_progressStep += dstLen;
00425 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00426 {
00427 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00428 emit notifyProgress(m_lastProgressReport);
00429 }
00430 if (m_cancelRequested) {
00431 break;
00432 }
00433 }
00434 delete [] colors;
00435 delete [] tmpLine;
00436 delete [] tmpSel;
00437 delete [] filterWeights;
00438 }
00439
00440 bool KisTransformWorker::run()
00441 {
00442
00443 m_cancelRequested = false;
00444 if(m_progress)
00445 m_progress->setSubject(this, true, true);
00446 m_progressTotalSteps = 0;
00447 m_progressStep = 0;
00448 QRect r;
00449 if(m_dev->hasSelection())
00450 r = m_dev->selection()->selectedExactRect();
00451 else
00452 r = m_dev->exactBounds();
00453
00454 KisPaintDeviceSP tmpdev1 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev1");;
00455 KisPaintDeviceSP tmpdev2 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00456 KisPaintDeviceSP tmpdev3 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00457 KisPaintDeviceSP srcdev = m_dev;
00458
00459 double xscale = m_xscale;
00460 double yscale = m_yscale;
00461 double xshear = m_xshear;
00462 double yshear = m_yshear;
00463 double rotation = m_rotation;
00464 Q_INT32 xtranslate = m_xtranslate;
00465 Q_INT32 ytranslate = m_ytranslate;
00466
00467 if(rotation < 0.0)
00468 rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI;
00469 else
00470 rotation = fmod(rotation, 2*M_PI);
00471 int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3;
00472
00473 double tmp;
00474 switch(rotQuadrant)
00475 {
00476 case 0:
00477 break;
00478 case 1:
00479 rotateRight90(srcdev, tmpdev1);
00480 srcdev = tmpdev1;
00481 rotation -= M_PI/2;
00482 tmp = xscale;
00483 xscale=yscale;
00484 yscale=tmp;
00485 break;
00486 case 2:
00487 rotate180(srcdev, tmpdev1);
00488 srcdev = tmpdev1;
00489 rotation -= M_PI;
00490 break;
00491 case 3:
00492 rotateLeft90(srcdev, tmpdev1);
00493 srcdev = tmpdev1;
00494 rotation += M_PI/2 + 2*M_PI;
00495 tmp = xscale;
00496 xscale = yscale;
00497 yscale = tmp;
00498 break;
00499 default:
00500 break;
00501 }
00502
00503 yshear = sin(rotation);
00504 xshear = -tan(rotation/2);
00505 xtranslate -= int(xshear*ytranslate);
00506
00507 m_progressTotalSteps = int(yscale * r.width() * r.height());
00508 m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear));
00509
00510 m_lastProgressReport=0;
00511
00512 if ( m_cancelRequested) {
00513 emit notifyProgressDone();
00514 return false;
00515 }
00516
00517 transformPass <KisHLineIteratorPixel>(srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter);
00518 if(m_dev->hasSelection())
00519 m_dev->selection()->clear();
00520
00521 if ( m_cancelRequested) {
00522 emit notifyProgressDone();
00523 return false;
00524 }
00525
00526 if(xshear==0.0)
00527
00528 transformPass <KisVLineIteratorPixel>(tmpdev2.data(), m_dev.data(), yscale, yshear, ytranslate, m_filter);
00529 else
00530 transformPass <KisVLineIteratorPixel>(tmpdev2.data(), tmpdev3.data(), yscale, yshear, ytranslate, m_filter);
00531
00532 if(m_dev->hasSelection())
00533 m_dev->selection()->clear();
00534
00535 if ( m_cancelRequested) {
00536 emit notifyProgressDone();
00537 return false;
00538 }
00539
00540 if (xshear != 0.0)
00541 transformPass <KisHLineIteratorPixel>(tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter);
00542 if (m_dev->parentLayer()) {
00543 m_dev->parentLayer()->setDirty();
00544 }
00545
00546 emit notifyProgressDone();
00547 m_dev->emitSelectionChanged();
00548
00549 return m_cancelRequested;
00550 }