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