3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #define DEBUG_KP_PIXMAP_FX 0
32 #include <kpPixmapFX.h>
36 #include <qapplication.h>
38 #include <qdatetime.h>
41 #include <qpainterpath.h>
48 #include <kconfiggroup.h>
52 #include <kmessagebox.h>
54 #include <kpAbstractSelection.h>
60 struct GetSetPaintPixmapAtPack
62 const QPixmap
*srcPixmap
;
65 bool isSettingPixelsNotPainting
;
68 static void GetSetPaintPixmapAtHelper (QPainter
*p
, bool drawingOnRGBLayer
, void *data
)
70 GetSetPaintPixmapAtPack
*pack
= static_cast <GetSetPaintPixmapAtPack
*> (data
);
72 #if DEBUG_KP_PIXMAP_FX
73 kDebug () << "kppixmapfx.cpp:GetSetPaintPixmapAtHelper(drawingOnRGBLayer="
74 << drawingOnRGBLayer
<< ")"
75 << " srcPixmap: rect=" << pack
->srcPixmap
->size ()
76 << " hasMask=" << kpPixmapFX::hasMask (*pack
->srcPixmap
)
77 << " destTopLeft=" << pack
->destTopLeft
78 << " validSrcRect=" << pack
->validSrcRect
<< endl
;
81 // Make sure "validSrcRect" lives up to its name.
82 Q_ASSERT (pack
->validSrcRect
.intersect (pack
->srcPixmap
->rect ()) ==
85 if (drawingOnRGBLayer
)
87 // <srcPixmap> is masked by its mask.
89 // For setting-pixels-mode, this doesn't matter since the mask will
90 // be copied, hiding the not-copied pixels.
92 // For painting-pixels-mode, this is the desired behaviour.
93 p
->drawPixmap (pack
->destTopLeft
,
99 const QBitmap srcMask
= kpPixmapFX::getNonNullMask (*pack
->srcPixmap
);
101 const QRect
destRect (pack
->destTopLeft
.x (), pack
->destTopLeft
.y (),
102 pack
->validSrcRect
.width (), pack
->validSrcRect
.height ());
104 // SYNC: Use a Qt "feature": QBitmap's (e.g. "srcMask") are considered to
105 // mask themselves (i.e. "srcMask.mask()" returns "srcMask" instead of
106 // "QBitmap()"). Therefore, "drawPixmap(srcMask)" can never create
107 // transparent pixels.
109 // This is the right behaviour for painting-pixels-mode
110 // (!isSettingPixelsNotPainting) but needs to be worked around for
111 // setting-pixels-mode (isSettingPixelsNotPainting).
112 if (pack
->isSettingPixelsNotPainting
)
114 p
->fillRect (destRect
, Qt::color0
/*transparent*/);
117 p
->drawPixmap (pack
->destTopLeft
,
124 QPixmap
kpPixmapFX::getPixmapAt (const QPixmap
&pm
, const QRect
&rect
)
126 QPixmap
retPixmap (rect
.width (), rect
.height ());
128 #if DEBUG_KP_PIXMAP_FX && 1
129 kDebug () << "kpPixmapFX::getPixmapAt(pm.hasMask="
130 << !pm
.mask ().isNull ()
137 KP_PFX_CHECK_NO_ALPHA_CHANNEL (pm
);
139 const QRect validSrcRect
= pm
.rect ().intersect (rect
);
140 const bool wouldHaveUndefinedPixels
= (validSrcRect
!= rect
);
142 // ssss ssss <-- "pm", "validSrcRect"
146 // ssss|SSSS | <-- "rect"
150 // Let 's' and 'S' be source (pm) pixels.
152 // If "rect" asks for part of the source (pm) and some more, the "some
153 // more" should be transparent - not undefined.
154 if (wouldHaveUndefinedPixels
)
156 #if DEBUG_KP_PIXMAP_FX && 1
157 kDebug () << "\tret would contain undefined pixels - setting them to transparent";
159 QBitmap
transparentMask (rect
.width (), rect
.height ());
160 transparentMask
.fill (Qt::color0
/*transparent*/);
161 retPixmap
.setMask (transparentMask
);
164 if (validSrcRect
.isEmpty ())
166 #if DEBUG_KP_PIXMAP_FX && 1
167 kDebug () << "\tsilly case - completely invalid rect - ret transparent pixmap";
172 // REFACTOR: we could call setPixmapAt().
173 GetSetPaintPixmapAtPack pack
;
174 pack
.srcPixmap
= &pm
;
175 pack
.destTopLeft
= validSrcRect
.topLeft () - rect
.topLeft ();
176 pack
.validSrcRect
= validSrcRect
;
177 pack
.isSettingPixelsNotPainting
= true;
179 kpPixmapFX::draw (&retPixmap
, &::GetSetPaintPixmapAtHelper
,
180 true/*always "draw"/copy RGB layer*/,
181 (kpPixmapFX::hasMask (retPixmap
) ||
182 kpPixmapFX::hasMask (pm
))/*draw on mask if either has one*/,
186 #if DEBUG_KP_PIXMAP_FX && 1
187 kDebug () << "\tretPixmap.hasMask="
188 << !retPixmap
.mask ().isNull ()
192 KP_PFX_CHECK_NO_ALPHA_CHANNEL (retPixmap
);
198 void kpPixmapFX::setPixmapAt (QPixmap
*destPixmapPtr
, const QRect
&destRect
,
199 const QPixmap
&srcPixmap
)
201 #if DEBUG_KP_PIXMAP_FX && 1
202 kDebug () << "kpPixmapFX::setPixmapAt(destPixmap->rect="
203 << destPixmapPtr
->rect ()
204 << ",destPixmap->hasMask="
205 << !destPixmapPtr
->mask ().isNull ()
208 << ",srcPixmap.rect="
210 << ",srcPixmap.hasMask="
211 << !srcPixmap
.mask ().isNull ()
216 Q_ASSERT (destPixmapPtr
);
218 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
219 KP_PFX_CHECK_NO_ALPHA_CHANNEL (srcPixmap
);
221 #if DEBUG_KP_PIXMAP_FX && 0
222 if (!destPixmapPtr
->mask ().isNull ())
224 QImage image
= kpPixmapFX::convertToQImage (*destPixmapPtr
);
227 for (int y
= 0; y
< image
.height (); y
++)
229 for (int x
= 0; x
< image
.width (); x
++)
231 if (qAlpha (image
.pixel (x
, y
)) == 0)
236 kDebug () << "\tdestPixmapPtr numTrans=" << numTrans
;
240 // You cannot copy more than what you have.
241 Q_ASSERT (destRect
.width () <= srcPixmap
.width () &&
242 destRect
.height () <= srcPixmap
.height ());
244 GetSetPaintPixmapAtPack pack
;
245 pack
.srcPixmap
= &srcPixmap
;
246 pack
.destTopLeft
= destRect
.topLeft ();
247 pack
.validSrcRect
= QRect (0, 0, destRect
.width (), destRect
.height ());
248 pack
.isSettingPixelsNotPainting
= true;
250 kpPixmapFX::draw (destPixmapPtr
, &::GetSetPaintPixmapAtHelper
,
251 true/*always "draw"/copy RGB layer*/,
252 (kpPixmapFX::hasMask (*destPixmapPtr
) ||
253 kpPixmapFX::hasMask (srcPixmap
))/*draw on mask if either has one*/,
256 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
258 #if DEBUG_KP_PIXMAP_FX && 0
259 kDebug () << "\tdestPixmap->hasMask="
260 << !destPixmapPtr
->mask ().isNull ()
262 if (!destPixmapPtr
->mask ().isNull ())
264 QImage image
= kpPixmapFX::convertToQImage (*destPixmapPtr
);
267 for (int y
= 0; y
< image
.height (); y
++)
269 for (int x
= 0; x
< image
.width (); x
++)
271 if (qAlpha (image
.pixel (x
, y
)) == 0)
276 kDebug () << "\tdestPixmapPtr numTrans=" << numTrans
;
282 void kpPixmapFX::setPixmapAt (QPixmap
*destPixmapPtr
, const QPoint
&destAt
,
283 const QPixmap
&srcPixmap
)
285 kpPixmapFX::setPixmapAt (destPixmapPtr
,
286 QRect (destAt
.x (), destAt
.y (),
287 srcPixmap
.width (), srcPixmap
.height ()),
292 void kpPixmapFX::setPixmapAt (QPixmap
*destPixmapPtr
, int destX
, int destY
,
293 const QPixmap
&srcPixmap
)
295 kpPixmapFX::setPixmapAt (destPixmapPtr
, QPoint (destX
, destY
), srcPixmap
);
300 void kpPixmapFX::paintPixmapAt (QPixmap
*destPixmapPtr
, const QPoint
&destAt
,
301 const QPixmap
&srcPixmap
)
303 Q_ASSERT (destPixmapPtr
);
305 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
306 KP_PFX_CHECK_NO_ALPHA_CHANNEL (srcPixmap
);
308 GetSetPaintPixmapAtPack pack
;
309 pack
.srcPixmap
= &srcPixmap
;
310 pack
.destTopLeft
= destAt
;
311 pack
.validSrcRect
= QRect (0, 0, srcPixmap
.width (), srcPixmap
.height ());
312 pack
.isSettingPixelsNotPainting
= false;
314 kpPixmapFX::draw (destPixmapPtr
, &::GetSetPaintPixmapAtHelper
,
315 true/*always "draw"/copy RGB layer*/,
316 kpPixmapFX::hasMask (*destPixmapPtr
)/*draw on mask only if dest already has one
317 (the src will still be masked by its mask if it has one)*/,
320 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
324 void kpPixmapFX::paintPixmapAt (QPixmap
*destPixmapPtr
, int destX
, int destY
,
325 const QPixmap
&srcPixmap
)
327 kpPixmapFX::paintPixmapAt (destPixmapPtr
, QPoint (destX
, destY
), srcPixmap
);
332 kpColor
kpPixmapFX::getColorAtPixel (const QPixmap
&pm
, const QPoint
&at
)
334 #if DEBUG_KP_PIXMAP_FX && 0
335 kDebug () << "kpToolColorPicker::colorAtPixel" << p
;
338 if (at
.x () < 0 || at
.x () >= pm
.width () ||
339 at
.y () < 0 || at
.y () >= pm
.height ())
341 return kpColor::Invalid
;
344 QPixmap pixmap
= getPixmapAt (pm
, QRect (at
, at
));
345 QImage image
= kpPixmapFX::convertToQImage (pixmap
);
348 kError () << "kpPixmapFX::getColorAtPixel(QPixmap) could not convert to QImage" << endl
;
349 return kpColor::Invalid
;
352 return getColorAtPixel (image
, QPoint (0, 0));
356 kpColor
kpPixmapFX::getColorAtPixel (const QPixmap
&pm
, int x
, int y
)
358 return kpPixmapFX::getColorAtPixel (pm
, QPoint (x
, y
));
362 kpColor
kpPixmapFX::getColorAtPixel (const QImage
&img
, const QPoint
&at
)
364 if (!img
.valid (at
.x (), at
.y ()))
365 return kpColor::Invalid
;
367 QRgb rgba
= img
.pixel (at
.x (), at
.y ());
368 return kpColor (rgba
);
372 kpColor
kpPixmapFX::getColorAtPixel (const QImage
&img
, int x
, int y
)
374 return kpPixmapFX::getColorAtPixel (img
, QPoint (x
, y
));