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