1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

CoreGraphics: Fix bug where subsection images were rendered incorrectly

This commit is contained in:
reuk 2025-02-03 13:56:06 +00:00
parent a381fdf81d
commit 56ea531298
No known key found for this signature in database
3 changed files with 92 additions and 21 deletions

View file

@ -871,4 +871,68 @@ Graphics::ScopedSaveState::~ScopedSaveState()
context.restoreState();
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
class GraphicsTests : public UnitTest
{
public:
GraphicsTests() : UnitTest ("Graphics", UnitTestCategories::graphics) {}
void runTest() override
{
beginTest ("Render image subsection");
{
renderImageSubsection (NativeImageType{}, NativeImageType{});
}
}
private:
void renderImageSubsection (const ImageType& sourceType, const ImageType& targetType)
{
const auto sourceColour = Colours::cyan;
const auto sourceOffset = 49;
const Image source { Image::ARGB, 50, 50, true, sourceType };
const Image target { Image::ARGB, 50, 50, true, targetType };
const auto subsection = source.getClippedImage (Rectangle { sourceOffset, sourceOffset, 1, 1 });
Image::BitmapData { subsection, Image::BitmapData::writeOnly }.setPixelColour (0, 0, sourceColour);
{
// Render the subsection image so that it fills 'target'
Graphics g { target };
g.drawImage (subsection,
0, 0, target.getWidth(), target.getHeight(),
0, 0, 1, 1);
}
{
// Check that all pixels in 'target' match the bottom right pixel of 'source'
const Image::BitmapData bitmap { target, Image::BitmapData::readOnly };
int numFailures = 0;
for (auto y = 0; y < bitmap.height; ++y)
{
for (auto x = 0; x < bitmap.width; ++x)
{
const auto targetColour = bitmap.getPixelColour (x, y);
if (targetColour != sourceColour)
++numFailures;
}
}
expect (numFailures == 0);
}
}
};
static GraphicsTests graphicsTests;
#endif
} // namespace juce

View file

@ -282,7 +282,7 @@ public:
#if JUCE_MAC || JUCE_IOS
CGContextRef getCGContext() const { return impl->getCGContext(); }
CGImageRef getCGImage (CGColorSpaceRef x) const { return impl->getCGImage (x); }
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef x) const { return impl->getCGImage (x); }
#endif
private:
@ -297,7 +297,7 @@ private:
#if JUCE_MAC || JUCE_IOS
virtual CGContextRef getCGContext() const = 0;
virtual CGImageRef getCGImage (CGColorSpaceRef x) const = 0;
virtual CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef x) const = 0;
#endif
};
@ -316,7 +316,7 @@ private:
#if JUCE_MAC || JUCE_IOS
CGContextRef getCGContext() const override { return impl.getCGContext(); }
CGImageRef getCGImage (CGColorSpaceRef x) const override { return impl.getCGImage (x); }
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef x) const override { return impl.getCGImage (x); }
#endif
private:
@ -417,9 +417,12 @@ public:
return self->sourceImage->getNativeExtensions().getCGContext();
}
CGImageRef getCGImage (CGColorSpaceRef colourSpace) const
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef colourSpace) const
{
return self->sourceImage->getNativeExtensions().getCGImage (colourSpace);
const auto& parentNative = self->sourceImage->getNativeExtensions();
const auto parentImage = parentNative.getCGImage (colourSpace);
return CFUniquePtr<CGImageRef> { CGImageCreateWithImageInRect (parentImage.get(),
makeCGRect (self->area + parentNative.getTopLeft())) };
}
#endif
@ -518,7 +521,7 @@ auto ImagePixelData::getNativeExtensions() -> NativeExtensions
#if JUCE_MAC || JUCE_IOS
CGContextRef getCGContext() const { return {}; }
CGImageRef getCGImage (CGColorSpaceRef) const { return {}; }
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef) const { return {}; }
#endif
};

View file

@ -144,9 +144,9 @@ public:
}
//==============================================================================
static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)
static CFUniquePtr<CGImageRef> getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)
{
auto* cgim = std::invoke ([&]() -> CGImageRef
auto cgim = std::invoke ([&]() -> CFUniquePtr<CGImageRef>
{
if (auto ptr = juceImage.getPixelData())
return ptr->getNativeExtensions().getCGImage (colourSpace);
@ -155,7 +155,7 @@ public:
});
if (cgim != nullptr)
return CGImageRetain (cgim);
return cgim;
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
@ -163,13 +163,17 @@ public:
CFUniquePtr<CFDataRef> data (CFDataCreate (nullptr, (const UInt8*) srcData.data, (CFIndex) usableSize));
detail::DataProviderPtr provider { CGDataProviderCreateWithCFData (data.get()) };
return CGImageCreate ((size_t) srcData.width,
return CFUniquePtr<CGImageRef> { CGImageCreate ((size_t) srcData.width,
(size_t) srcData.height,
8,
(size_t) srcData.pixelStride * 8,
(size_t) srcData.lineStride,
colourSpace, getCGImageFlags (juceImage.getFormat()), provider.get(),
nullptr, true, kCGRenderingIntentDefault);
colourSpace,
getCGImageFlags (juceImage.getFormat()),
provider.get(),
nullptr,
true,
kCGRenderingIntentDefault) };
}
//==============================================================================
@ -185,10 +189,10 @@ public:
HeapBlock<uint8> data;
};
CGImageRef getCGImage (CGColorSpaceRef colourSpace)
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef colourSpace)
{
if (cachedImageRef != nullptr)
return cachedImageRef.get();
return CFUniquePtr<CGImageRef> { CGImageRetain (cachedImageRef.get()) };
const Image::BitmapData srcData { Image { this }, Image::BitmapData::readOnly };
@ -205,7 +209,7 @@ public:
colourSpace, getCGImageFlags (pixelFormat), provider.get(),
nullptr, true, kCGRenderingIntentDefault));
return cachedImageRef.get();
return CFUniquePtr<CGImageRef> { CGImageRetain (cachedImageRef.get()) };
}
ImageDataContainer::Ptr imageData = new ImageDataContainer();
@ -222,7 +226,7 @@ public:
return self->context.get();
}
CGImageRef getCGImage (CGColorSpaceRef x) const
CFUniquePtr<CGImageRef> getCGImage (CGColorSpaceRef x) const
{
return self->getCGImage (x);
}
@ -1200,7 +1204,7 @@ Image juce_createImageFromCIImage (CIImage* im, int w, int h)
CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace)
{
return CoreGraphicsPixelData::getCachedImageRef (juceImage, colourSpace);
return CoreGraphicsPixelData::getCachedImageRef (juceImage, colourSpace).release();
}
CGContextRef juce_getImageContext (const Image& image)