]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/quartz/quartzloader.cpp
Support for using Quartz to load images on OS X
[libs/gui.git] / source / graphics / quartz / quartzloader.cpp
1 #include <algorithm>
2 #include <CoreGraphics/CGColorSpace.h>
3 #include <CoreGraphics/CGImage.h>
4 #include <ImageIO/CGImageSource.h>
5 // Avoid messing up sigc++ headers
6 #undef nil
7 #include "quartzloader.h"
8
9 using namespace std;
10
11 namespace {
12
13 size_t get_bytes(void *info, void *buffer, size_t count)
14 {
15         Msp::IO::Seekable *io = reinterpret_cast<Msp::IO::Seekable *>(info);
16         char *cbuf = reinterpret_cast<char *>(buffer);
17         return io->read(cbuf, count);
18 }
19
20 off_t skip_forward(void *info, off_t count)
21 {
22         Msp::IO::Seekable *io = reinterpret_cast<Msp::IO::Seekable *>(info);
23
24         off_t i = 0;
25         char buf[1024];
26         while(i<count)
27                 i += io->read(buf, min<unsigned>(sizeof(buf), count-i));
28
29         return i;
30 }
31
32 void rewind(void *info)
33 {
34         Msp::IO::Seekable *io = reinterpret_cast<Msp::IO::Seekable *>(info);
35         io->seek(0, Msp::IO::S_BEG);
36 }
37
38 CGDataProviderSequentialCallbacks callbacks =
39 {
40         0,
41         &get_bytes,
42         &skip_forward,
43         &rewind,
44         0
45 };
46
47 } // namespace
48
49
50 namespace Msp {
51 namespace Graphics {
52
53 struct QuartzLoader::Private
54 {
55         CGDataProviderRef provider;
56         CGImageSourceRef source;
57 };
58
59
60 ImageLoader::Register<QuartzLoader> QuartzLoader::reg;
61
62 QuartzLoader::QuartzLoader(IO::Seekable &io):
63         priv(new Private)
64 {
65         priv->provider = CGDataProviderCreateSequential(&io, &callbacks);
66         priv->source = CGImageSourceCreateWithDataProvider(priv->provider, 0);
67 }
68
69 QuartzLoader::~QuartzLoader()
70 {
71         CFRelease(priv->source);
72         CFRelease(priv->provider);
73         delete priv;
74 }
75
76 bool QuartzLoader::detect(const string &sig)
77 {
78         CGImageSourceRef source = CGImageSourceCreateIncremental(0);
79         CFDataRef data = CFDataCreate(0, reinterpret_cast<const UInt8 *>(sig.data()), sig.size());
80         CGImageSourceUpdateData(source, data, false);
81         CGImageSourceStatus status = CGImageSourceGetStatus(source);
82         CFRelease(data);
83         CFRelease(source);
84
85         return status==kCGImageStatusIncomplete;
86 }
87
88 void QuartzLoader::load(Image::Data &data)
89 {
90         CGImageRef image = CGImageSourceCreateImageAtIndex(priv->source, 0, 0);
91
92         try
93         {
94                 data.width = CGImageGetWidth(image);
95                 data.height = CGImageGetHeight(image);
96
97                 CGColorSpaceRef color = CGImageGetColorSpace(image);
98                 CGColorSpaceModel model = CGColorSpaceGetModel(color);
99                 CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
100                 if(model==kCGColorSpaceModelRGB)
101                 {
102                         if(alpha==kCGImageAlphaLast)
103                                 data.fmt = RGBA;
104                         else if(alpha==kCGImageAlphaNone || alpha==kCGImageAlphaNoneSkipFirst || alpha==kCGImageAlphaNoneSkipLast)
105                                 data.fmt = RGB;
106                         else
107                                 throw unsupported_image_format("unknown alpha mode");
108                 }
109                 else
110                         throw unsupported_image_format("unknown colorspace");
111
112                 unsigned bytes_per_pixel = (CGImageGetBitsPerPixel(image)+7)/8;
113
114                 CGDataProviderRef dp = CGImageGetDataProvider(image);
115                 CFDataRef image_data = CGDataProviderCopyData(dp);
116                 data.data = new char[data.width*data.height*bytes_per_pixel];
117                 CFDataGetBytes(image_data, CFRangeMake(0, CFDataGetLength(image_data)), reinterpret_cast<UInt8 *>(data.data));
118                 CFRelease(image_data);
119
120                 CFRelease(image);
121
122                 if(alpha==kCGImageAlphaNoneSkipFirst || alpha==kCGImageAlphaNoneSkipLast)
123                 {
124                         const char *src = data.data;
125                         if(alpha==kCGImageAlphaNoneSkipFirst)
126                                 ++src;
127                         char *dest = data.data;
128                         for(unsigned y=0; y<data.height; ++y)
129                                 for(unsigned x=0; x<data.width; ++x)
130                                 {
131                                         for(unsigned i=0; i<3; ++i)
132                                                 dest[i] = src[i];
133                                         dest += 3;
134                                         src += 4;
135                                 }
136                 }
137         }
138         catch(...)
139         {
140                 CFRelease(image);
141                 throw;
142         }
143 }
144
145 } // namespace Graphics
146 } // namespace Msp