00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <cfloat>
00022
00023 #include "qbrush.h"
00024 #include "qcolor.h"
00025 #include "qfontinfo.h"
00026 #include "qfontmetrics.h"
00027 #include "qpen.h"
00028 #include "qregion.h"
00029 #include "qwmatrix.h"
00030 #include <qimage.h>
00031 #include <qmap.h>
00032 #include <qpainter.h>
00033 #include <qpixmap.h>
00034 #include <qpointarray.h>
00035 #include <qrect.h>
00036 #include <qstring.h>
00037
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040
00041 #include <qcolor.h>
00042
00043 #include "kis_brush.h"
00044 #include "kis_global.h"
00045 #include "kis_image.h"
00046 #include "kis_iterators_pixel.h"
00047 #include "kis_layer.h"
00048 #include "kis_paint_device.h"
00049 #include "kis_painter.h"
00050 #include "kis_pattern.h"
00051 #include "kis_rect.h"
00052 #include "kis_colorspace.h"
00053 #include "kis_types.h"
00054 #include "kis_vec.h"
00055 #include "kis_selection.h"
00056 #include "kis_convolution_painter.h"
00057
00058
00059 KisKernelSP KisKernel::fromQImage(const QImage& img)
00060 {
00061 KisKernelSP k = new KisKernel;
00062 k->width = img.width();
00063 k->height = img.height();
00064 k->offset = 0;
00065 uint count = k->width * k->height;
00066 k->data = new Q_INT32[count];
00067 Q_INT32* itData = k->data;
00068 Q_UINT8* itImg = img.bits();
00069 k->factor = 0;
00070 for(uint i = 0; i < count; ++i , ++itData, itImg+=4)
00071 {
00072 *itData = 255 - ( *itImg + *(itImg+1) + *(itImg+2) ) / 3;
00073 k->factor += *itData;
00074 }
00075 return k;
00076 }
00077
00078
00079 KisConvolutionPainter::KisConvolutionPainter()
00080 : super()
00081 {
00082 }
00083
00084 KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device) : super(device)
00085 {
00086 }
00087
00088 void KisConvolutionPainter::applyMatrix(KisKernelSP kernel, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h,
00089 KisConvolutionBorderOp borderOp,
00090 KisChannelInfo::enumChannelFlags channelFlags )
00091 {
00092
00093 if (m_device->hasSelection()) {
00094
00095 QRect r = m_device->selection()->selectedRect().intersect(QRect(x, y, w, h));
00096 x = r.x();
00097 y = r.y();
00098 w = r.width();
00099 h = r.height();
00100
00101 }
00102
00103 if ( w == 0 && h == 0 ) return;
00104
00105
00106 Q_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh;
00107 kw = kernel->width;
00108 kh = kernel->height;
00109 khalfWidth = (kw - 1) / 2;
00110 khalfHeight = (kh - 1) / 2;
00111
00112 xLastMinuskhw = x + (w - khalfWidth);
00113 yLastMinuskhh = y + (h - khalfHeight);
00114
00115
00116 if (w < kw || h < kh || (kw&1) == 0 || (kh&1) == 0 || kernel->factor == 0 ) return;
00117
00118 m_cancelRequested = false;
00119 int lastProgressPercent = 0;
00120 emit notifyProgress(0);
00121
00122 KisColorSpace * cs = m_device->colorSpace();
00123
00124
00125 switch (borderOp) {
00126 case BORDER_DEFAULT_FILL :
00127 break;
00128 case BORDER_REPEAT:
00129 applyMatrixRepeat(kernel, x, y, w, h, channelFlags);
00130 return;
00131 case BORDER_WRAP:
00132 case BORDER_AVOID:
00133 default :
00134 x += khalfWidth;
00135 y += khalfHeight;
00136 w -= kw - 1;
00137 h -= kh - 1;
00138 }
00139
00140
00141
00142 int cacheSize = kw * kh;
00143 int cdepth = cs -> pixelSize();
00144 Q_UINT8** pixelPtrCache = new Q_UINT8*[cacheSize];
00145 for (int i = 0; i < cacheSize; i++)
00146 pixelPtrCache[i] = new Q_UINT8[cdepth];
00147
00148
00149
00150 int row = y;
00151
00152 for (; row < y + h; ++row) {
00153
00154
00155 int col = x;
00156
00157 KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true);
00158 bool needFull = true;
00159 while (!hit.isDone()) {
00160
00161
00162
00163 if(needFull)
00164 {
00165 Q_INT32 i = 0;
00166 for (Q_INT32 krow = 0; krow < kh; ++krow) {
00167
00168
00169
00170
00171
00172
00173 KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, (row - khalfHeight) + krow, kw, false);
00174 while (!kit.isDone()) {
00175 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00176 ++kit;
00177 ++i;
00178 }
00179 }
00180 needFull = false;
00181 Q_ASSERT (i==kw*kh);
00182 } else {
00183 for (Q_INT32 krow = 0; krow < kh; ++krow) {
00184 Q_UINT8** d = pixelPtrCache + krow * kw;
00185
00186 for (int i = 0; i < (kw-1); i++) {
00187 memcpy(d[i], d[i+1], cdepth);
00188 }
00189 }
00190 Q_INT32 i = kw - 1;
00191 KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, row - khalfHeight, kh, false);
00192 while (!kit.isDone()) {
00193 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00194 ++kit;
00195 i += kw;
00196 }
00197 }
00198 if (hit.isSelected()) {
00199 cs->convolveColors(pixelPtrCache, kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh);
00200
00201 }
00202 ++col;
00203 ++hit;
00204 }
00205
00206 int progressPercent = 100 - ((((y + h) - row) * 100) / h);
00207
00208 if (progressPercent > lastProgressPercent) {
00209 emit notifyProgress(progressPercent);
00210 lastProgressPercent = progressPercent;
00211
00212 if (m_cancelRequested) {
00213 for (int i = 0; i < cacheSize; i++)
00214 delete[] pixelPtrCache[i];
00215 delete[] pixelPtrCache;
00216
00217 return;
00218 }
00219 }
00220
00221 }
00222
00223 addDirtyRect(QRect(x, y, w, h));
00224
00225 emit notifyProgressDone();
00226
00227 for (int i = 0; i < cacheSize; i++)
00228 delete[] pixelPtrCache[i];
00229 delete[] pixelPtrCache;
00230 }
00231
00232 void KisConvolutionPainter::applyMatrixRepeat(KisKernelSP kernel, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h,
00233 KisChannelInfo::enumChannelFlags channelFlags)
00234 {
00235 int lastProgressPercent = 0;
00236
00237 Q_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh;
00238 kw = kernel->width;
00239 kh = kernel->height;
00240 khalfWidth = (kw - 1) / 2;
00241 khalfHeight = (kh - 1) / 2;
00242
00243 xLastMinuskhw = x + (w - khalfWidth);
00244 yLastMinuskhh = y + (h - khalfHeight);
00245
00246 KisColorSpace * cs = m_device->colorSpace();
00247
00248
00249
00250 int cacheSize = kw * kh;
00251 int cdepth = cs -> pixelSize();
00252 Q_UINT8** pixelPtrCache = new Q_UINT8*[cacheSize];
00253 for (int i = 0; i < cacheSize; i++)
00254 pixelPtrCache[i] = new Q_UINT8[cdepth];
00255
00256
00257 int row = y;
00258
00259 for (; row < y + h; ++row) {
00260
00261
00262 int col = x;
00263
00264 KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true);
00265 bool needFull = true;
00266
00267 Q_INT32 itStart = row - khalfHeight;
00268 Q_INT32 itH = kh;
00269 if(itStart < 0)
00270 {
00271 itH += itStart;
00272 itStart = 0;
00273 } else if(itStart + kh > yLastMinuskhh)
00274 {
00275 itH -= itStart + kh - yLastMinuskhh;
00276 }
00277 KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, itStart, itH, false);
00278 while (!hit.isDone()) {
00279
00280
00281
00282 if(needFull)
00283 {
00284 Q_INT32 i = 0;
00285 Q_INT32 krow = 0;
00286 if( row < khalfHeight )
00287 {
00288
00289
00290 if( x < khalfWidth)
00291 {
00292 Q_INT32 kcol = 0;
00293 KisHLineIteratorPixel kit = m_device->createHLineIterator(0, 0, kw, false);
00294 for(; kcol < (khalfWidth - x) + 1; ++kcol)
00295 {
00296 memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth);
00297 }
00298 for(; kcol < kw; ++kcol)
00299 {
00300 ++kit;
00301 memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth);
00302 }
00303 } else {
00304 uint kcol = 0;
00305 KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, 0, kw, false);
00306 while (!kit.isDone()) {
00307 memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth);
00308 ++kit;
00309 ++kcol;
00310 }
00311 }
00312 krow = 1;
00313 for(;krow < (khalfHeight - row); ++krow)
00314 {
00315
00316 for (int i = 0; i < kw; i++)
00317 memcpy(pixelPtrCache[krow * kw + i], pixelPtrCache[i], cdepth);
00318 }
00319 i = krow * kw;
00320 }
00321 Q_INT32 itH = kh;
00322 if(row + khalfHeight > yLastMinuskhh)
00323 {
00324 itH += yLastMinuskhh - row - khalfHeight;
00325 }
00326 for (; krow < itH; ++krow) {
00327
00328
00329
00330
00331
00332
00333 Q_INT32 itHStart = col - khalfWidth;
00334 Q_INT32 itW = kw;
00335 if(itHStart < 0)
00336 {
00337 itW += itHStart;
00338 itHStart = 0;
00339 }
00340 KisHLineIteratorPixel kit = m_device->createHLineIterator(itHStart, (row - khalfHeight) + krow, itW, false);
00341 if( col < khalfWidth )
00342 {
00343 for(; i < krow * kw + ( kw - itW ); i+= 1)
00344 {
00345 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00346 }
00347 }
00348 while (!kit.isDone()) {
00349 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00350 ++kit;
00351 ++i;
00352 }
00353 }
00354 Q_INT32 lastvalid = i - kw;
00355 for(; krow < kh; ++krow) {
00356
00357 for (int i = 0; i < kw; i++)
00358 memcpy(pixelPtrCache[krow * kw + i], pixelPtrCache[lastvalid + i],
00359 cdepth);
00360 }
00361 needFull = false;
00362 } else {
00363
00364
00365
00366
00367
00368
00369
00370 Q_UINT8* firstincache = pixelPtrCache[0];
00371 memmove(pixelPtrCache, pixelPtrCache + 1, (cacheSize - 1) * sizeof(Q_UINT8*) );
00372 pixelPtrCache[cacheSize - 1] = firstincache;
00373 if(col < xLastMinuskhw)
00374 {
00375 Q_INT32 i = kw - 1;
00376
00377 kit.nextCol();
00378 if( row < khalfHeight )
00379 {
00380 for(; i < (khalfHeight- row ) * kw; i+=kw)
00381 {
00382 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00383 }
00384 }
00385 while (!kit.isDone()) {
00386 memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth);
00387 ++kit;
00388 i += kw;
00389 }
00390 Q_INT32 lastvalid = i - kw;
00391 for(;i < kw*kh; i+=kw)
00392 {
00393 memcpy(pixelPtrCache[i], pixelPtrCache[lastvalid], cdepth);
00394 }
00395 }
00396 }
00397 if (hit.isSelected()) {
00398 cs->convolveColors(pixelPtrCache, kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh);
00399 }
00400 ++col;
00401 ++hit;
00402 }
00403
00404 int progressPercent = 100 - ((((y + h) - row) * 100) / h);
00405
00406 if (progressPercent > lastProgressPercent) {
00407 emit notifyProgress(progressPercent);
00408 lastProgressPercent = progressPercent;
00409
00410 if (m_cancelRequested) {
00411 for (int i = 0; i < cacheSize; i++)
00412 delete[] pixelPtrCache[i];
00413 delete[] pixelPtrCache;
00414 return;
00415 }
00416 }
00417
00418 }
00419
00420 addDirtyRect(QRect(x, y, w, h));
00421
00422 emit notifyProgressDone();
00423 for (int i = 0; i < cacheSize; i++)
00424 delete[] pixelPtrCache[i];
00425 delete[] pixelPtrCache;
00426 }