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 if (m_device->selection()->isTotallyUnselected(QRect(x, y, w, h))) {
00096 return;
00097 }
00098
00099 QRect r = m_device->selection()->extent().intersect(QRect(x, y, w, h));
00100 x = r.x();
00101 y = r.y();
00102 w = r.width();
00103 h = r.height();
00104
00105 }
00106
00107
00108 Q_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh;
00109 kw = kernel->width;
00110 kh = kernel->height;
00111 khalfWidth = (kw - 1) / 2;
00112 khalfHeight = (kh - 1) / 2;
00113
00114 xLastMinuskhw = x + (w - khalfWidth);
00115 yLastMinuskhh = y + (h - khalfHeight);
00116
00117
00118 if (w < kw || h < kh || (kw&1) == 0 || (kh&1) == 0 || kernel->factor == 0 ) return;
00119
00120 m_cancelRequested = false;
00121 int lastProgressPercent = 0;
00122 emit notifyProgress(0);
00123
00124 KisColorSpace * cs = m_device->colorSpace();
00125
00126
00127 switch (borderOp) {
00128 case BORDER_DEFAULT_FILL :
00129 break;
00130 case BORDER_REPEAT:
00131 applyMatrixRepeat(kernel, x, y, w, h, channelFlags);
00132 return;
00133 case BORDER_WRAP:
00134 case BORDER_AVOID:
00135 default :
00136 x += khalfWidth;
00137 y += khalfHeight;
00138 w -= kw - 1;
00139 h -= kh - 1;
00140 }
00141
00142
00143
00144 QMemArray<Q_UINT8 *> pixelPtrCache(kw * kh);
00145
00146
00147
00148 int row = y;
00149
00150 for (; row < y + h; ++row) {
00151
00152
00153 int col = x;
00154
00155 KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true);
00156 bool needFull = true;
00157 while (!hit.isDone()) {
00158 if (hit.isSelected()) {
00159
00160
00161
00162 if(needFull)
00163 {
00164 Q_INT32 i = 0;
00165 for (Q_INT32 krow = 0; krow < kh; ++krow) {
00166
00167
00168
00169
00170
00171
00172 KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, (row - khalfHeight) + krow, kw, false);
00173 while (!kit.isDone()) {
00174 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00175 ++kit;
00176 ++i;
00177 }
00178 }
00179 needFull = false;
00180 Q_ASSERT (i==kw*kh);
00181 } else {
00182 for (Q_INT32 krow = 0; krow < kh; ++krow) {
00183 Q_UINT8** d = pixelPtrCache.data() + krow * kw;
00184 memmove( d, d + 1, (kw-1)*sizeof(Q_UINT8*));
00185 }
00186 Q_INT32 i = kw - 1;
00187 KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, row - khalfHeight, kh, false);
00188 while (!kit.isDone()) {
00189 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00190 ++kit;
00191 i += kw;
00192 }
00193 }
00194 cs->convolveColors(pixelPtrCache.data(), kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh);
00195
00196 }
00197 ++col;
00198 ++hit;
00199 }
00200
00201 int progressPercent = 100 - ((((y + h) - row) * 100) / h);
00202
00203 if (progressPercent > lastProgressPercent) {
00204 emit notifyProgress(progressPercent);
00205 lastProgressPercent = progressPercent;
00206
00207 if (m_cancelRequested) {
00208 return;
00209 }
00210 }
00211
00212 }
00213
00214 addDirtyRect(QRect(x, y, w, h));
00215
00216 emit notifyProgressDone();
00217 }
00218
00219 void KisConvolutionPainter::applyMatrixRepeat(KisKernelSP kernel, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h,
00220 KisChannelInfo::enumChannelFlags channelFlags)
00221 {
00222 int lastProgressPercent = 0;
00223
00224 Q_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh;
00225 kw = kernel->width;
00226 kh = kernel->height;
00227 khalfWidth = (kw - 1) / 2;
00228 khalfHeight = (kh - 1) / 2;
00229
00230 xLastMinuskhw = x + (w - khalfWidth);
00231 yLastMinuskhh = y + (h - khalfHeight);
00232
00233 KisColorSpace * cs = m_device->colorSpace();
00234
00235
00236
00237 QMemArray<Q_UINT8 *> pixelPtrCache(kw * kh);
00238
00239
00240 int row = y;
00241
00242 for (; row < y + h; ++row) {
00243
00244
00245 int col = x;
00246
00247 KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true);
00248 bool needFull = true;
00249
00250 Q_INT32 itStart = row - khalfHeight;
00251 Q_INT32 itH = kh;
00252 if(itStart < 0)
00253 {
00254 itH += itStart;
00255 itStart = 0;
00256 } else if(itStart + kh > yLastMinuskhh)
00257 {
00258 itH -= itStart + kh - yLastMinuskhh;
00259 }
00260 KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, itStart, itH, false);
00261 while (!hit.isDone()) {
00262 if (hit.isSelected()) {
00263
00264
00265
00266 if(needFull)
00267 {
00268 Q_INT32 i = 0;
00269 Q_INT32 krow = 0;
00270 if( row < khalfHeight )
00271 {
00272
00273
00274 if( x < khalfWidth)
00275 {
00276 Q_INT32 kcol = 0;
00277 KisHLineIteratorPixel kit = m_device->createHLineIterator(0, 0, kw, false);
00278 for(; kcol < (khalfWidth - x) + 1; ++kcol)
00279 {
00280 pixelPtrCache[kcol] = const_cast<Q_UINT8 *>(kit.oldRawData());
00281 }
00282 for(; kcol < kw; ++kcol)
00283 {
00284 ++kit;
00285 pixelPtrCache[kcol] = const_cast<Q_UINT8 *>(kit.oldRawData());
00286 }
00287 } else {
00288 uint kcol = 0;
00289 KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, 0, kw, false);
00290 while (!kit.isDone()) {
00291 pixelPtrCache[kcol] = const_cast<Q_UINT8 *>(kit.oldRawData());
00292 ++kit;
00293 ++kcol;
00294 }
00295 }
00296 krow = 1;
00297 for(;krow < (khalfHeight - row); ++krow)
00298 {
00299 memcpy( pixelPtrCache.data() + krow * kw, pixelPtrCache.data(), kw*sizeof(Q_UINT8*));
00300 }
00301 i = krow * kw;
00302 }
00303 Q_INT32 itH = kh;
00304 if(row + khalfHeight > yLastMinuskhh)
00305 {
00306 itH += yLastMinuskhh - row - khalfHeight;
00307 }
00308 for (; krow < itH; ++krow) {
00309
00310
00311
00312
00313
00314
00315 Q_INT32 itHStart = col - khalfWidth;
00316 Q_INT32 itW = kw;
00317 if(itHStart < 0)
00318 {
00319 itW += itHStart;
00320 itHStart = 0;
00321 }
00322 KisHLineIteratorPixel kit = m_device->createHLineIterator(itHStart, (row - khalfHeight) + krow, itW, false);
00323 if( col < khalfWidth )
00324 {
00325 for(; i < krow * kw + ( kw - itW ); i+= 1)
00326 {
00327 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00328 }
00329 }
00330 while (!kit.isDone()) {
00331 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00332 ++kit;
00333 ++i;
00334 }
00335 }
00336 Q_INT32 lastvalid = i - kw;
00337 for(; krow < kh; ++krow) {
00338 memcpy( pixelPtrCache.data() + krow * kw,
00339 pixelPtrCache.data() + lastvalid,
00340 kw * sizeof(Q_UINT8*));
00341 }
00342 needFull = false;
00343 } else {
00344 for (Q_INT32 krow = 0; krow < kh; ++krow) {
00345 Q_UINT8** d = pixelPtrCache.data() + krow * kw;
00346 memmove( d, d + 1, (kw-1)*sizeof(Q_UINT8*));
00347 }
00348 if(col < xLastMinuskhw)
00349 {
00350 Q_INT32 i = kw - 1;
00351
00352 kit.nextCol();
00353 if( row < khalfHeight )
00354 {
00355 for(; i < (khalfHeight- row ) * kw; i+=kw)
00356 {
00357 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00358 }
00359 }
00360 while (!kit.isDone()) {
00361 pixelPtrCache[i] = const_cast<Q_UINT8 *>(kit.oldRawData());
00362 ++kit;
00363 i += kw;
00364 }
00365 Q_INT32 lastvalid = i - kw;
00366 for(;i < kw*kh; i+=kw)
00367 {
00368 pixelPtrCache[i] = pixelPtrCache[lastvalid];
00369 }
00370 }
00371 }
00372 cs->convolveColors(pixelPtrCache.data(), kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh);
00373 }
00374 ++col;
00375 ++hit;
00376 }
00377
00378 int progressPercent = 100 - ((((y + h) - row) * 100) / h);
00379
00380 if (progressPercent > lastProgressPercent) {
00381 emit notifyProgress(progressPercent);
00382 lastProgressPercent = progressPercent;
00383
00384 if (m_cancelRequested) {
00385 return;
00386 }
00387 }
00388
00389 }
00390
00391 addDirtyRect(QRect(x, y, w, h));
00392
00393 emit notifyProgressDone();
00394 }