The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

699 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. ImagePixelData::ImagePixelData (Image::PixelFormat format, int w, int h)
  21. : pixelFormat (format), width (w), height (h)
  22. {
  23. jassert (format == Image::RGB || format == Image::ARGB || format == Image::SingleChannel);
  24. jassert (w > 0 && h > 0); // It's illegal to create a zero-sized image!
  25. }
  26. ImagePixelData::~ImagePixelData()
  27. {
  28. listeners.call ([this] (Listener& l) { l.imageDataBeingDeleted (this); });
  29. }
  30. void ImagePixelData::sendDataChangeMessage()
  31. {
  32. listeners.call ([this] (Listener& l) { l.imageDataChanged (this); });
  33. }
  34. int ImagePixelData::getSharedCount() const noexcept
  35. {
  36. return getReferenceCount();
  37. }
  38. //==============================================================================
  39. ImageType::ImageType() {}
  40. ImageType::~ImageType() {}
  41. Image ImageType::convert (const Image& source) const
  42. {
  43. if (source.isNull() || getTypeID() == source.getPixelData()->createType()->getTypeID())
  44. return source;
  45. const Image::BitmapData src (source, Image::BitmapData::readOnly);
  46. Image newImage (create (src.pixelFormat, src.width, src.height, false));
  47. Image::BitmapData dest (newImage, Image::BitmapData::writeOnly);
  48. if (src.pixelStride == dest.pixelStride && src.pixelFormat == dest.pixelFormat)
  49. {
  50. for (int y = 0; y < dest.height; ++y)
  51. memcpy (dest.getLinePointer (y), src.getLinePointer (y), (size_t) dest.lineStride);
  52. }
  53. else
  54. {
  55. for (int y = 0; y < dest.height; ++y)
  56. for (int x = 0; x < dest.width; ++x)
  57. dest.setPixelColour (x, y, src.getPixelColour (x, y));
  58. }
  59. return newImage;
  60. }
  61. //==============================================================================
  62. class SoftwarePixelData : public ImagePixelData
  63. {
  64. public:
  65. SoftwarePixelData (Image::PixelFormat formatToUse, int w, int h, bool clearImage)
  66. : ImagePixelData (formatToUse, w, h),
  67. pixelStride (formatToUse == Image::RGB ? 3 : ((formatToUse == Image::ARGB) ? 4 : 1)),
  68. lineStride ((pixelStride * jmax (1, w) + 3) & ~3)
  69. {
  70. imageData.allocate ((size_t) lineStride * (size_t) jmax (1, h), clearImage);
  71. }
  72. std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
  73. {
  74. sendDataChangeMessage();
  75. return std::make_unique<LowLevelGraphicsSoftwareRenderer> (Image (*this));
  76. }
  77. void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
  78. {
  79. bitmap.data = imageData + (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride;
  80. bitmap.pixelFormat = pixelFormat;
  81. bitmap.lineStride = lineStride;
  82. bitmap.pixelStride = pixelStride;
  83. if (mode != Image::BitmapData::readOnly)
  84. sendDataChangeMessage();
  85. }
  86. ImagePixelData::Ptr clone() override
  87. {
  88. auto s = new SoftwarePixelData (pixelFormat, width, height, false);
  89. memcpy (s->imageData, imageData, (size_t) lineStride * (size_t) height);
  90. return *s;
  91. }
  92. std::unique_ptr<ImageType> createType() const override { return std::make_unique<SoftwareImageType>(); }
  93. private:
  94. HeapBlock<uint8> imageData;
  95. const int pixelStride, lineStride;
  96. JUCE_LEAK_DETECTOR (SoftwarePixelData)
  97. };
  98. SoftwareImageType::SoftwareImageType() {}
  99. SoftwareImageType::~SoftwareImageType() {}
  100. ImagePixelData::Ptr SoftwareImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
  101. {
  102. return *new SoftwarePixelData (format, width, height, clearImage);
  103. }
  104. int SoftwareImageType::getTypeID() const
  105. {
  106. return 2;
  107. }
  108. //==============================================================================
  109. NativeImageType::NativeImageType() {}
  110. NativeImageType::~NativeImageType() {}
  111. int NativeImageType::getTypeID() const
  112. {
  113. return 1;
  114. }
  115. #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD
  116. ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
  117. {
  118. return new SoftwarePixelData (format, width, height, clearImage);
  119. }
  120. #endif
  121. //==============================================================================
  122. class SubsectionPixelData : public ImagePixelData
  123. {
  124. public:
  125. SubsectionPixelData (ImagePixelData::Ptr source, Rectangle<int> r)
  126. : ImagePixelData (source->pixelFormat, r.getWidth(), r.getHeight()),
  127. sourceImage (std::move (source)), area (r)
  128. {
  129. }
  130. std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
  131. {
  132. auto g = sourceImage->createLowLevelContext();
  133. g->clipToRectangle (area);
  134. g->setOrigin (area.getPosition());
  135. return g;
  136. }
  137. void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
  138. {
  139. sourceImage->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode);
  140. if (mode != Image::BitmapData::readOnly)
  141. sendDataChangeMessage();
  142. }
  143. ImagePixelData::Ptr clone() override
  144. {
  145. jassert (getReferenceCount() > 0); // (This method can't be used on an unowned pointer, as it will end up self-deleting)
  146. auto type = createType();
  147. Image newImage (type->create (pixelFormat, area.getWidth(), area.getHeight(), pixelFormat != Image::RGB));
  148. {
  149. Graphics g (newImage);
  150. g.drawImageAt (Image (*this), 0, 0);
  151. }
  152. return *newImage.getPixelData();
  153. }
  154. std::unique_ptr<ImageType> createType() const override { return sourceImage->createType(); }
  155. /* as we always hold a reference to image, don't double count */
  156. int getSharedCount() const noexcept override { return getReferenceCount() + sourceImage->getSharedCount() - 1; }
  157. private:
  158. friend class Image;
  159. const ImagePixelData::Ptr sourceImage;
  160. const Rectangle<int> area;
  161. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubsectionPixelData)
  162. };
  163. Image Image::getClippedImage (const Rectangle<int>& area) const
  164. {
  165. if (area.contains (getBounds()))
  166. return *this;
  167. auto validArea = area.getIntersection (getBounds());
  168. if (validArea.isEmpty())
  169. return {};
  170. return Image (*new SubsectionPixelData (image, validArea));
  171. }
  172. //==============================================================================
  173. Image::Image() noexcept
  174. {
  175. }
  176. Image::Image (ReferenceCountedObjectPtr<ImagePixelData> instance) noexcept
  177. : image (std::move (instance))
  178. {
  179. }
  180. Image::Image (PixelFormat format, int width, int height, bool clearImage)
  181. : image (NativeImageType().create (format, width, height, clearImage))
  182. {
  183. }
  184. Image::Image (PixelFormat format, int width, int height, bool clearImage, const ImageType& type)
  185. : image (type.create (format, width, height, clearImage))
  186. {
  187. }
  188. Image::Image (const Image& other) noexcept
  189. : image (other.image)
  190. {
  191. }
  192. Image& Image::operator= (const Image& other)
  193. {
  194. image = other.image;
  195. return *this;
  196. }
  197. Image::Image (Image&& other) noexcept
  198. : image (std::move (other.image))
  199. {
  200. }
  201. Image& Image::operator= (Image&& other) noexcept
  202. {
  203. image = std::move (other.image);
  204. return *this;
  205. }
  206. Image::~Image()
  207. {
  208. }
  209. int Image::getReferenceCount() const noexcept { return image == nullptr ? 0 : image->getSharedCount(); }
  210. int Image::getWidth() const noexcept { return image == nullptr ? 0 : image->width; }
  211. int Image::getHeight() const noexcept { return image == nullptr ? 0 : image->height; }
  212. Rectangle<int> Image::getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); }
  213. Image::PixelFormat Image::getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->pixelFormat; }
  214. bool Image::isARGB() const noexcept { return getFormat() == ARGB; }
  215. bool Image::isRGB() const noexcept { return getFormat() == RGB; }
  216. bool Image::isSingleChannel() const noexcept { return getFormat() == SingleChannel; }
  217. bool Image::hasAlphaChannel() const noexcept { return getFormat() != RGB; }
  218. std::unique_ptr<LowLevelGraphicsContext> Image::createLowLevelContext() const
  219. {
  220. if (image != nullptr)
  221. return image->createLowLevelContext();
  222. return {};
  223. }
  224. void Image::duplicateIfShared()
  225. {
  226. if (getReferenceCount() > 1)
  227. image = image->clone();
  228. }
  229. Image Image::createCopy() const
  230. {
  231. if (image != nullptr)
  232. return Image (image->clone());
  233. return {};
  234. }
  235. Image Image::rescaled (int newWidth, int newHeight, Graphics::ResamplingQuality quality) const
  236. {
  237. if (image == nullptr || (image->width == newWidth && image->height == newHeight))
  238. return *this;
  239. auto type = image->createType();
  240. Image newImage (type->create (image->pixelFormat, newWidth, newHeight, hasAlphaChannel()));
  241. Graphics g (newImage);
  242. g.setImageResamplingQuality (quality);
  243. g.drawImageTransformed (*this, AffineTransform::scale ((float) newWidth / (float) image->width,
  244. (float) newHeight / (float) image->height), false);
  245. return newImage;
  246. }
  247. Image Image::convertedToFormat (PixelFormat newFormat) const
  248. {
  249. if (image == nullptr || newFormat == image->pixelFormat)
  250. return *this;
  251. auto w = image->width, h = image->height;
  252. auto type = image->createType();
  253. Image newImage (type->create (newFormat, w, h, false));
  254. if (newFormat == SingleChannel)
  255. {
  256. if (! hasAlphaChannel())
  257. {
  258. newImage.clear (getBounds(), Colours::black);
  259. }
  260. else
  261. {
  262. const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
  263. const BitmapData srcData (*this, 0, 0, w, h);
  264. for (int y = 0; y < h; ++y)
  265. {
  266. auto src = reinterpret_cast<const PixelARGB*> (srcData.getLinePointer (y));
  267. auto dst = destData.getLinePointer (y);
  268. for (int x = 0; x < w; ++x)
  269. dst[x] = src[x].getAlpha();
  270. }
  271. }
  272. }
  273. else if (image->pixelFormat == SingleChannel && newFormat == Image::ARGB)
  274. {
  275. const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
  276. const BitmapData srcData (*this, 0, 0, w, h);
  277. for (int y = 0; y < h; ++y)
  278. {
  279. auto src = reinterpret_cast<const PixelAlpha*> (srcData.getLinePointer (y));
  280. auto dst = reinterpret_cast<PixelARGB*> (destData.getLinePointer (y));
  281. for (int x = 0; x < w; ++x)
  282. dst[x].set (src[x]);
  283. }
  284. }
  285. else
  286. {
  287. if (hasAlphaChannel())
  288. newImage.clear (getBounds());
  289. Graphics g (newImage);
  290. g.drawImageAt (*this, 0, 0);
  291. }
  292. return newImage;
  293. }
  294. NamedValueSet* Image::getProperties() const
  295. {
  296. return image == nullptr ? nullptr : &(image->userData);
  297. }
  298. //==============================================================================
  299. Image::BitmapData::BitmapData (Image& im, int x, int y, int w, int h, BitmapData::ReadWriteMode mode)
  300. : width (w), height (h)
  301. {
  302. // The BitmapData class must be given a valid image, and a valid rectangle within it!
  303. jassert (im.image != nullptr);
  304. jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= im.getWidth() && y + h <= im.getHeight());
  305. im.image->initialiseBitmapData (*this, x, y, mode);
  306. jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
  307. }
  308. Image::BitmapData::BitmapData (const Image& im, int x, int y, int w, int h)
  309. : width (w), height (h)
  310. {
  311. // The BitmapData class must be given a valid image, and a valid rectangle within it!
  312. jassert (im.image != nullptr);
  313. jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= im.getWidth() && y + h <= im.getHeight());
  314. im.image->initialiseBitmapData (*this, x, y, readOnly);
  315. jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
  316. }
  317. Image::BitmapData::BitmapData (const Image& im, BitmapData::ReadWriteMode mode)
  318. : width (im.getWidth()),
  319. height (im.getHeight())
  320. {
  321. // The BitmapData class must be given a valid image!
  322. jassert (im.image != nullptr);
  323. im.image->initialiseBitmapData (*this, 0, 0, mode);
  324. jassert (data != nullptr && pixelStride > 0 && lineStride != 0);
  325. }
  326. Image::BitmapData::~BitmapData()
  327. {
  328. }
  329. Colour Image::BitmapData::getPixelColour (int x, int y) const noexcept
  330. {
  331. jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height));
  332. auto pixel = getPixelPointer (x, y);
  333. switch (pixelFormat)
  334. {
  335. case Image::ARGB: return Colour ( ((const PixelARGB*) pixel)->getUnpremultiplied());
  336. case Image::RGB: return Colour (*((const PixelRGB*) pixel));
  337. case Image::SingleChannel: return Colour (*((const PixelAlpha*) pixel));
  338. case Image::UnknownFormat:
  339. default: jassertfalse; break;
  340. }
  341. return {};
  342. }
  343. void Image::BitmapData::setPixelColour (int x, int y, Colour colour) const noexcept
  344. {
  345. jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height));
  346. auto pixel = getPixelPointer (x, y);
  347. auto col = colour.getPixelARGB();
  348. switch (pixelFormat)
  349. {
  350. case Image::ARGB: ((PixelARGB*) pixel)->set (col); break;
  351. case Image::RGB: ((PixelRGB*) pixel)->set (col); break;
  352. case Image::SingleChannel: ((PixelAlpha*) pixel)->set (col); break;
  353. case Image::UnknownFormat:
  354. default: jassertfalse; break;
  355. }
  356. }
  357. //==============================================================================
  358. void Image::clear (const Rectangle<int>& area, Colour colourToClearTo)
  359. {
  360. if (image != nullptr)
  361. {
  362. auto g = image->createLowLevelContext();
  363. g->setFill (colourToClearTo);
  364. g->fillRect (area, true);
  365. }
  366. }
  367. //==============================================================================
  368. Colour Image::getPixelAt (int x, int y) const
  369. {
  370. if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()))
  371. {
  372. const BitmapData srcData (*this, x, y, 1, 1);
  373. return srcData.getPixelColour (0, 0);
  374. }
  375. return {};
  376. }
  377. void Image::setPixelAt (int x, int y, Colour colour)
  378. {
  379. if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()))
  380. {
  381. const BitmapData destData (*this, x, y, 1, 1, BitmapData::writeOnly);
  382. destData.setPixelColour (0, 0, colour);
  383. }
  384. }
  385. void Image::multiplyAlphaAt (int x, int y, float multiplier)
  386. {
  387. if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())
  388. && hasAlphaChannel())
  389. {
  390. const BitmapData destData (*this, x, y, 1, 1, BitmapData::readWrite);
  391. if (isARGB())
  392. reinterpret_cast<PixelARGB*> (destData.data)->multiplyAlpha (multiplier);
  393. else
  394. *(destData.data) = (uint8) (*(destData.data) * multiplier);
  395. }
  396. }
  397. template <class PixelType>
  398. struct PixelIterator
  399. {
  400. template <class PixelOperation>
  401. static void iterate (const Image::BitmapData& data, const PixelOperation& pixelOp)
  402. {
  403. for (int y = 0; y < data.height; ++y)
  404. {
  405. auto p = data.getLinePointer (y);
  406. for (int x = 0; x < data.width; ++x)
  407. {
  408. pixelOp (*reinterpret_cast<PixelType*> (p));
  409. p += data.pixelStride;
  410. }
  411. }
  412. }
  413. };
  414. template <class PixelOperation>
  415. static void performPixelOp (const Image::BitmapData& data, const PixelOperation& pixelOp)
  416. {
  417. switch (data.pixelFormat)
  418. {
  419. case Image::ARGB: PixelIterator<PixelARGB> ::iterate (data, pixelOp); break;
  420. case Image::RGB: PixelIterator<PixelRGB> ::iterate (data, pixelOp); break;
  421. case Image::SingleChannel: PixelIterator<PixelAlpha>::iterate (data, pixelOp); break;
  422. case Image::UnknownFormat:
  423. default: jassertfalse; break;
  424. }
  425. }
  426. struct AlphaMultiplyOp
  427. {
  428. float alpha;
  429. template <class PixelType>
  430. void operator() (PixelType& pixel) const
  431. {
  432. pixel.multiplyAlpha (alpha);
  433. }
  434. };
  435. void Image::multiplyAllAlphas (float amountToMultiplyBy)
  436. {
  437. jassert (hasAlphaChannel());
  438. const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
  439. performPixelOp (destData, AlphaMultiplyOp { amountToMultiplyBy });
  440. }
  441. struct DesaturateOp
  442. {
  443. template <class PixelType>
  444. void operator() (PixelType& pixel) const
  445. {
  446. pixel.desaturate();
  447. }
  448. };
  449. void Image::desaturate()
  450. {
  451. if (isARGB() || isRGB())
  452. {
  453. const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
  454. performPixelOp (destData, DesaturateOp());
  455. }
  456. }
  457. void Image::createSolidAreaMask (RectangleList<int>& result, float alphaThreshold) const
  458. {
  459. if (hasAlphaChannel())
  460. {
  461. auto threshold = (uint8) jlimit (0, 255, roundToInt (alphaThreshold * 255.0f));
  462. SparseSet<int> pixelsOnRow;
  463. const BitmapData srcData (*this, 0, 0, getWidth(), getHeight());
  464. for (int y = 0; y < srcData.height; ++y)
  465. {
  466. pixelsOnRow.clear();
  467. auto lineData = srcData.getLinePointer (y);
  468. if (isARGB())
  469. {
  470. for (int x = 0; x < srcData.width; ++x)
  471. {
  472. if (reinterpret_cast<const PixelARGB*> (lineData)->getAlpha() >= threshold)
  473. pixelsOnRow.addRange (Range<int> (x, x + 1));
  474. lineData += srcData.pixelStride;
  475. }
  476. }
  477. else
  478. {
  479. for (int x = 0; x < srcData.width; ++x)
  480. {
  481. if (*lineData >= threshold)
  482. pixelsOnRow.addRange (Range<int> (x, x + 1));
  483. lineData += srcData.pixelStride;
  484. }
  485. }
  486. for (int i = 0; i < pixelsOnRow.getNumRanges(); ++i)
  487. {
  488. auto range = pixelsOnRow.getRange (i);
  489. result.add (Rectangle<int> (range.getStart(), y, range.getLength(), 1));
  490. }
  491. result.consolidate();
  492. }
  493. }
  494. else
  495. {
  496. result.add (0, 0, getWidth(), getHeight());
  497. }
  498. }
  499. void Image::moveImageSection (int dx, int dy,
  500. int sx, int sy,
  501. int w, int h)
  502. {
  503. if (dx < 0)
  504. {
  505. w += dx;
  506. sx -= dx;
  507. dx = 0;
  508. }
  509. if (dy < 0)
  510. {
  511. h += dy;
  512. sy -= dy;
  513. dy = 0;
  514. }
  515. if (sx < 0)
  516. {
  517. w += sx;
  518. dx -= sx;
  519. sx = 0;
  520. }
  521. if (sy < 0)
  522. {
  523. h += sy;
  524. dy -= sy;
  525. sy = 0;
  526. }
  527. const int minX = jmin (dx, sx);
  528. const int minY = jmin (dy, sy);
  529. w = jmin (w, getWidth() - jmax (sx, dx));
  530. h = jmin (h, getHeight() - jmax (sy, dy));
  531. if (w > 0 && h > 0)
  532. {
  533. auto maxX = jmax (dx, sx) + w;
  534. auto maxY = jmax (dy, sy) + h;
  535. const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite);
  536. auto dst = destData.getPixelPointer (dx - minX, dy - minY);
  537. auto src = destData.getPixelPointer (sx - minX, sy - minY);
  538. auto lineSize = (size_t) destData.pixelStride * (size_t) w;
  539. if (dy > sy)
  540. {
  541. while (--h >= 0)
  542. {
  543. const int offset = h * destData.lineStride;
  544. memmove (dst + offset, src + offset, lineSize);
  545. }
  546. }
  547. else if (dst != src)
  548. {
  549. while (--h >= 0)
  550. {
  551. memmove (dst, src, lineSize);
  552. dst += destData.lineStride;
  553. src += destData.lineStride;
  554. }
  555. }
  556. }
  557. }
  558. //==============================================================================
  559. #if JUCE_ALLOW_STATIC_NULL_VARIABLES
  560. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
  561. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
  562. const Image Image::null;
  563. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  564. JUCE_END_IGNORE_WARNINGS_MSVC
  565. #endif
  566. } // namespace juce