File indexing completed on 2024-12-22 04:07:28

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 
0029 #define DEBUG_KP_TOOL_CROP 0
0030 
0031 
0032 #include "kpTransformCrop.h"
0033 #include "kpTransformCropPrivate.h"
0034 
0035 #include "layers/selections/image/kpAbstractImageSelection.h"
0036 #include "environments/commands/kpCommandEnvironment.h"
0037 #include "commands/kpCommandHistory.h"
0038 #include "document/kpDocument.h"
0039 #include "imagelib/kpImage.h"
0040 #include "commands/kpMacroCommand.h"
0041 #include "mainWindow/kpMainWindow.h"
0042 #include "pixmapfx/kpPixmapFX.h"
0043 #include "commands/tools/selection/kpToolSelectionCreateCommand.h"
0044 #include "views/manager/kpViewManager.h"
0045 
0046 
0047 // See the "image selection" part of the kpTransformCrop() API Doc.
0048 //
0049 // REFACTOR: Move into commands/
0050 class SetDocumentToSelectionImageCommand : public kpCommand
0051 {
0052 public:
0053     explicit SetDocumentToSelectionImageCommand (kpCommandEnvironment *environ);
0054     ~SetDocumentToSelectionImageCommand () override;
0055 
0056     /* (uninteresting child of macro cmd) */
0057     QString name () const override { return {}; }
0058 
0059     kpCommandSize::SizeType size () const override
0060     {
0061         return ImageSize (m_oldImage) +
0062                SelectionSize (m_fromSelectionPtr) +
0063                ImageSize (m_imageIfFromSelectionDoesntHaveOne);
0064     }
0065 
0066     // ASSUMPTION: Document has been resized to be the same size as the
0067     //             selection.
0068     void execute () override;
0069     void unexecute () override;
0070 
0071 protected:
0072     kpColor m_backgroundColor;
0073     kpImage m_oldImage;
0074     kpAbstractImageSelection *m_fromSelectionPtr;
0075     kpImage m_imageIfFromSelectionDoesntHaveOne;
0076 };
0077 
0078 
0079 SetDocumentToSelectionImageCommand::SetDocumentToSelectionImageCommand (kpCommandEnvironment *environ)
0080     : kpCommand (environ),
0081       m_backgroundColor (environ->backgroundColor ()),
0082       m_fromSelectionPtr (
0083         dynamic_cast <kpAbstractImageSelection *> (
0084             environ->document ()->selection ()->clone ()))
0085 {
0086     Q_ASSERT (m_fromSelectionPtr);
0087 
0088     if ( m_fromSelectionPtr )  // make coverity happy
0089     {
0090       m_imageIfFromSelectionDoesntHaveOne =
0091         m_fromSelectionPtr->hasContent () ?
0092             kpImage () :
0093             document ()->getSelectedBaseImage ();
0094     }
0095 }
0096 
0097 //---------------------------------------------------------------------
0098 
0099 SetDocumentToSelectionImageCommand::~SetDocumentToSelectionImageCommand ()
0100 {
0101     delete m_fromSelectionPtr;
0102 }
0103 
0104 //---------------------------------------------------------------------
0105 
0106 // public virtual [base kpCommand]
0107 void SetDocumentToSelectionImageCommand::execute ()
0108 {
0109 #if DEBUG_KP_TOOL_CROP
0110     qCDebug(kpLogImagelib) << "SetDocumentToSelectionImageCommand::execute()";
0111 #endif
0112 
0113     viewManager ()->setQueueUpdates ();
0114     {
0115         // kpTransformCrop_ImageSelection's <resizeDocCommand> has
0116         // executed, resizing the document to be the size of the selection
0117         // bounding rectangle.
0118         Q_ASSERT (document ()->width () == m_fromSelectionPtr->width ());
0119         Q_ASSERT (document ()->height () == m_fromSelectionPtr->height ());
0120         m_oldImage = document ()->image ();
0121 
0122 
0123         //
0124         // e.g. original elliptical selection:
0125         //
0126         //     t/---\    T = original transparent selection pixel
0127         //     | TT |    t = outside the selection region
0128         //     t\__/t    [every other character] = original opaque selection pixel
0129         //
0130         // Afterwards, the _document_ image becomes:
0131         //
0132         //      b/---\   T = [unchanged]
0133         //      | TT |   b = background color
0134         //      b\__/b   [every other character] = [unchanged]
0135         //
0136         // The selection is deleted.
0137         //
0138         // TODO: Do not introduce a mask if the result will not contain
0139         //       any transparent pixels.
0140         //
0141 
0142         QImage newDocImage(document()->width(), document()->height(), QImage::Format_ARGB32_Premultiplied);
0143         newDocImage.fill(m_backgroundColor.toQRgb());
0144 
0145     #if DEBUG_KP_TOOL_CROP
0146         qCDebug(kpLogImagelib) << "\tsel: rect=" << m_fromSelectionPtr->boundingRect ()
0147                    << " pm=" << m_fromSelectionPtr->hasContent ();
0148     #endif
0149         QImage setTransparentImage;
0150 
0151         if (m_fromSelectionPtr->hasContent ())
0152         {
0153             setTransparentImage = m_fromSelectionPtr->transparentImage ();
0154 
0155         #if DEBUG_KP_TOOL_CROP
0156             qCDebug(kpLogImagelib) << "\thave pixmap; rect="
0157                        << setTransparentImage.rect ();
0158         #endif
0159         }
0160         else
0161         {
0162             setTransparentImage = m_imageIfFromSelectionDoesntHaveOne;
0163         #if DEBUG_KP_TOOL_CROP
0164             qCDebug(kpLogImagelib) << "\tno pixmap in sel - get it; rect="
0165                        << setTransparentImage.rect ();
0166         #endif
0167         }
0168 
0169         kpPixmapFX::paintPixmapAt (&newDocImage,
0170             QPoint (0, 0),
0171             setTransparentImage);
0172 
0173 
0174         document ()->setImageAt (newDocImage, QPoint (0, 0));
0175         document ()->selectionDelete ();
0176 
0177 
0178         environ ()->somethingBelowTheCursorChanged ();
0179     }
0180     viewManager ()->restoreQueueUpdates ();
0181 }
0182 
0183 //---------------------------------------------------------------------
0184 
0185 // public virtual [base kpCommand]
0186 void SetDocumentToSelectionImageCommand::unexecute ()
0187 {
0188 #if DEBUG_KP_TOOL_CROP
0189     qCDebug(kpLogImagelib) << "SetDocumentToSelectionImageCommand::unexecute()";
0190 #endif
0191 
0192     viewManager ()->setQueueUpdates ();
0193     {
0194         document ()->setImageAt (m_oldImage, QPoint (0, 0));
0195         m_oldImage = kpImage ();
0196 
0197     #if DEBUG_KP_TOOL_CROP
0198         qCDebug(kpLogImagelib) << "\tsel: rect=" << m_fromSelectionPtr->boundingRect ()
0199                    << " pm=" << m_fromSelectionPtr->hasContent ();
0200     #endif
0201         document ()->setSelection (*m_fromSelectionPtr);
0202 
0203         environ ()->somethingBelowTheCursorChanged ();
0204     }
0205     viewManager ()->restoreQueueUpdates ();
0206 }
0207 
0208 //---------------------------------------------------------------------
0209 
0210 
0211 void kpTransformCrop_ImageSelection (kpMainWindow *mainWindow,
0212         const QString &commandName, kpCommand *resizeDocCommand)
0213 {
0214     // Save starting selection, minus the border.
0215     auto *borderImageSel = dynamic_cast <kpAbstractImageSelection *> (
0216             mainWindow->document ()->selection ()->clone ());
0217 
0218     Q_ASSERT (borderImageSel);
0219 
0220     if ( !borderImageSel ) {  // make coverity happy
0221         return;
0222     }
0223 
0224     // (only interested in border)
0225     borderImageSel->deleteContent ();
0226     borderImageSel->moveTo (QPoint (0, 0));
0227 
0228     auto *environ = mainWindow->commandEnvironment ();
0229     auto *macroCmd = new kpMacroCommand (commandName, environ);
0230 
0231     // (must resize doc _before_ SetDocumentToSelectionImageCommand in case
0232     //  doc needs to gets bigger - else selection image may not fit)
0233     macroCmd->addCommand (resizeDocCommand);
0234 
0235 #if DEBUG_KP_TOOL_CROP
0236     qCDebug(kpLogImagelib) << "\tis pixmap sel";
0237     qCDebug(kpLogImagelib) << "\tcreating SetImage cmd";
0238 #endif
0239     macroCmd->addCommand (new SetDocumentToSelectionImageCommand (environ));
0240 
0241 
0242     mainWindow->addImageOrSelectionCommand (
0243         macroCmd,
0244         true/*add create cmd*/,
0245         false/*don't add pull cmd*/);
0246 
0247 
0248     // Add selection border back for convenience.
0249     mainWindow->commandHistory ()->addCommand (
0250         new kpToolSelectionCreateCommand (
0251             i18n ("Selection: Create"),
0252             *borderImageSel,
0253             mainWindow->commandEnvironment ()));
0254 
0255 
0256     delete borderImageSel;
0257 }