File indexing completed on 2024-06-02 04:23:53
0001 0002 /* 0003 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without 0007 modification, are permitted provided that the following conditions 0008 are met: 0009 0010 1. Redistributions of source code must retain the above copyright 0011 notice, this list of conditions and the following disclaimer. 0012 2. Redistributions in binary form must reproduce the above copyright 0013 notice, this list of conditions and the following disclaimer in the 0014 documentation and/or other materials provided with the distribution. 0015 0016 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 // TODO: Color Similarity is obviously useful in Autocrop but it isn't 0029 // obvious as to how to implement it. The current heuristic, 0030 // for each side, chooses an arbitrary reference color for which 0031 // all other candidate pixels in that side are tested against 0032 // for similarity. But if the reference color happens to be at 0033 // one extreme of the range of colors in that side, then pixels 0034 // at the other extreme would not be deemed similar enough. The 0035 // key is to find the median color as the reference but how do 0036 // you do this if you don't know which pixels to sample in the first 0037 // place (that's what you're trying to find)? Chicken and egg situation. 0038 // 0039 // The other heuristic that is in doubt is the use of the average 0040 // color in determining the similarity of sides (it is possible 0041 // to get vastly differently colors in both sides yet they will be 0042 // considered similar). 0043 0044 #define DEBUG_KP_TOOL_AUTO_CROP 0 0045 0046 0047 #include "kpTransformAutoCrop.h" 0048 0049 #include "layers/selections/image/kpAbstractImageSelection.h" 0050 #include "widgets/toolbars/kpColorToolBar.h" 0051 #include "environments/commands/kpCommandEnvironment.h" 0052 #include "commands/kpCommandHistory.h" 0053 #include "document/kpDocument.h" 0054 #include "mainWindow/kpMainWindow.h" 0055 #include "imagelib/kpPainter.h" 0056 #include "pixmapfx/kpPixmapFX.h" 0057 #include "layers/selections/image/kpRectangularImageSelection.h" 0058 #include "generic/kpSetOverrideCursorSaver.h" 0059 #include "tools/kpTool.h" 0060 #include "views/manager/kpViewManager.h" 0061 0062 #include "kpLogCategories.h" 0063 #include <KMessageBox> 0064 #include <KLocalizedString> 0065 0066 #include <QImage> 0067 0068 //--------------------------------------------------------------------- 0069 0070 class kpTransformAutoCropBorder 0071 { 0072 public: 0073 // WARNING: Only call the <ctor> with imagePtr = 0 if you are going to use 0074 // operator= to fill it in with a valid imagePtr immediately 0075 // afterwards. 0076 explicit kpTransformAutoCropBorder (const kpImage *imagePtr = nullptr, int processedColorSimilarity = 0); 0077 0078 kpCommandSize::SizeType size () const; 0079 0080 const kpImage *image () const; 0081 int processedColorSimilarity () const; 0082 QRect rect () const; 0083 int left () const; 0084 int right () const; 0085 int top () const; 0086 int bottom () const; 0087 kpColor referenceColor () const; 0088 kpColor averageColor () const; 0089 bool isSingleColor () const; 0090 0091 // (returns true on success (even if no rect) or false on error) 0092 bool calculate (int isX, int dir); 0093 0094 bool fillsEntireImage () const; 0095 bool exists () const; 0096 void invalidate (); 0097 0098 private: 0099 const kpImage *m_imagePtr; 0100 int m_processedColorSimilarity; 0101 0102 QRect m_rect; 0103 kpColor m_referenceColor; 0104 int m_redSum, m_greenSum, m_blueSum; 0105 bool m_isSingleColor; 0106 }; 0107 0108 kpTransformAutoCropBorder::kpTransformAutoCropBorder (const kpImage *imagePtr, 0109 int processedColorSimilarity) 0110 : m_imagePtr (imagePtr), 0111 m_processedColorSimilarity (processedColorSimilarity) 0112 { 0113 invalidate (); 0114 } 0115 0116 0117 // public 0118 kpCommandSize::SizeType kpTransformAutoCropBorder::size () const 0119 { 0120 return sizeof (kpTransformAutoCropBorder); 0121 } 0122 0123 0124 // public 0125 const kpImage *kpTransformAutoCropBorder::image () const 0126 { 0127 return m_imagePtr; 0128 } 0129 0130 // public 0131 int kpTransformAutoCropBorder::processedColorSimilarity () const 0132 { 0133 return m_processedColorSimilarity; 0134 } 0135 0136 // public 0137 QRect kpTransformAutoCropBorder::rect () const 0138 { 0139 return m_rect; 0140 } 0141 0142 // public 0143 int kpTransformAutoCropBorder::left () const 0144 { 0145 return m_rect.left (); 0146 } 0147 0148 // public 0149 int kpTransformAutoCropBorder::right () const 0150 { 0151 return m_rect.right (); 0152 } 0153 0154 // public 0155 int kpTransformAutoCropBorder::top () const 0156 { 0157 return m_rect.top (); 0158 } 0159 0160 // public 0161 int kpTransformAutoCropBorder::bottom () const 0162 { 0163 return m_rect.bottom (); 0164 } 0165 0166 // public 0167 kpColor kpTransformAutoCropBorder::referenceColor () const 0168 { 0169 return m_referenceColor; 0170 } 0171 0172 // public 0173 kpColor kpTransformAutoCropBorder::averageColor () const 0174 { 0175 if (!m_rect.isValid ()) 0176 return kpColor::Invalid; 0177 0178 if (m_referenceColor.isTransparent ()) 0179 return kpColor::Transparent; 0180 0181 if (m_processedColorSimilarity == 0) 0182 return m_referenceColor; 0183 0184 int numPixels = (m_rect.width () * m_rect.height ()); 0185 Q_ASSERT (numPixels > 0); 0186 0187 return kpColor (m_redSum / numPixels, m_greenSum / numPixels, m_blueSum / numPixels); 0188 0189 } 0190 0191 //--------------------------------------------------------------------- 0192 0193 bool kpTransformAutoCropBorder::isSingleColor () const 0194 { 0195 return m_isSingleColor; 0196 } 0197 0198 //--------------------------------------------------------------------- 0199 0200 // public 0201 bool kpTransformAutoCropBorder::calculate (int isX, int dir) 0202 { 0203 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0204 qCDebug(kpLogImagelib) << "kpTransformAutoCropBorder::calculate() CALLED!"; 0205 #endif 0206 int maxX = m_imagePtr->width () - 1; 0207 int maxY = m_imagePtr->height () - 1; 0208 0209 QImage qimage = *m_imagePtr; 0210 Q_ASSERT (!qimage.isNull ()); 0211 0212 // (sync both branches) 0213 if (isX) 0214 { 0215 int numCols = 0; 0216 int startX = (dir > 0) ? 0 : maxX; 0217 0218 kpColor col = kpPixmapFX::getColorAtPixel (qimage, startX, 0); 0219 for (int x = startX; 0220 x >= 0 && x <= maxX; 0221 x += dir) 0222 { 0223 int y; 0224 for (y = 0; y <= maxY; y++) 0225 { 0226 if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) 0227 break; 0228 } 0229 0230 if (y <= maxY) 0231 break; 0232 else 0233 numCols++; 0234 } 0235 0236 if (numCols) 0237 { 0238 m_rect = 0239 kpPainter::normalizedRect(QPoint(startX, 0), 0240 QPoint(startX + (numCols - 1) * dir, maxY)); 0241 m_referenceColor = col; 0242 } 0243 } 0244 else 0245 { 0246 int numRows = 0; 0247 int startY = (dir > 0) ? 0 : maxY; 0248 0249 kpColor col = kpPixmapFX::getColorAtPixel (qimage, 0, startY); 0250 for (int y = startY; 0251 y >= 0 && y <= maxY; 0252 y += dir) 0253 { 0254 int x; 0255 for (x = 0; x <= maxX; x++) 0256 { 0257 if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) 0258 break; 0259 } 0260 0261 if (x <= maxX) 0262 break; 0263 else 0264 numRows++; 0265 } 0266 0267 if (numRows) 0268 { 0269 m_rect = kpPainter::normalizedRect(QPoint(0, startY), 0270 QPoint(maxX, startY + (numRows - 1) * dir)); 0271 m_referenceColor = col; 0272 } 0273 } 0274 0275 0276 if (m_rect.isValid ()) 0277 { 0278 m_isSingleColor = true; 0279 0280 if (m_processedColorSimilarity != 0) 0281 { 0282 for (int y = m_rect.top (); y <= m_rect.bottom (); y++) 0283 { 0284 for (int x = m_rect.left (); x <= m_rect.right (); x++) 0285 { 0286 kpColor colAtPixel = kpPixmapFX::getColorAtPixel (qimage, x, y); 0287 0288 if (m_isSingleColor && colAtPixel != m_referenceColor) 0289 m_isSingleColor = false; 0290 0291 m_redSum += colAtPixel.red (); 0292 m_greenSum += colAtPixel.green (); 0293 m_blueSum += colAtPixel.blue (); 0294 } 0295 } 0296 } 0297 } 0298 0299 0300 return true; 0301 } 0302 0303 // public 0304 bool kpTransformAutoCropBorder::fillsEntireImage () const 0305 { 0306 return (m_rect == m_imagePtr->rect ()); 0307 } 0308 0309 // public 0310 bool kpTransformAutoCropBorder::exists () const 0311 { 0312 // (will use in an addition so make sure returns 1 or 0) 0313 return (m_rect.isValid () ? 1 : 0); 0314 } 0315 0316 // public 0317 void kpTransformAutoCropBorder::invalidate () 0318 { 0319 m_rect = QRect (); 0320 m_referenceColor = kpColor::Invalid; 0321 m_redSum = m_greenSum = m_blueSum = 0; 0322 m_isSingleColor = false; 0323 } 0324 0325 0326 struct kpTransformAutoCropCommandPrivate 0327 { 0328 bool actOnSelection{}; 0329 kpTransformAutoCropBorder leftBorder, rightBorder, topBorder, botBorder; 0330 kpImage *leftImage{}, *rightImage{}, *topImage{}, *botImage{}; 0331 0332 QRect contentsRect; 0333 int oldWidth{}, oldHeight{}; 0334 kpAbstractImageSelection *oldSelectionPtr{}; 0335 }; 0336 0337 // REFACTOR: Move to /commands/ 0338 kpTransformAutoCropCommand::kpTransformAutoCropCommand (bool actOnSelection, 0339 const kpTransformAutoCropBorder &leftBorder, 0340 const kpTransformAutoCropBorder &rightBorder, 0341 const kpTransformAutoCropBorder &topBorder, 0342 const kpTransformAutoCropBorder &botBorder, 0343 kpCommandEnvironment *environ) 0344 : kpNamedCommand(text(actOnSelection, DontShowAccel), environ), 0345 d (new kpTransformAutoCropCommandPrivate ()) 0346 { 0347 d->actOnSelection = actOnSelection; 0348 d->leftBorder = leftBorder; 0349 d->rightBorder = rightBorder; 0350 d->topBorder = topBorder; 0351 d->botBorder = botBorder; 0352 d->leftImage = nullptr; 0353 d->rightImage = nullptr; 0354 d->topImage = nullptr; 0355 d->botImage = nullptr; 0356 0357 kpDocument *doc = document (); 0358 Q_ASSERT (doc); 0359 0360 d->oldWidth = doc->width (d->actOnSelection); 0361 d->oldHeight = doc->height (d->actOnSelection); 0362 0363 d->oldSelectionPtr = nullptr; 0364 } 0365 0366 //--------------------------------------------------------------------- 0367 0368 kpTransformAutoCropCommand::~kpTransformAutoCropCommand () 0369 { 0370 deleteUndoImages (); 0371 0372 delete d->oldSelectionPtr; 0373 delete d; 0374 } 0375 0376 //--------------------------------------------------------------------- 0377 // public static 0378 0379 QString kpTransformAutoCropCommand::text(bool actOnSelection, int options) 0380 { 0381 if (actOnSelection) 0382 { 0383 if (options & kpTransformAutoCropCommand::ShowAccel) { 0384 return i18n ("Remove Internal B&order"); 0385 } 0386 0387 return i18n ("Remove Internal Border"); 0388 } 0389 0390 if (options & kpTransformAutoCropCommand::ShowAccel) 0391 return i18n ("Autocr&op"); 0392 0393 return i18n ("Autocrop"); 0394 } 0395 0396 //--------------------------------------------------------------------- 0397 // public virtual [base kpCommand] 0398 0399 kpCommandSize::SizeType kpTransformAutoCropCommand::size () const 0400 { 0401 return d->leftBorder.size () + 0402 d->rightBorder.size () + 0403 d->topBorder.size () + 0404 d->botBorder.size () + 0405 ImageSize (d->leftImage) + 0406 ImageSize (d->rightImage) + 0407 ImageSize (d->topImage) + 0408 ImageSize (d->botImage) + 0409 SelectionSize (d->oldSelectionPtr); 0410 } 0411 0412 //--------------------------------------------------------------------- 0413 // private 0414 0415 void kpTransformAutoCropCommand::getUndoImage (const kpTransformAutoCropBorder &border, kpImage **image) 0416 { 0417 kpDocument *doc = document (); 0418 Q_ASSERT (doc); 0419 0420 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0421 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::getUndoImage()"; 0422 qCDebug(kpLogImagelib) << "\timage=" << image 0423 << " border: rect=" << border.rect () 0424 << " isSingleColor=" << border.isSingleColor (); 0425 #endif 0426 0427 if (image && border.exists () && !border.isSingleColor ()) 0428 { 0429 if (*image) 0430 { 0431 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0432 qCDebug(kpLogImagelib) << "\talready have *image - delete it"; 0433 #endif 0434 delete *image; 0435 } 0436 0437 *image = new kpImage ( 0438 kpPixmapFX::getPixmapAt (doc->image (d->actOnSelection), 0439 border.rect ())); 0440 } 0441 } 0442 0443 0444 // private 0445 void kpTransformAutoCropCommand::getUndoImages () 0446 { 0447 getUndoImage (d->leftBorder, &d->leftImage); 0448 getUndoImage (d->rightBorder, &d->rightImage); 0449 getUndoImage (d->topBorder, &d->topImage); 0450 getUndoImage (d->botBorder, &d->botImage); 0451 } 0452 0453 // private 0454 void kpTransformAutoCropCommand::deleteUndoImages () 0455 { 0456 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0457 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::deleteUndoImages()"; 0458 #endif 0459 0460 delete d->leftImage; d->leftImage = nullptr; 0461 delete d->rightImage; d->rightImage = nullptr; 0462 delete d->topImage; d->topImage = nullptr; 0463 delete d->botImage; d->botImage = nullptr; 0464 } 0465 0466 0467 // public virtual [base kpCommand] 0468 void kpTransformAutoCropCommand::execute () 0469 { 0470 if (!d->contentsRect.isValid ()) { 0471 d->contentsRect = contentsRect (); 0472 } 0473 0474 0475 getUndoImages (); 0476 0477 0478 kpDocument *doc = document (); 0479 Q_ASSERT (doc); 0480 0481 0482 kpImage imageWithoutBorder = 0483 kpTool::neededPixmap (doc->image (d->actOnSelection), 0484 d->contentsRect); 0485 0486 0487 if (!d->actOnSelection) { 0488 doc->setImage (imageWithoutBorder); 0489 } 0490 else { 0491 d->oldSelectionPtr = doc->imageSelection ()->clone (); 0492 d->oldSelectionPtr->setBaseImage (kpImage ()); 0493 0494 // d->contentsRect is relative to the top of the sel 0495 // while sel is relative to the top of the doc 0496 QRect rect = d->contentsRect; 0497 rect.translate (d->oldSelectionPtr->x (), d->oldSelectionPtr->y ()); 0498 0499 kpRectangularImageSelection sel ( 0500 rect, 0501 imageWithoutBorder, 0502 d->oldSelectionPtr->transparency ()); 0503 0504 doc->setSelection (sel); 0505 0506 environ ()->somethingBelowTheCursorChanged (); 0507 } 0508 } 0509 0510 // public virtual [base kpCommand] 0511 void kpTransformAutoCropCommand::unexecute () 0512 { 0513 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0514 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::unexecute()"; 0515 #endif 0516 0517 kpDocument *doc = document (); 0518 Q_ASSERT (doc); 0519 0520 kpImage image (d->oldWidth, d->oldHeight, QImage::Format_ARGB32_Premultiplied); 0521 0522 // restore the position of the center image 0523 kpPixmapFX::setPixmapAt (&image, d->contentsRect, 0524 doc->image (d->actOnSelection)); 0525 0526 // draw the borders 0527 0528 const kpTransformAutoCropBorder *borders [] = 0529 { 0530 &d->leftBorder, &d->rightBorder, 0531 &d->topBorder, &d->botBorder, 0532 nullptr 0533 }; 0534 0535 const kpImage *images [] = 0536 { 0537 d->leftImage, d->rightImage, 0538 d->topImage, d->botImage, 0539 nullptr 0540 }; 0541 0542 const kpImage **p = images; 0543 for (const kpTransformAutoCropBorder **b = borders; *b; b++, p++) 0544 { 0545 if (!(*b)->exists ()) { 0546 continue; 0547 } 0548 0549 if ((*b)->isSingleColor ()) 0550 { 0551 kpColor col = (*b)->referenceColor (); 0552 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0553 qCDebug(kpLogImagelib) << "\tdrawing border " << (*b)->rect () 0554 << " rgb=" << (int *) col.toQRgb () /* %X hack */; 0555 #endif 0556 0557 const QRect r = (*b)->rect (); 0558 kpPainter::fillRect (&image, 0559 r.x (), r.y (), r.width (), r.height (), 0560 col); 0561 } 0562 else 0563 { 0564 #if DEBUG_KP_TOOL_AUTO_CROP && 1 0565 qCDebug(kpLogImagelib) << "\trestoring border image " << (*b)->rect (); 0566 #endif 0567 if (*p) 0568 { 0569 // REFACTOR: Add equivalent method to kpPainter and use. 0570 kpPixmapFX::setPixmapAt (&image, (*b)->rect (), **p); 0571 } 0572 } 0573 } 0574 0575 0576 if (!d->actOnSelection) { 0577 doc->setImage (image); 0578 } 0579 else 0580 { 0581 d->oldSelectionPtr->setBaseImage (image); 0582 0583 doc->setSelection (*d->oldSelectionPtr); 0584 delete d->oldSelectionPtr; d->oldSelectionPtr = nullptr; 0585 0586 environ ()->somethingBelowTheCursorChanged (); 0587 } 0588 0589 0590 deleteUndoImages (); 0591 } 0592 0593 0594 // private 0595 QRect kpTransformAutoCropCommand::contentsRect () const 0596 { 0597 const kpImage image = document ()->image (d->actOnSelection); 0598 0599 QPoint topLeft (d->leftBorder.exists () ? 0600 d->leftBorder.rect ().right () + 1 : 0601 0, 0602 d->topBorder.exists () ? 0603 d->topBorder.rect ().bottom () + 1 : 0604 0); 0605 QPoint botRight (d->rightBorder.exists () ? 0606 d->rightBorder.rect ().left () - 1 : 0607 image.width () - 1, 0608 d->botBorder.exists () ? 0609 d->botBorder.rect ().top () - 1 : 0610 image.height () - 1); 0611 0612 return {topLeft, botRight}; 0613 } 0614 0615 0616 static void ShowNothingToAutocropMessage (kpMainWindow *mainWindow, bool actOnSelection) 0617 { 0618 kpSetOverrideCursorSaver cursorSaver (Qt::ArrowCursor); 0619 0620 if (actOnSelection) 0621 { 0622 KMessageBox::information (mainWindow, 0623 i18n ("KolourPaint cannot remove the selection's internal border as it" 0624 " could not be located."), 0625 i18nc ("@title:window", "Cannot Remove Internal Border"), 0626 QStringLiteral("NothingToAutoCrop")); 0627 } 0628 else 0629 { 0630 KMessageBox::information (mainWindow, 0631 i18n ("KolourPaint cannot automatically crop the image as its" 0632 " border could not be located."), 0633 i18nc ("@title:window", "Cannot Autocrop"), 0634 QStringLiteral("NothingToAutoCrop")); 0635 } 0636 } 0637 0638 bool kpTransformAutoCrop (kpMainWindow *mainWindow) 0639 { 0640 #if DEBUG_KP_TOOL_AUTO_CROP 0641 qCDebug(kpLogImagelib) << "kpTransformAutoCrop() CALLED!"; 0642 #endif 0643 0644 Q_ASSERT (mainWindow); 0645 kpDocument *doc = mainWindow->document (); 0646 Q_ASSERT (doc); 0647 0648 // OPT: if already pulled selection image, no need to do it again here 0649 kpImage image = doc->selection () ? doc->getSelectedBaseImage () : doc->image (); 0650 Q_ASSERT (!image.isNull ()); 0651 0652 kpViewManager *vm = mainWindow->viewManager (); 0653 Q_ASSERT (vm); 0654 0655 int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity (); 0656 kpTransformAutoCropBorder leftBorder (&image, processedColorSimilarity), 0657 rightBorder (&image, processedColorSimilarity), 0658 topBorder (&image, processedColorSimilarity), 0659 botBorder (&image, processedColorSimilarity); 0660 0661 0662 kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); 0663 0664 mainWindow->colorToolBar ()->flashColorSimilarityToolBarItem (); 0665 0666 // TODO: With Colour Similarity, a lot of weird (and wonderful) things can 0667 // happen resulting in a huge number of code paths. Needs refactoring 0668 // and regression testing. 0669 // 0670 // TODO: e.g. When the top fills entire rect but bot doesn't we could 0671 // invalidate top and continue autocrop. 0672 int numRegions = 0; 0673 if (!leftBorder.calculate (true/*x*/, +1/*going right*/) || 0674 leftBorder.fillsEntireImage () || 0675 !rightBorder.calculate (true/*x*/, -1/*going left*/) || 0676 rightBorder.fillsEntireImage () || 0677 !topBorder.calculate (false/*y*/, +1/*going down*/) || 0678 topBorder.fillsEntireImage () || 0679 !botBorder.calculate (false/*y*/, -1/*going up*/) || 0680 botBorder.fillsEntireImage () || 0681 ((numRegions = leftBorder.exists () + 0682 rightBorder.exists () + 0683 topBorder.exists () + 0684 botBorder.exists ()) == 0)) 0685 { 0686 #if DEBUG_KP_TOOL_AUTO_CROP 0687 qCDebug(kpLogImagelib) << "\tcan't find border; leftBorder.rect=" << leftBorder.rect () 0688 << " rightBorder.rect=" << rightBorder.rect () 0689 << " topBorder.rect=" << topBorder.rect () 0690 << " botBorder.rect=" << botBorder.rect (); 0691 #endif 0692 ::ShowNothingToAutocropMessage (mainWindow, static_cast<bool> (doc->selection ())); 0693 return false; 0694 } 0695 0696 #if DEBUG_KP_TOOL_AUTO_CROP 0697 qCDebug(kpLogImagelib) << "\tnumRegions=" << numRegions; 0698 qCDebug(kpLogImagelib) << "\t\tleft=" << leftBorder.rect () 0699 << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : nullptr) 0700 << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : nullptr); 0701 qCDebug(kpLogImagelib) << "\t\tright=" << rightBorder.rect () 0702 << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : nullptr) 0703 << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : nullptr); 0704 qCDebug(kpLogImagelib) << "\t\ttop=" << topBorder.rect () 0705 << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : nullptr) 0706 << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : nullptr); 0707 qCDebug(kpLogImagelib) << "\t\tbot=" << botBorder.rect () 0708 << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : nullptr) 0709 << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : nullptr); 0710 #endif 0711 0712 // In case e.g. the user pastes a solid, coloured-in rectangle, 0713 // we favor killing the bottom and right regions 0714 // (these regions probably contain the unwanted whitespace due 0715 // to the doc being bigger than the pasted selection to start with). 0716 // 0717 // We also kill if they kiss or even overlap. 0718 0719 if (leftBorder.exists () && rightBorder.exists ()) 0720 { 0721 const kpColor leftCol = leftBorder.averageColor (); 0722 const kpColor rightCol = rightBorder.averageColor (); 0723 0724 if ((numRegions == 2 && !leftCol.isSimilarTo (rightCol, processedColorSimilarity)) || 0725 leftBorder.right () >= rightBorder.left () - 1) // kissing or overlapping 0726 { 0727 #if DEBUG_KP_TOOL_AUTO_CROP 0728 qCDebug(kpLogImagelib) << "\tignoring left border"; 0729 #endif 0730 leftBorder.invalidate (); 0731 } 0732 } 0733 0734 if (topBorder.exists () && botBorder.exists ()) 0735 { 0736 const kpColor topCol = topBorder.averageColor (); 0737 const kpColor botCol = botBorder.averageColor (); 0738 0739 if ((numRegions == 2 && !topCol.isSimilarTo (botCol, processedColorSimilarity)) || 0740 topBorder.bottom () >= botBorder.top () - 1) // kissing or overlapping 0741 { 0742 #if DEBUG_KP_TOOL_AUTO_CROP 0743 qCDebug(kpLogImagelib) << "\tignoring top border"; 0744 #endif 0745 topBorder.invalidate (); 0746 } 0747 } 0748 0749 0750 mainWindow->addImageOrSelectionCommand ( 0751 new kpTransformAutoCropCommand (static_cast<bool> (doc->selection ()), 0752 leftBorder, rightBorder, topBorder, botBorder, mainWindow->commandEnvironment ())); 0753 0754 0755 return true; 0756 }