00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <qimage.h>
00020
00021 #include <kdebug.h>
00022 #include <klocale.h>
00023 #include <qcolor.h>
00024
00025 #include "kis_layer.h"
00026 #include "kis_debug_areas.h"
00027 #include "kis_types.h"
00028 #include "kis_colorspace_factory_registry.h"
00029 #include "kis_fill_painter.h"
00030 #include "kis_iterators_pixel.h"
00031 #include "kis_integer_maths.h"
00032 #include "kis_image.h"
00033 #include "kis_datamanager.h"
00034 #include "kis_fill_painter.h"
00035 #include "kis_selection.h"
00036
00037 KisSelection::KisSelection(KisPaintDeviceSP dev)
00038 : super(dev->parentLayer()
00039 , KisMetaRegistry::instance()->csRegistry()->getAlpha8()
00040 , (QString("selection for ") + dev->name()).latin1())
00041 , m_parentPaintDevice(dev)
00042 , m_doCacheExactRect(false)
00043 , m_dirty(false)
00044 {
00045 Q_ASSERT(dev);
00046 }
00047
00048 KisSelection::KisSelection()
00049 : super(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), "anonymous selection")
00050 , m_parentPaintDevice(0), m_dirty(false)
00051 {
00052 }
00053
00054 KisSelection::KisSelection(const KisSelection& rhs)
00055 : super(rhs), m_parentPaintDevice(rhs.m_parentPaintDevice), m_doCacheExactRect(rhs.m_doCacheExactRect),
00056 m_cachedExactRect(rhs.m_cachedExactRect), m_dirty(rhs.m_dirty)
00057 {
00058 }
00059
00060 KisSelection::~KisSelection()
00061 {
00062 }
00063
00064 Q_UINT8 KisSelection::selected(Q_INT32 x, Q_INT32 y)
00065 {
00066 KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false);
00067
00068 Q_UINT8 *pix = iter.rawData();
00069
00070 return *pix;
00071 }
00072
00073 void KisSelection::setSelected(Q_INT32 x, Q_INT32 y, Q_UINT8 s)
00074 {
00075 KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true);
00076
00077 Q_UINT8 *pix = iter.rawData();
00078
00079 *pix = s;
00080 }
00081
00082 QImage KisSelection::maskImage()
00083 {
00084
00085 QImage img;
00086 QRect bounds;
00087 if (m_parentPaintDevice) {
00088
00089 bounds = m_parentPaintDevice->exactBounds();
00090 bounds = bounds.intersect( m_parentPaintDevice->image()->bounds() );
00091 img = QImage(bounds.width(), bounds.height(), 32);
00092 }
00093 else {
00094 bounds = QRect( 0, 0, image()->width(), image()->height());
00095 img = QImage(bounds.width(), bounds.height(), 32);
00096 }
00097
00098 KisHLineIteratorPixel it = createHLineIterator(bounds.x(), bounds.y(), bounds.width(), false);
00099 for (int y2 = bounds.y(); y2 < bounds.height() - bounds.y(); ++y2) {
00100 int x2 = 0;
00101 while (!it.isDone()) {
00102 Q_UINT8 s = MAX_SELECTED - *(it.rawData());
00103 Q_INT32 c = qRgb(s, s, s);
00104 img.setPixel(x2, y2, c);
00105 ++x2;
00106 ++it;
00107 }
00108 it.nextRow();
00109 }
00110 return img;
00111 }
00112 void KisSelection::select(QRect r)
00113 {
00114 KisFillPainter painter(this);
00115 KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
00116 painter.fillRect(r, KisColor(Qt::white, cs), MAX_SELECTED);
00117 Q_INT32 x, y, w, h;
00118 extent(x, y, w, h);
00119 }
00120
00121 void KisSelection::clear(QRect r)
00122 {
00123 KisFillPainter painter(this);
00124 KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
00125 painter.fillRect(r, KisColor(Qt::white, cs), MIN_SELECTED);
00126 }
00127
00128 void KisSelection::clear()
00129 {
00130 Q_UINT8 defPixel = MIN_SELECTED;
00131 m_datamanager->setDefaultPixel(&defPixel);
00132 m_datamanager->clear();
00133 }
00134
00135 void KisSelection::invert()
00136 {
00137 Q_INT32 x,y,w,h;
00138
00139 extent(x, y, w, h);
00140 KisRectIterator it = createRectIterator(x, y, w, h, true);
00141 while ( ! it.isDone() )
00142 {
00143
00144
00145 *(it.rawData()) = MAX_SELECTED - *(it.rawData());
00146 ++it;
00147 }
00148 Q_UINT8 defPixel = MAX_SELECTED - *(m_datamanager->defaultPixel());
00149 m_datamanager->setDefaultPixel(&defPixel);
00150 }
00151
00152 bool KisSelection::isTotallyUnselected(QRect r)
00153 {
00154 if(*(m_datamanager->defaultPixel()) != MIN_SELECTED)
00155 return false;
00156 QRect sr = selectedExactRect();
00157 return ! r.intersects(sr);
00158 }
00159
00160 bool KisSelection::isProbablyTotallyUnselected(QRect r)
00161 {
00162 if(*(m_datamanager->defaultPixel()) != MIN_SELECTED)
00163 return false;
00164 QRect sr = selectedRect();
00165 return ! r.intersects(sr);
00166 }
00167
00168
00169 QRect KisSelection::selectedRect() const
00170 {
00171 if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
00172 return extent();
00173 else
00174 return extent().unite(m_parentPaintDevice->extent());
00175 }
00176
00177 QRect KisSelection::selectedExactRect() const
00178 {
00179 if(m_doCacheExactRect)
00180 return m_cachedExactRect;
00181 else if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
00182 return exactBounds();
00183 else
00184 return exactBounds().unite(m_parentPaintDevice->exactBounds());
00185 }
00186
00187 void KisSelection::stopCachingExactRect()
00188 {
00189 kdDebug() << "stop caching the exact rect" << endl;
00190 m_doCacheExactRect = false;
00191 }
00192
00193
00194 void KisSelection::startCachingExactRect()
00195 {
00196 kdDebug() << "start caching the exact rect" << endl;
00197 if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
00198 m_cachedExactRect = exactBounds();
00199 else
00200 m_cachedExactRect = exactBounds().unite(m_parentPaintDevice->exactBounds());
00201 m_doCacheExactRect = true;
00202 }
00203
00204 void KisSelection::paintUniformSelectionRegion(QImage img, const QRect& imageRect, const QRegion& uniformRegion)
00205 {
00206 Q_ASSERT(img.size() == imageRect.size());
00207 Q_ASSERT(imageRect.contains(uniformRegion.boundingRect()));
00208
00209 if (img.isNull() || img.size() != imageRect.size() || !imageRect.contains(uniformRegion.boundingRect())) {
00210 return;
00211 }
00212
00213 if (*m_datamanager->defaultPixel() == MIN_SELECTED) {
00214
00215 QRegion region = uniformRegion & QRegion(imageRect);
00216
00217 if (!region.isEmpty()) {
00218 QMemArray<QRect> rects = region.rects();
00219
00220 for (unsigned int i = 0; i < rects.count(); i++) {
00221 QRect r = rects[i];
00222
00223 for (Q_INT32 y = 0; y < r.height(); ++y) {
00224
00225 QRgb *imagePixel = reinterpret_cast<QRgb *>(img.scanLine(r.y() - imageRect.y() + y));
00226 imagePixel += r.x() - imageRect.x();
00227
00228 Q_INT32 numPixels = r.width();
00229
00230 while (numPixels > 0) {
00231
00232 QRgb srcPixel = *imagePixel;
00233 Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9;
00234 Q_UINT8 srcAlpha = qAlpha(srcPixel);
00235
00236 srcGrey = UINT8_MULT(srcGrey, srcAlpha);
00237 Q_UINT8 dstAlpha = QMAX(srcAlpha, 192);
00238
00239 QRgb dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
00240 *imagePixel = dstPixel;
00241
00242 ++imagePixel;
00243 --numPixels;
00244 }
00245 }
00246 }
00247 }
00248 }
00249 }
00250
00251 void KisSelection::paintSelection(QImage img, Q_INT32 imageRectX, Q_INT32 imageRectY, Q_INT32 imageRectWidth, Q_INT32 imageRectHeight)
00252 {
00253 Q_ASSERT(img.size() == QSize(imageRectWidth, imageRectHeight));
00254
00255 if (img.isNull() || img.size() != QSize(imageRectWidth, imageRectHeight)) {
00256 return;
00257 }
00258
00259 QRect imageRect(imageRectX, imageRectY, imageRectWidth, imageRectHeight);
00260 QRect selectionExtent = extent();
00261
00262 selectionExtent.setLeft(selectionExtent.left() - 1);
00263 selectionExtent.setTop(selectionExtent.top() - 1);
00264 selectionExtent.setWidth(selectionExtent.width() + 2);
00265 selectionExtent.setHeight(selectionExtent.height() + 2);
00266
00267 QRegion uniformRegion = QRegion(imageRect);
00268 uniformRegion -= QRegion(selectionExtent);
00269
00270 if (!uniformRegion.isEmpty()) {
00271 paintUniformSelectionRegion(img, imageRect, uniformRegion);
00272 }
00273
00274 QRect nonuniformRect = imageRect & selectionExtent;
00275
00276 if (!nonuniformRect.isEmpty()) {
00277
00278 const Q_INT32 imageRectOffsetX = nonuniformRect.x() - imageRectX;
00279 const Q_INT32 imageRectOffsetY = nonuniformRect.y() - imageRectY;
00280
00281 imageRectX = nonuniformRect.x();
00282 imageRectY = nonuniformRect.y();
00283 imageRectWidth = nonuniformRect.width();
00284 imageRectHeight = nonuniformRect.height();
00285
00286 const Q_INT32 NUM_SELECTION_ROWS = 3;
00287
00288 Q_UINT8 *selectionRow[NUM_SELECTION_ROWS];
00289
00290 Q_INT32 aboveRowIndex = 0;
00291 Q_INT32 centreRowIndex = 1;
00292 Q_INT32 belowRowIndex = 2;
00293
00294 selectionRow[aboveRowIndex] = new Q_UINT8[imageRectWidth + 2];
00295 selectionRow[centreRowIndex] = new Q_UINT8[imageRectWidth + 2];
00296 selectionRow[belowRowIndex] = new Q_UINT8[imageRectWidth + 2];
00297
00298 readBytes(selectionRow[centreRowIndex], imageRectX - 1, imageRectY - 1, imageRectWidth + 2, 1);
00299 readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY, imageRectWidth + 2, 1);
00300
00301 for (Q_INT32 y = 0; y < imageRectHeight; ++y) {
00302
00303 Q_INT32 oldAboveRowIndex = aboveRowIndex;
00304 aboveRowIndex = centreRowIndex;
00305 centreRowIndex = belowRowIndex;
00306 belowRowIndex = oldAboveRowIndex;
00307
00308 readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY + y + 1, imageRectWidth + 2, 1);
00309
00310 const Q_UINT8 *aboveRow = selectionRow[aboveRowIndex] + 1;
00311 const Q_UINT8 *centreRow = selectionRow[centreRowIndex] + 1;
00312 const Q_UINT8 *belowRow = selectionRow[belowRowIndex] + 1;
00313
00314 QRgb *imagePixel = reinterpret_cast<QRgb *>(img.scanLine(imageRectOffsetY + y));
00315 imagePixel += imageRectOffsetX;
00316
00317 for (Q_INT32 x = 0; x < imageRectWidth; ++x) {
00318
00319 Q_UINT8 centre = *centreRow;
00320
00321 if (centre != MAX_SELECTED) {
00322
00323
00324
00325 QRgb srcPixel = *imagePixel;
00326 Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9;
00327 Q_UINT8 srcAlpha = qAlpha(srcPixel);
00328
00329
00330 srcGrey = UINT8_MULT(srcGrey, srcAlpha);
00331
00332 QRgb dstPixel;
00333
00334 if (centre == MIN_SELECTED) {
00335
00336
00337 Q_UINT8 left = *(centreRow - 1);
00338 Q_UINT8 right = *(centreRow + 1);
00339 Q_UINT8 above = *aboveRow;
00340 Q_UINT8 below = *belowRow;
00341
00342
00343
00344 Q_UINT8 dstAlpha = QMAX(srcAlpha, 192);
00345
00346
00347 if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) {
00348 dstPixel = qRgba(255, 0, 0, dstAlpha);
00349 } else {
00350 dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
00351 }
00352 } else {
00353 dstPixel = qRgba(UINT8_BLEND(qRed(srcPixel), srcGrey + 128, centre),
00354 UINT8_BLEND(qGreen(srcPixel), srcGrey + 128, centre),
00355 UINT8_BLEND(qBlue(srcPixel), srcGrey + 165, centre),
00356 srcAlpha);
00357 }
00358
00359 *imagePixel = dstPixel;
00360 }
00361
00362 aboveRow++;
00363 centreRow++;
00364 belowRow++;
00365 imagePixel++;
00366 }
00367 }
00368
00369 delete [] selectionRow[aboveRowIndex];
00370 delete [] selectionRow[centreRowIndex];
00371 delete [] selectionRow[belowRowIndex];
00372 }
00373 }
00374
00375 void KisSelection::paintSelection(QImage img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize)
00376 {
00377 if (img.isNull() || scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) {
00378 return;
00379 }
00380
00381 Q_ASSERT(img.size() == scaledImageRect.size());
00382
00383 if (img.size() != scaledImageRect.size()) {
00384 return;
00385 }
00386
00387 Q_INT32 imageWidth = imageSize.width();
00388 Q_INT32 imageHeight = imageSize.height();
00389
00390 QRect selectionExtent = extent();
00391
00392 selectionExtent.setLeft(selectionExtent.left() - 1);
00393 selectionExtent.setTop(selectionExtent.top() - 1);
00394 selectionExtent.setWidth(selectionExtent.width() + 2);
00395 selectionExtent.setHeight(selectionExtent.height() + 2);
00396
00397 double xScale = static_cast<double>(scaledImageSize.width()) / imageWidth;
00398 double yScale = static_cast<double>(scaledImageSize.height()) / imageHeight;
00399
00400 QRect scaledSelectionExtent;
00401
00402 scaledSelectionExtent.setLeft(static_cast<int>(selectionExtent.left() * xScale));
00403 scaledSelectionExtent.setRight(static_cast<int>(ceil((selectionExtent.right() + 1) * xScale)) - 1);
00404 scaledSelectionExtent.setTop(static_cast<int>(selectionExtent.top() * yScale));
00405 scaledSelectionExtent.setBottom(static_cast<int>(ceil((selectionExtent.bottom() + 1) * yScale)) - 1);
00406
00407 QRegion uniformRegion = QRegion(scaledImageRect);
00408 uniformRegion -= QRegion(scaledSelectionExtent);
00409
00410 if (!uniformRegion.isEmpty()) {
00411 paintUniformSelectionRegion(img, scaledImageRect, uniformRegion);
00412 }
00413
00414 QRect nonuniformRect = scaledImageRect & scaledSelectionExtent;
00415
00416 if (!nonuniformRect.isEmpty()) {
00417
00418 const Q_INT32 scaledImageRectXOffset = nonuniformRect.x() - scaledImageRect.x();
00419 const Q_INT32 scaledImageRectYOffset = nonuniformRect.y() - scaledImageRect.y();
00420
00421 const Q_INT32 scaledImageRectX = nonuniformRect.x();
00422 const Q_INT32 scaledImageRectY = nonuniformRect.y();
00423 const Q_INT32 scaledImageRectWidth = nonuniformRect.width();
00424 const Q_INT32 scaledImageRectHeight = nonuniformRect.height();
00425
00426 const Q_INT32 imageRowLeft = static_cast<Q_INT32>(scaledImageRectX / xScale);
00427 const Q_INT32 imageRowRight = static_cast<Q_INT32>((ceil((scaledImageRectX + scaledImageRectWidth - 1 + 1) / xScale)) - 1);
00428
00429 const Q_INT32 imageRowWidth = imageRowRight - imageRowLeft + 1;
00430 const Q_INT32 imageRowStride = imageRowWidth + 2;
00431
00432 const Q_INT32 NUM_SELECTION_ROWS = 3;
00433
00434 Q_INT32 aboveRowIndex = 0;
00435 Q_INT32 centreRowIndex = 1;
00436 Q_INT32 belowRowIndex = 2;
00437
00438 Q_INT32 aboveRowSrcY = -3;
00439 Q_INT32 centreRowSrcY = -3;
00440 Q_INT32 belowRowSrcY = -3;
00441
00442 Q_UINT8 *selectionRows = new Q_UINT8[imageRowStride * NUM_SELECTION_ROWS];
00443 Q_UINT8 *selectionRow[NUM_SELECTION_ROWS];
00444
00445 selectionRow[0] = selectionRows + 1;
00446 selectionRow[1] = selectionRow[0] + imageRowStride;
00447 selectionRow[2] = selectionRow[0] + (2 * imageRowStride);
00448
00449 for (Q_INT32 y = 0; y < scaledImageRectHeight; ++y) {
00450
00451 Q_INT32 scaledY = scaledImageRectY + y;
00452 Q_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height();
00453
00454 Q_UINT8 *aboveRow;
00455 Q_UINT8 *centreRow;
00456 Q_UINT8 *belowRow;
00457
00458 if (srcY - 1 == aboveRowSrcY) {
00459 aboveRow = selectionRow[aboveRowIndex];
00460 centreRow = selectionRow[centreRowIndex];
00461 belowRow = selectionRow[belowRowIndex];
00462 } else if (srcY - 1 == centreRowSrcY) {
00463
00464 Q_INT32 oldAboveRowIndex = aboveRowIndex;
00465
00466 aboveRowIndex = centreRowIndex;
00467 centreRowIndex = belowRowIndex;
00468 belowRowIndex = oldAboveRowIndex;
00469
00470 aboveRow = selectionRow[aboveRowIndex];
00471 centreRow = selectionRow[centreRowIndex];
00472 belowRow = selectionRow[belowRowIndex];
00473
00474 readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1);
00475
00476 } else if (srcY - 1 == belowRowSrcY) {
00477
00478 Q_INT32 oldAboveRowIndex = aboveRowIndex;
00479 Q_INT32 oldCentreRowIndex = centreRowIndex;
00480
00481 aboveRowIndex = belowRowIndex;
00482 centreRowIndex = oldAboveRowIndex;
00483 belowRowIndex = oldCentreRowIndex;
00484
00485 aboveRow = selectionRow[aboveRowIndex];
00486 centreRow = selectionRow[centreRowIndex];
00487 belowRow = selectionRow[belowRowIndex];
00488
00489 if (belowRowIndex == centreRowIndex + 1) {
00490 readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 2);
00491 } else {
00492 readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 1);
00493 readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1);
00494 }
00495
00496 } else {
00497
00498 aboveRowIndex = 0;
00499 centreRowIndex = 1;
00500 belowRowIndex = 2;
00501
00502 aboveRow = selectionRow[aboveRowIndex];
00503 centreRow = selectionRow[centreRowIndex];
00504 belowRow = selectionRow[belowRowIndex];
00505
00506 readBytes(selectionRows, imageRowLeft - 1, srcY - 1, imageRowStride, NUM_SELECTION_ROWS);
00507 }
00508
00509 aboveRowSrcY = srcY - 1;
00510 centreRowSrcY = aboveRowSrcY + 1;
00511 belowRowSrcY = centreRowSrcY + 1;
00512
00513 QRgb *imagePixel = reinterpret_cast<QRgb *>(img.scanLine(scaledImageRectYOffset + y));
00514 imagePixel += scaledImageRectXOffset;
00515
00516 for (Q_INT32 x = 0; x < scaledImageRectWidth; ++x) {
00517
00518 Q_INT32 scaledX = scaledImageRectX + x;
00519 Q_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width();
00520
00521 Q_UINT8 centre = *(centreRow + srcX - imageRowLeft);
00522
00523 if (centre != MAX_SELECTED) {
00524
00525
00526
00527 QRgb srcPixel = *imagePixel;
00528 Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9;
00529 Q_UINT8 srcAlpha = qAlpha(srcPixel);
00530
00531
00532 srcGrey = UINT8_MULT(srcGrey, srcAlpha);
00533
00534 QRgb dstPixel;
00535
00536 if (centre == MIN_SELECTED) {
00537
00538
00539 Q_UINT8 left = *(centreRow + (srcX - imageRowLeft) - 1);
00540 Q_UINT8 right = *(centreRow + (srcX - imageRowLeft) + 1);
00541 Q_UINT8 above = *(aboveRow + (srcX - imageRowLeft));
00542 Q_UINT8 below = *(belowRow + (srcX - imageRowLeft));
00543
00544
00545
00546 Q_UINT8 dstAlpha = QMAX(srcAlpha, 192);
00547
00548
00549 if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) {
00550 dstPixel = qRgba(255, 0, 0, dstAlpha);
00551 } else {
00552 dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
00553 }
00554 } else {
00555 dstPixel = qRgba(UINT8_BLEND(qRed(srcPixel), srcGrey + 128, centre),
00556 UINT8_BLEND(qGreen(srcPixel), srcGrey + 128, centre),
00557 UINT8_BLEND(qBlue(srcPixel), srcGrey + 165, centre),
00558 srcAlpha);
00559 }
00560
00561 *imagePixel = dstPixel;
00562 }
00563
00564 imagePixel++;
00565 }
00566 }
00567
00568 delete [] selectionRows;
00569 }
00570 }
00571
00572 void KisSelection::setDirty(const QRect& rc)
00573 {
00574 if (m_dirty)
00575 super::setDirty(rc);
00576 }
00577
00578 void KisSelection::setDirty()
00579 {
00580 if (m_dirty)
00581 super::setDirty();
00582 }