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