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.

juce_Image.cpp 21KB

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