Audio plugin host https://kx.studio/carla
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.

660 lines
21KB

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