Add remaining files
[juce-lv2.git] / juce / source / src / gui / graphics / imaging / juce_Image.cpp
blob74c70c35af00f08fc5e35bafad39603cd1ada6cd
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_Image.h"
31 #include "../contexts/juce_Graphics.h"
32 #include "../contexts/juce_LowLevelGraphicsSoftwareRenderer.h"
33 #include "../colour/juce_PixelFormats.h"
34 #include "../../../containers/juce_SparseSet.h"
37 //==============================================================================
38 Image::SharedImage::SharedImage (const PixelFormat format_, const int width_, const int height_)
39 : format (format_), width (width_), height (height_)
41 jassert (format_ == RGB || format_ == ARGB || format_ == SingleChannel);
42 jassert (width > 0 && height > 0); // It's illegal to create a zero-sized image!
45 Image::SharedImage::~SharedImage()
49 //==============================================================================
50 class SoftwareSharedImage : public Image::SharedImage
52 public:
53 SoftwareSharedImage (const Image::PixelFormat format_, const int width_, const int height_, const bool clearImage)
54 : Image::SharedImage (format_, width_, height_),
55 pixelStride (format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1)),
56 lineStride ((pixelStride * jmax (1, width_) + 3) & ~3)
58 imageData.allocate (lineStride * jmax (1, height_), clearImage);
61 Image::ImageType getType() const
63 return Image::SoftwareImage;
66 LowLevelGraphicsContext* createLowLevelContext()
68 return new LowLevelGraphicsSoftwareRenderer (Image (this));
71 void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/)
73 bitmap.data = imageData + x * pixelStride + y * lineStride;
74 bitmap.pixelFormat = format;
75 bitmap.lineStride = lineStride;
76 bitmap.pixelStride = pixelStride;
79 Image::SharedImage* clone()
81 SoftwareSharedImage* s = new SoftwareSharedImage (format, width, height, false);
82 memcpy (s->imageData, imageData, lineStride * height);
83 return s;
86 private:
87 HeapBlock<uint8> imageData;
88 const int pixelStride, lineStride;
90 JUCE_LEAK_DETECTOR (SoftwareSharedImage);
93 Image::SharedImage* Image::SharedImage::createSoftwareImage (Image::PixelFormat format, int width, int height, bool clearImage)
95 return new SoftwareSharedImage (format, width, height, clearImage);
98 //==============================================================================
99 class SubsectionSharedImage : public Image::SharedImage
101 public:
102 SubsectionSharedImage (Image::SharedImage* const image_, const Rectangle<int>& area_)
103 : Image::SharedImage (image_->getPixelFormat(), area_.getWidth(), area_.getHeight()),
104 image (image_), area (area_)
108 Image::ImageType getType() const
110 return Image::SoftwareImage;
113 LowLevelGraphicsContext* createLowLevelContext()
115 LowLevelGraphicsContext* g = image->createLowLevelContext();
116 g->clipToRectangle (area);
117 g->setOrigin (area.getX(), area.getY());
118 return g;
121 void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode)
123 image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode);
126 Image::SharedImage* clone()
128 return new SubsectionSharedImage (image->clone(), area);
131 private:
132 const ReferenceCountedObjectPtr<Image::SharedImage> image;
133 const Rectangle<int> area;
135 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubsectionSharedImage);
138 Image Image::getClippedImage (const Rectangle<int>& area) const
140 if (area.contains (getBounds()))
141 return *this;
143 const Rectangle<int> validArea (area.getIntersection (getBounds()));
144 if (validArea.isEmpty())
145 return Image::null;
147 return Image (new SubsectionSharedImage (image, validArea));
151 //==============================================================================
152 Image::Image()
156 Image::Image (SharedImage* const instance)
157 : image (instance)
161 Image::Image (const PixelFormat format,
162 const int width, const int height,
163 const bool clearImage, const ImageType type)
164 : image (type == Image::NativeImage ? SharedImage::createNativeImage (format, width, height, clearImage)
165 : new SoftwareSharedImage (format, width, height, clearImage))
169 Image::Image (const Image& other)
170 : image (other.image)
174 Image& Image::operator= (const Image& other)
176 image = other.image;
177 return *this;
180 Image::~Image()
184 const Image Image::null;
186 LowLevelGraphicsContext* Image::createLowLevelContext() const
188 return image == nullptr ? nullptr : image->createLowLevelContext();
191 void Image::duplicateIfShared()
193 if (image != nullptr && image->getReferenceCount() > 1)
194 image = image->clone();
197 Image Image::rescaled (const int newWidth, const int newHeight, const Graphics::ResamplingQuality quality) const
199 if (image == nullptr || (image->width == newWidth && image->height == newHeight))
200 return *this;
202 Image newImage (image->format, newWidth, newHeight, hasAlphaChannel(), image->getType());
204 Graphics g (newImage);
205 g.setImageResamplingQuality (quality);
206 g.drawImage (*this, 0, 0, newWidth, newHeight, 0, 0, image->width, image->height, false);
208 return newImage;
211 Image Image::convertedToFormat (PixelFormat newFormat) const
213 if (image == nullptr || newFormat == image->format)
214 return *this;
216 const int w = image->width, h = image->height;
217 Image newImage (newFormat, w, h, false, image->getType());
219 if (newFormat == SingleChannel)
221 if (! hasAlphaChannel())
223 newImage.clear (getBounds(), Colours::black);
225 else
227 const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
228 const BitmapData srcData (*this, 0, 0, w, h);
230 for (int y = 0; y < h; ++y)
232 const PixelARGB* src = (const PixelARGB*) srcData.getLinePointer(y);
233 uint8* dst = destData.getLinePointer (y);
235 for (int x = w; --x >= 0;)
237 *dst++ = src->getAlpha();
238 ++src;
243 else
245 if (hasAlphaChannel())
246 newImage.clear (getBounds());
248 Graphics g (newImage);
249 g.drawImageAt (*this, 0, 0);
252 return newImage;
255 NamedValueSet* Image::getProperties() const
257 return image == nullptr ? nullptr : &(image->userData);
260 //==============================================================================
261 Image::BitmapData::BitmapData (Image& image, const int x, const int y, const int w, const int h, BitmapData::ReadWriteMode mode)
262 : width (w),
263 height (h)
265 // The BitmapData class must be given a valid image, and a valid rectangle within it!
266 jassert (image.image != nullptr);
267 jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight());
269 image.image->initialiseBitmapData (*this, x, y, mode);
270 jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
273 Image::BitmapData::BitmapData (const Image& image, const int x, const int y, const int w, const int h)
274 : width (w),
275 height (h)
277 // The BitmapData class must be given a valid image, and a valid rectangle within it!
278 jassert (image.image != nullptr);
279 jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight());
281 image.image->initialiseBitmapData (*this, x, y, readOnly);
282 jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
285 Image::BitmapData::BitmapData (const Image& image, BitmapData::ReadWriteMode mode)
286 : width (image.getWidth()),
287 height (image.getHeight())
289 // The BitmapData class must be given a valid image!
290 jassert (image.image != nullptr);
292 image.image->initialiseBitmapData (*this, 0, 0, mode);
293 jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
296 Image::BitmapData::~BitmapData()
300 const Colour Image::BitmapData::getPixelColour (const int x, const int y) const noexcept
302 jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height));
304 const uint8* const pixel = getPixelPointer (x, y);
306 switch (pixelFormat)
308 case Image::ARGB: return Colour (((const PixelARGB*) pixel)->getUnpremultipliedARGB());
309 case Image::RGB: return Colour (((const PixelRGB*) pixel)->getUnpremultipliedARGB());
310 case Image::SingleChannel: return Colour (((const PixelAlpha*) pixel)->getUnpremultipliedARGB());
311 default: jassertfalse; break;
314 return Colour();
317 void Image::BitmapData::setPixelColour (const int x, const int y, const Colour& colour) const noexcept
319 jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height));
321 uint8* const pixel = getPixelPointer (x, y);
322 const PixelARGB col (colour.getPixelARGB());
324 switch (pixelFormat)
326 case Image::ARGB: ((PixelARGB*) pixel)->set (col); break;
327 case Image::RGB: ((PixelRGB*) pixel)->set (col); break;
328 case Image::SingleChannel: *pixel = col.getAlpha(); break;
329 default: jassertfalse; break;
333 void Image::setPixelData (int x, int y, int w, int h,
334 const uint8* const sourcePixelData, const int sourceLineStride)
336 jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= getWidth() && y + h <= getHeight());
338 if (Rectangle<int>::intersectRectangles (x, y, w, h, 0, 0, getWidth(), getHeight()))
340 const BitmapData dest (*this, x, y, w, h, BitmapData::writeOnly);
342 for (int i = 0; i < h; ++i)
344 memcpy (dest.getLinePointer(i),
345 sourcePixelData + sourceLineStride * i,
346 w * dest.pixelStride);
351 //==============================================================================
352 void Image::clear (const Rectangle<int>& area, const Colour& colourToClearTo)
354 const Rectangle<int> clipped (area.getIntersection (getBounds()));
356 if (! clipped.isEmpty())
358 const PixelARGB col (colourToClearTo.getPixelARGB());
360 const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), BitmapData::writeOnly);
361 uint8* dest = destData.data;
362 int dh = clipped.getHeight();
364 while (--dh >= 0)
366 uint8* line = dest;
367 dest += destData.lineStride;
369 if (isARGB())
371 for (int x = clipped.getWidth(); --x >= 0;)
373 ((PixelARGB*) line)->set (col);
374 line += destData.pixelStride;
377 else if (isRGB())
379 for (int x = clipped.getWidth(); --x >= 0;)
381 ((PixelRGB*) line)->set (col);
382 line += destData.pixelStride;
385 else
387 for (int x = clipped.getWidth(); --x >= 0;)
389 *line = col.getAlpha();
390 line += destData.pixelStride;
397 //==============================================================================
398 const Colour Image::getPixelAt (const int x, const int y) const
400 if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()))
402 const BitmapData srcData (*this, x, y, 1, 1);
403 return srcData.getPixelColour (0, 0);
406 return Colour();
409 void Image::setPixelAt (const int x, const int y, const Colour& colour)
411 if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()))
413 const BitmapData destData (*this, x, y, 1, 1, BitmapData::writeOnly);
414 destData.setPixelColour (0, 0, colour);
418 void Image::multiplyAlphaAt (const int x, const int y, const float multiplier)
420 if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())
421 && hasAlphaChannel())
423 const BitmapData destData (*this, x, y, 1, 1, BitmapData::readWrite);
425 if (isARGB())
426 ((PixelARGB*) destData.data)->multiplyAlpha (multiplier);
427 else
428 *(destData.data) = (uint8) (*(destData.data) * multiplier);
432 void Image::multiplyAllAlphas (const float amountToMultiplyBy)
434 if (hasAlphaChannel())
436 const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
438 if (isARGB())
440 for (int y = 0; y < destData.height; ++y)
442 uint8* p = destData.getLinePointer (y);
444 for (int x = 0; x < destData.width; ++x)
446 ((PixelARGB*) p)->multiplyAlpha (amountToMultiplyBy);
447 p += destData.pixelStride;
451 else
453 for (int y = 0; y < destData.height; ++y)
455 uint8* p = destData.getLinePointer (y);
457 for (int x = 0; x < destData.width; ++x)
459 *p = (uint8) (*p * amountToMultiplyBy);
460 p += destData.pixelStride;
465 else
467 jassertfalse; // can't do this without an alpha-channel!
471 void Image::desaturate()
473 if (isARGB() || isRGB())
475 const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
477 if (isARGB())
479 for (int y = 0; y < destData.height; ++y)
481 uint8* p = destData.getLinePointer (y);
483 for (int x = 0; x < destData.width; ++x)
485 ((PixelARGB*) p)->desaturate();
486 p += destData.pixelStride;
490 else
492 for (int y = 0; y < destData.height; ++y)
494 uint8* p = destData.getLinePointer (y);
496 for (int x = 0; x < destData.width; ++x)
498 ((PixelRGB*) p)->desaturate();
499 p += destData.pixelStride;
506 void Image::createSolidAreaMask (RectangleList& result, const float alphaThreshold) const
508 if (hasAlphaChannel())
510 const uint8 threshold = (uint8) jlimit (0, 255, roundToInt (alphaThreshold * 255.0f));
511 SparseSet<int> pixelsOnRow;
513 const BitmapData srcData (*this, 0, 0, getWidth(), getHeight());
515 for (int y = 0; y < srcData.height; ++y)
517 pixelsOnRow.clear();
518 const uint8* lineData = srcData.getLinePointer (y);
520 if (isARGB())
522 for (int x = 0; x < srcData.width; ++x)
524 if (((const PixelARGB*) lineData)->getAlpha() >= threshold)
525 pixelsOnRow.addRange (Range<int> (x, x + 1));
527 lineData += srcData.pixelStride;
530 else
532 for (int x = 0; x < srcData.width; ++x)
534 if (*lineData >= threshold)
535 pixelsOnRow.addRange (Range<int> (x, x + 1));
537 lineData += srcData.pixelStride;
541 for (int i = 0; i < pixelsOnRow.getNumRanges(); ++i)
543 const Range<int> range (pixelsOnRow.getRange (i));
544 result.add (Rectangle<int> (range.getStart(), y, range.getLength(), 1));
547 result.consolidate();
550 else
552 result.add (0, 0, getWidth(), getHeight());
556 void Image::moveImageSection (int dx, int dy,
557 int sx, int sy,
558 int w, int h)
560 if (dx < 0)
562 w += dx;
563 sx -= dx;
564 dx = 0;
567 if (dy < 0)
569 h += dy;
570 sy -= dy;
571 dy = 0;
574 if (sx < 0)
576 w += sx;
577 dx -= sx;
578 sx = 0;
581 if (sy < 0)
583 h += sy;
584 dy -= sy;
585 sy = 0;
588 const int minX = jmin (dx, sx);
589 const int minY = jmin (dy, sy);
591 w = jmin (w, getWidth() - jmax (sx, dx));
592 h = jmin (h, getHeight() - jmax (sy, dy));
594 if (w > 0 && h > 0)
596 const int maxX = jmax (dx, sx) + w;
597 const int maxY = jmax (dy, sy) + h;
599 const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite);
601 uint8* dst = destData.getPixelPointer (dx - minX, dy - minY);
602 const uint8* src = destData.getPixelPointer (sx - minX, sy - minY);
604 const int lineSize = destData.pixelStride * w;
606 if (dy > sy)
608 while (--h >= 0)
610 const int offset = h * destData.lineStride;
611 memmove (dst + offset, src + offset, lineSize);
614 else if (dst != src)
616 while (--h >= 0)
618 memmove (dst, src, lineSize);
619 dst += destData.lineStride;
620 src += destData.lineStride;
627 END_JUCE_NAMESPACE