mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Graphics: Move Image::moveImageSection into ImagePixelData
Co-authored-by: Matt Gonzalez <matt@echoaudio.com>
This commit is contained in:
parent
e9a5531587
commit
2324e34e1b
2 changed files with 133 additions and 67 deletions
|
|
@ -464,6 +464,97 @@ auto ImagePixelData::getNativeExtensions() -> NativeExtensions
|
|||
return NativeExtensions { Wrapped{} };
|
||||
}
|
||||
|
||||
struct MoveImageParams
|
||||
{
|
||||
Rectangle<int> src{};
|
||||
Point<int> dst{};
|
||||
|
||||
MoveImageParams constrained (int width, int height) const
|
||||
{
|
||||
const auto intersectedSrc = src.getIntersection ({ width, height });
|
||||
const auto srcOffset = intersectedSrc.getPosition() - src.getPosition();
|
||||
const auto intersectedDst = intersectedSrc.withPosition (dst + srcOffset).getIntersection ({ width, height });
|
||||
|
||||
if (intersectedDst.isEmpty())
|
||||
return {};
|
||||
|
||||
const MoveImageParams result { intersectedDst.withPosition (intersectedDst.getPosition() + src.getPosition() - dst),
|
||||
intersectedDst.getPosition() };
|
||||
|
||||
// postconditions
|
||||
jassert ((juce::Rectangle { width, height }.contains (result.src)));
|
||||
jassert ((juce::Rectangle { width, height }.contains (result.src.withPosition (result.dst))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator== (const MoveImageParams& other) const
|
||||
{
|
||||
const auto tie = [] (auto& x) { return std::tuple (x.src, x.dst); };
|
||||
return tie (*this) == tie (other);
|
||||
}
|
||||
|
||||
bool operator!= (const MoveImageParams& other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
};
|
||||
|
||||
static void moveValidatedImageSectionInSoftware (ImagePixelData& img,
|
||||
Point<int> destTopLeft,
|
||||
Rectangle<int> sourceRect)
|
||||
{
|
||||
const auto minX = jmin (destTopLeft.x, sourceRect.getX());
|
||||
const auto minY = jmin (destTopLeft.y, sourceRect.getY());
|
||||
|
||||
Image tempImage { &img };
|
||||
const Image::BitmapData destData (tempImage,
|
||||
minX,
|
||||
minY,
|
||||
sourceRect.getWidth(),
|
||||
sourceRect.getHeight(),
|
||||
Image::BitmapData::readWrite);
|
||||
|
||||
const auto dstPos = destTopLeft - Point { minX, minY };
|
||||
const auto srcPos = sourceRect.getPosition() - Point { minX, minY };
|
||||
|
||||
auto* dst = destData.getPixelPointer (dstPos.x, dstPos.y);
|
||||
const auto* src = destData.getPixelPointer (srcPos.x, srcPos.y);
|
||||
|
||||
const auto lineSize = (size_t) destData.pixelStride * (size_t) sourceRect.getWidth();
|
||||
|
||||
if (destTopLeft.y > sourceRect.getY())
|
||||
{
|
||||
for (auto h = sourceRect.getHeight(); --h >= 0;)
|
||||
{
|
||||
const auto offset = h * destData.lineStride;
|
||||
memmove (dst + offset, src + offset, lineSize);
|
||||
}
|
||||
}
|
||||
else if (dst != src)
|
||||
{
|
||||
for (auto h = sourceRect.getHeight(); --h >= 0;)
|
||||
{
|
||||
memmove (dst, src, lineSize);
|
||||
dst += destData.lineStride;
|
||||
src += destData.lineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePixelData::moveImageSection (Point<int> destTopLeft, Rectangle<int> sourceRect)
|
||||
{
|
||||
const auto constrained = MoveImageParams { sourceRect, destTopLeft }.constrained (width, height);
|
||||
|
||||
if (! constrained.src.isEmpty())
|
||||
moveValidatedImageSection (constrained.dst, constrained.src);
|
||||
}
|
||||
|
||||
void ImagePixelData::moveValidatedImageSection (Point<int> destTopLeft, Rectangle<int> sourceRect)
|
||||
{
|
||||
moveValidatedImageSectionInSoftware (*this, destTopLeft, sourceRect);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ImageType::ImageType() = default;
|
||||
ImageType::~ImageType() = default;
|
||||
|
|
@ -931,74 +1022,10 @@ void Image::createSolidAreaMask (RectangleList<int>& result, float alphaThreshol
|
|||
}
|
||||
}
|
||||
|
||||
void Image::moveImageSection (int dx, int dy,
|
||||
int sx, int sy,
|
||||
int w, int h)
|
||||
void Image::moveImageSection (int dx, int dy, int sx, int sy, int w, int h)
|
||||
{
|
||||
if (dx < 0)
|
||||
{
|
||||
w += dx;
|
||||
sx -= dx;
|
||||
dx = 0;
|
||||
}
|
||||
|
||||
if (dy < 0)
|
||||
{
|
||||
h += dy;
|
||||
sy -= dy;
|
||||
dy = 0;
|
||||
}
|
||||
|
||||
if (sx < 0)
|
||||
{
|
||||
w += sx;
|
||||
dx -= sx;
|
||||
sx = 0;
|
||||
}
|
||||
|
||||
if (sy < 0)
|
||||
{
|
||||
h += sy;
|
||||
dy -= sy;
|
||||
sy = 0;
|
||||
}
|
||||
|
||||
const int minX = jmin (dx, sx);
|
||||
const int minY = jmin (dy, sy);
|
||||
|
||||
w = jmin (w, getWidth() - jmax (sx, dx));
|
||||
h = jmin (h, getHeight() - jmax (sy, dy));
|
||||
|
||||
if (w > 0 && h > 0)
|
||||
{
|
||||
auto maxX = jmax (dx, sx) + w;
|
||||
auto maxY = jmax (dy, sy) + h;
|
||||
|
||||
const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite);
|
||||
|
||||
auto dst = destData.getPixelPointer (dx - minX, dy - minY);
|
||||
auto src = destData.getPixelPointer (sx - minX, sy - minY);
|
||||
|
||||
auto lineSize = (size_t) destData.pixelStride * (size_t) w;
|
||||
|
||||
if (dy > sy)
|
||||
{
|
||||
while (--h >= 0)
|
||||
{
|
||||
const int offset = h * destData.lineStride;
|
||||
memmove (dst + offset, src + offset, lineSize);
|
||||
}
|
||||
}
|
||||
else if (dst != src)
|
||||
{
|
||||
while (--h >= 0)
|
||||
{
|
||||
memmove (dst, src, lineSize);
|
||||
dst += destData.lineStride;
|
||||
src += destData.lineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (image != nullptr)
|
||||
image->moveImageSection ({ dx, dy }, { sx, sy, w, h });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1012,4 +1039,33 @@ JUCE_END_IGNORE_DEPRECATION_WARNINGS
|
|||
|
||||
#endif
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class ImagePixelDataClippingTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
ImagePixelDataClippingTests()
|
||||
: UnitTest ("ImagePixelDataClippingTests", UnitTestCategories::graphics)
|
||||
{
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("MoveImageParams constrains arguments appropriately");
|
||||
{
|
||||
expect ((MoveImageParams { { 300, 400 }, { 5, 5 } }.constrained (350, 450) == MoveImageParams { { 300, 400 }, { 5, 5 } }));
|
||||
expect ((MoveImageParams { { 350, 450 }, { 5, 5 } }.constrained (300, 400) == MoveImageParams { { 295, 395 }, { 5, 5 } }));
|
||||
expect ((MoveImageParams { { -5, -10, 20, 30 }, { 0, 0 } }.constrained (100, 100) == MoveImageParams { { 15, 20 }, { 5, 10 } }));
|
||||
expect ((MoveImageParams { { 1, 2, 10, 10 }, { -5, -5 } }.constrained (20, 20) == MoveImageParams { { 6, 7, 5, 5 }, { 0, 0 } }));
|
||||
expect ((MoveImageParams { { 40, 50, 100, 100 }, { 10, 10 } }.constrained (100, 100) == MoveImageParams { { 40, 50, 60, 50 }, { 10, 10 } }));
|
||||
expect ((MoveImageParams { { 20, 20, 10, 10 }, { -20, -20 } }.constrained (20, 20) == MoveImageParams { { 0, 0, 0, 0 }, { 0, 0 } }));
|
||||
expect ((MoveImageParams { { -20, -30, 100, 100 }, { -30, -40 } }.constrained (100, 100) == MoveImageParams { { 10, 10, 70, 60 }, { 0, 0 } }));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ImagePixelDataClippingTests imagePixelDataClippingTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -605,6 +605,10 @@ public:
|
|||
*/
|
||||
virtual int getSharedCount() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Copies a section of the image to somewhere else within itself. */
|
||||
void moveImageSection (Point<int> destTopLeft, Rectangle<int> sourceRect);
|
||||
|
||||
/** Applies a native blur effect to this image, if available.
|
||||
This blur applies to all channels of the input image. It may be more expensive to
|
||||
calculate than a box blur, but should produce higher-quality results.
|
||||
|
|
@ -689,6 +693,12 @@ public:
|
|||
virtual NativeExtensions getNativeExtensions();
|
||||
|
||||
private:
|
||||
/* Called by moveImageSection().
|
||||
The source and destination rects are both guaranteed to be within the image bounds, and
|
||||
non-empty.
|
||||
*/
|
||||
virtual void moveValidatedImageSection (Point<int> destTopLeft, Rectangle<int> sourceRect);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePixelData)
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue