there is no moc file generated for this class
[kdegraphics.git] / kolourpaint / pixmapfx / kpPixmapFX_GetSetPixmapParts.cpp
blob9ddcbed60b47dd549c1bc7b32f2c957dac0fa1df
2 /*
3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
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>
34 #include <math.h>
36 #include <qapplication.h>
37 #include <qbitmap.h>
38 #include <qdatetime.h>
39 #include <qimage.h>
40 #include <qpainter.h>
41 #include <qpainterpath.h>
42 #include <qpixmap.h>
43 #include <qpoint.h>
44 #include <qpolygon.h>
45 #include <qrect.h>
47 #include <kconfig.h>
48 #include <kconfiggroup.h>
49 #include <kdebug.h>
50 #include <kglobal.h>
51 #include <klocale.h>
52 #include <kmessagebox.h>
54 #include <kpAbstractSelection.h>
55 #include <kpColor.h>
56 #include <kpDefs.h>
57 #include <kpTool.h>
60 struct GetSetPaintPixmapAtPack
62 const QPixmap *srcPixmap;
63 QPoint destTopLeft;
64 QRect validSrcRect;
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;
79 #endif
81 // Make sure "validSrcRect" lives up to its name.
82 Q_ASSERT (pack->validSrcRect.intersect (pack->srcPixmap->rect ()) ==
83 pack->validSrcRect);
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,
94 *pack->srcPixmap,
95 pack->validSrcRect);
97 else
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,
118 srcMask,
119 pack->validSrcRect);
123 // public static
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 ()
131 << ",rect="
132 << rect
133 << ")"
134 << endl;
135 #endif
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"
143 // ssss ssss
144 // +--------+
145 // ssss|SSSS |
146 // ssss|SSSS | <-- "rect"
147 // | |
148 // +--------+
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";
158 #endif
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";
168 #endif
169 return retPixmap;
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*/,
183 &pack);
186 #if DEBUG_KP_PIXMAP_FX && 1
187 kDebug () << "\tretPixmap.hasMask="
188 << !retPixmap.mask ().isNull ()
189 << endl;
190 #endif
192 KP_PFX_CHECK_NO_ALPHA_CHANNEL (retPixmap);
193 return retPixmap;
197 // public static
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 ()
206 << ",destRect="
207 << destRect
208 << ",srcPixmap.rect="
209 << srcPixmap.rect ()
210 << ",srcPixmap.hasMask="
211 << !srcPixmap.mask ().isNull ()
212 << ")"
213 << endl;
214 #endif
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);
225 int numTrans = 0;
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)
232 numTrans++;
236 kDebug () << "\tdestPixmapPtr numTrans=" << numTrans;
238 #endif
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*/,
254 &pack);
256 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr);
258 #if DEBUG_KP_PIXMAP_FX && 0
259 kDebug () << "\tdestPixmap->hasMask="
260 << !destPixmapPtr->mask ().isNull ()
261 << endl;
262 if (!destPixmapPtr->mask ().isNull ())
264 QImage image = kpPixmapFX::convertToQImage (*destPixmapPtr);
265 int numTrans = 0;
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)
272 numTrans++;
276 kDebug () << "\tdestPixmapPtr numTrans=" << numTrans;
278 #endif
281 // public static
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 ()),
288 srcPixmap);
291 // public static
292 void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
293 const QPixmap &srcPixmap)
295 kpPixmapFX::setPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap);
299 // public static
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)*/,
318 &pack);
320 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr);
323 // public static
324 void kpPixmapFX::paintPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
325 const QPixmap &srcPixmap)
327 kpPixmapFX::paintPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap);
331 // public static
332 kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, const QPoint &at)
334 #if DEBUG_KP_PIXMAP_FX && 0
335 kDebug () << "kpToolColorPicker::colorAtPixel" << p;
336 #endif
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);
346 if (image.isNull ())
348 kError () << "kpPixmapFX::getColorAtPixel(QPixmap) could not convert to QImage" << endl;
349 return kpColor::Invalid;
352 return getColorAtPixel (image, QPoint (0, 0));
355 // public static
356 kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, int x, int y)
358 return kpPixmapFX::getColorAtPixel (pm, QPoint (x, y));
361 // public static
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);
371 // public static
372 kpColor kpPixmapFX::getColorAtPixel (const QImage &img, int x, int y)
374 return kpPixmapFX::getColorAtPixel (img, QPoint (x, y));