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 Q_INT32 support = filterStrategy->intSupport();
00238 Q_INT32 dstLen, dstStart;
00239 Q_INT32 invfscale = 256;
00240
00241
00242 if(abs(scale) < scaleDenom)
00243 {
00244 support *= scaleDenom;
00245 support /= scale;
00246
00247 invfscale *= scale;
00248 invfscale /= scaleDenom;
00249 if(scale < 0)
00250 {
00251 support = -support;
00252 invfscale = -invfscale;
00253 }
00254 }
00255
00256
00257 if(scale < 0)
00258 dstLen = -srcLen * scale / scaleDenom;
00259 else
00260 dstLen = srcLen * scale / scaleDenom;
00261
00262
00263 Q_INT32 extraLen = (support+256)>>8;
00264
00265 Q_UINT8 *tmpLine = new Q_UINT8[(srcLen +2*extraLen)* pixelSize];
00266 Q_CHECK_PTR(tmpLine);
00267
00268 Q_UINT8 *tmpSel = new Q_UINT8[srcLen+2*extraLen];
00269 Q_CHECK_PTR(tmpSel);
00270
00271
00272 const Q_UINT8 **colors = new const Q_UINT8 *[2*support+1];
00273
00274
00275 FilterValues *filterWeights = new FilterValues[256];
00276
00277 for(int center = 0; center<256; ++center)
00278 {
00279 Q_INT32 begin = (255 + center - support)>>8;
00280 Q_INT32 span = ((center + support)>>8) - begin + 1;
00281 Q_INT32 t = (((begin<<8) - center) * invfscale)>>8;
00282 Q_INT32 dt = invfscale;
00283 filterWeights[center].weight = new Q_UINT8[span];
00284
00285 int sum=0;
00286 for(int num = 0; num<span; ++num)
00287 {
00288 Q_UINT32 tmpw = filterStrategy->intValueAt(t) * invfscale;
00289
00290 tmpw >>=8;
00291 filterWeights[center].weight[num] = tmpw;
00292
00293 t += dt;
00294 sum+=tmpw;
00295 }
00296
00297 if(sum!=255)
00298 {
00299 double fixfactor= 255.0/sum;
00300 sum=0;
00301 for(int num = 0; num<span; ++num)
00302 {
00303 filterWeights[center].weight[num] = int(filterWeights[center].weight[num] * fixfactor);
00304 sum+=filterWeights[center].weight[num];
00305 }
00306 }
00307
00308
00309 filterWeights[center].numWeights = span;
00310 }
00311
00312 for(lineNum = firstLine; lineNum < firstLine+numLines; lineNum++)
00313 {
00314 if(scale < 0)
00315 dstStart = srcStart * scale / scaleDenom - dstLen + dx;
00316 else
00317 dstStart = (srcStart) * scale / scaleDenom + dx;
00318
00319 shearFracOffset = -int( 256 * (lineNum * shear - floor(lineNum * shear)));
00320 dstStart += int(floor(lineNum * shear));
00321
00322
00323 T srcIt = createIterator <T>(src, srcStart - extraLen, lineNum, srcLen+2*extraLen);
00324 int i = 0;
00325 while(!srcIt.isDone())
00326 {
00327 Q_UINT8 *data;
00328
00329 if(srcIt.isSelected())
00330 {
00331 data = srcIt.rawData();
00332 memcpy(&tmpLine[i*pixelSize], data, pixelSize);
00333
00334
00335 cs->setAlpha(data, 0, 1);
00336
00337 tmpSel[i] = 255;
00338 }
00339 else
00340 tmpSel[i] = 0;
00341 ++srcIt;
00342 i++;
00343 }
00344
00345 T dstIt = createIterator <T>(dst, dstStart, lineNum, dstLen);
00346 T dstSelIt = createIterator <T>(dstSelection, dstStart, lineNum, dstLen);
00347
00348 i=0;
00349 while(!dstIt.isDone())
00350 {
00351 if(scale < 0)
00352 center = (srcLen<<8) + (((i<<8)) * scaleDenom) / scale;
00353 else
00354 center = (((i<<8)) * scaleDenom) / scale;
00355
00356 center += (extraLen<<8) + shearFracOffset;
00357
00358
00359 begin = (255 + center - support)>>8;
00360 end = (center + support)>>8;
00361
00363 Q_UINT8 selectedness = tmpSel[center>>8];
00364 if(selectedness)
00365 {
00366 int num=0;
00367 for(int srcpos = begin; srcpos <= end; ++srcpos)
00368 {
00369 colors[num] = &tmpLine[srcpos*pixelSize];
00370 num++;
00371 }
00372 data = dstIt.rawData();
00373 cs->mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data);
00374 data = dstSelIt.rawData();
00375 *data = selectedness;
00376 }
00377
00378 ++dstSelIt;
00379 ++dstIt;
00380 i++;
00381 }
00382
00383
00384 m_progressStep += dstLen;
00385 if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps)
00386 {
00387 m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
00388 emit notifyProgress(m_lastProgressReport);
00389 }
00390 if (m_cancelRequested) {
00391 break;
00392 }
00393 }
00394 delete [] colors;
00395 delete [] tmpLine;
00396 delete [] tmpSel;
00397 delete [] filterWeights;
00398 }
00399
00400 bool KisTransformWorker::run()
00401 {
00402
00403 m_cancelRequested = false;
00404 if(m_progress)
00405 m_progress->setSubject(this, true, true);
00406 m_progressTotalSteps = 0;
00407 m_progressStep = 0;
00408 QRect r;
00409 if(m_dev->hasSelection())
00410 r = m_dev->selection()->selectedExactRect();
00411 else
00412 r = m_dev->exactBounds();
00413
00414 KisPaintDeviceSP tmpdev1 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev1");;
00415 KisPaintDeviceSP tmpdev2 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00416 KisPaintDeviceSP tmpdev3 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");;
00417 KisPaintDeviceSP srcdev = m_dev;
00418
00419 double xscale = m_xscale;
00420 double yscale = m_yscale;
00421 double xshear = m_xshear;
00422 double yshear = m_yshear;
00423 double rotation = m_rotation;
00424 Q_INT32 xtranslate = m_xtranslate;
00425 Q_INT32 ytranslate = m_ytranslate;
00426
00427 if(rotation < 0.0)
00428 rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI;
00429 else
00430 rotation = fmod(rotation, 2*M_PI);
00431 int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3;
00432
00433 double tmp;
00434 switch(rotQuadrant)
00435 {
00436 case 0:
00437 break;
00438 case 1:
00439 rotateRight90(srcdev, tmpdev1);
00440 srcdev = tmpdev1;
00441 rotation -= M_PI/2;
00442 tmp = xscale;
00443 xscale=yscale;
00444 yscale=tmp;
00445 break;
00446 case 2:
00447 rotate180(srcdev, tmpdev1);
00448 srcdev = tmpdev1;
00449 rotation -= M_PI;
00450 break;
00451 case 3:
00452 rotateLeft90(srcdev, tmpdev1);
00453 srcdev = tmpdev1;
00454 rotation += M_PI/2 + 2*M_PI;
00455 tmp = xscale;
00456 xscale = yscale;
00457 yscale = tmp;
00458 break;
00459 default:
00460 break;
00461 }
00462
00463 yshear = sin(rotation);
00464 xshear = -tan(rotation/2);
00465 xtranslate -= int(xshear*ytranslate);
00466
00467 m_progressTotalSteps = int(yscale * r.width() * r.height());
00468 m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear));
00469
00470 m_lastProgressReport=0;
00471
00472 if ( m_cancelRequested) {
00473 emit notifyProgressDone();
00474 return false;
00475 }
00476
00477 transformPass <KisHLineIteratorPixel>(srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter);
00478 if(m_dev->hasSelection())
00479 m_dev->selection()->clear();
00480
00481 if ( m_cancelRequested) {
00482 emit notifyProgressDone();
00483 return false;
00484 }
00485
00486 transformPass <KisVLineIteratorPixel>(tmpdev2, tmpdev3, yscale, yshear, ytranslate, m_filter);
00487 if(m_dev->hasSelection())
00488 m_dev->selection()->clear();
00489
00490 if ( m_cancelRequested) {
00491 emit notifyProgressDone();
00492 return false;
00493 }
00494
00495 transformPass <KisHLineIteratorPixel>(tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter);
00496 if (m_dev->parentLayer()) {
00497 m_dev->parentLayer()->setDirty();
00498 }
00499
00500
00501 emit notifyProgressDone();
00502 m_dev->emitSelectionChanged();
00503
00504 return m_cancelRequested;
00505 }