aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/osx/graphics/quartz/Convert.h1
-rw-r--r--include/cru/osx/graphics/quartz/ImageFactory.h2
-rw-r--r--include/cru/platform/graphics/ImageFactory.h4
-rw-r--r--src/osx/graphics/quartz/Convert.cpp11
-rw-r--r--src/osx/graphics/quartz/ImageFactory.cpp51
5 files changed, 67 insertions, 2 deletions
diff --git a/include/cru/osx/graphics/quartz/Convert.h b/include/cru/osx/graphics/quartz/Convert.h
index 8d486069..be56b959 100644
--- a/include/cru/osx/graphics/quartz/Convert.h
+++ b/include/cru/osx/graphics/quartz/Convert.h
@@ -20,4 +20,5 @@ CGRect Convert(const Rect& rect);
Rect Convert(const CGRect& rect);
CGDataProviderRef ConvertStreamToCGDataProvider(io::Stream* stream);
+CGDataConsumerRef ConvertStreamToCGDataConsumer(io::Stream* stream);
} // namespace cru::platform::graphics::osx::quartz
diff --git a/include/cru/osx/graphics/quartz/ImageFactory.h b/include/cru/osx/graphics/quartz/ImageFactory.h
index 19e9c8c1..23d14332 100644
--- a/include/cru/osx/graphics/quartz/ImageFactory.h
+++ b/include/cru/osx/graphics/quartz/ImageFactory.h
@@ -15,6 +15,8 @@ class QuartzImageFactory : public OsxQuartzResource,
public:
std::unique_ptr<IImage> DecodeFromStream(io::Stream* stream) override;
+ void EncodeToStream(IImage* image, io::Stream* stream, ImageFormat format,
+ float quality) override;
std::unique_ptr<IImage> CreateBitmap(int width, int height) override;
};
} // namespace cru::platform::graphics::osx::quartz
diff --git a/include/cru/platform/graphics/ImageFactory.h b/include/cru/platform/graphics/ImageFactory.h
index 2339a069..cd868087 100644
--- a/include/cru/platform/graphics/ImageFactory.h
+++ b/include/cru/platform/graphics/ImageFactory.h
@@ -3,7 +3,7 @@
#include "cru/common/io/Stream.h"
namespace cru::platform::graphics {
-enum class ImageFormat { Jpeg, Png };
+enum class ImageFormat { Jpeg, Png, Gif };
struct CRU_PLATFORM_GRAPHICS_API IImageFactory
: public virtual IGraphicsResource {
@@ -15,7 +15,7 @@ struct CRU_PLATFORM_GRAPHICS_API IImageFactory
* \param stream The stream to write to.
* \param format The format to encode to.
* \param quality The quality to encode to.
- * \todo Implement on macOS and Windows.
+ * \todo Implement on Windows.
*/
virtual void EncodeToStream(IImage* image, io::Stream* stream,
ImageFormat format, float quality) = 0;
diff --git a/src/osx/graphics/quartz/Convert.cpp b/src/osx/graphics/quartz/Convert.cpp
index 993b5b61..df62a206 100644
--- a/src/osx/graphics/quartz/Convert.cpp
+++ b/src/osx/graphics/quartz/Convert.cpp
@@ -49,4 +49,15 @@ CGDataProviderRef ConvertStreamToCGDataProvider(io::Stream* stream) {
&kStreamToCGDataProviderCallbacks);
}
+const CGDataConsumerCallbacks kStreamToCGDataConsumerCallbacks{
+ [](void* info, const void* buffer, size_t count) -> size_t {
+ return static_cast<io::Stream*>(info)->Write(
+ static_cast<const std::byte*>(buffer), count);
+ },
+ [](void* info) {}};
+
+CGDataConsumerRef ConvertStreamToCGDataConsumer(io::Stream* stream) {
+ return CGDataConsumerCreate(stream, &kStreamToCGDataConsumerCallbacks);
+}
+
} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/ImageFactory.cpp b/src/osx/graphics/quartz/ImageFactory.cpp
index a8c17719..2c6d4705 100644
--- a/src/osx/graphics/quartz/ImageFactory.cpp
+++ b/src/osx/graphics/quartz/ImageFactory.cpp
@@ -1,12 +1,16 @@
#include "cru/osx/graphics/quartz/ImageFactory.h"
#include "cru/common/Exception.h"
+#include "cru/common/platform/osx/Convert.h"
#include "cru/osx/graphics/quartz/Convert.h"
#include "cru/osx/graphics/quartz/Image.h"
+#include "cru/platform/Check.h"
#include "cru/platform/graphics/Image.h"
#include <ImageIO/ImageIO.h>
namespace cru::platform::graphics::osx::quartz {
+using cru::platform::osx::Convert;
+
QuartzImageFactory::QuartzImageFactory(IGraphicsFactory* graphics_factory)
: OsxQuartzResource(graphics_factory) {}
@@ -28,6 +32,53 @@ std::unique_ptr<IImage> QuartzImageFactory::DecodeFromStream(
new QuartzImage(GetGraphicsFactory(), this, cg_image, true));
}
+static String GetImageFormatUniformTypeIdentifier(ImageFormat format) {
+ switch (format) {
+ case ImageFormat::Png:
+ return u"public.png";
+ case ImageFormat::Jpeg:
+ return u"public.jpeg";
+ case ImageFormat::Gif:
+ return u"com.compuserve.gif";
+ default:
+ throw Exception(u"Unknown image format.");
+ }
+}
+
+void QuartzImageFactory::EncodeToStream(IImage* image, io::Stream* stream,
+ ImageFormat format, float quality) {
+ if (quality <= 0 || quality > 1) {
+ throw Exception(u"Invalid quality value.");
+ }
+
+ auto quartz_image = CheckPlatform<QuartzImage>(image, GetPlatformId());
+ auto cg_image = quartz_image->GetCGImage();
+
+ CFStringRef uti = Convert(GetImageFormatUniformTypeIdentifier(format));
+ CGDataConsumerRef data_consumer = ConvertStreamToCGDataConsumer(stream);
+ CGImageDestinationRef destination =
+ CGImageDestinationCreateWithDataConsumer(data_consumer, uti, 1, nullptr);
+
+ CFMutableDictionaryRef properties =
+ CFDictionaryCreateMutable(nullptr, 0, nullptr, nullptr);
+ CFNumberRef quality_wrap =
+ CFNumberCreate(nullptr, kCFNumberFloatType, &quality);
+ CFDictionaryAddValue(properties, kCGImageDestinationLossyCompressionQuality,
+ quality_wrap);
+
+ CGImageDestinationAddImage(destination, cg_image, properties);
+
+ if (!CGImageDestinationFinalize(destination)) {
+ throw Exception(u"Failed to finalize image destination.");
+ }
+
+ CFRelease(quality_wrap);
+ CFRelease(properties);
+ CFRelease(destination);
+ CFRelease(data_consumer);
+ CFRelease(uti);
+}
+
std::unique_ptr<IImage> QuartzImageFactory::CreateBitmap(int width,
int height) {
if (width <= 0) throw Exception(u"Image width should be greater than 0.");