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