]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/quartz/quartzloader.cpp
1fc93ad2b3d36252a1e487e40ac82ad04d80c676
[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 || status==kCGImageStatusReadingHeader;
86 }
87
88 void QuartzLoader::load(Image::Data &data)
89 {
90         CGImageRef image = CGImageSourceCreateImageAtIndex(priv->source, 0, 0);
91         if(!image)
92                 throw bad_image_data("null image");
93
94         try
95         {
96                 data.width = CGImageGetWidth(image);
97                 data.height = CGImageGetHeight(image);
98                 data.stride = CGImageGetBytesPerRow(image);
99
100                 CGColorSpaceRef color = CGImageGetColorSpace(image);
101                 CGColorSpaceModel model = CGColorSpaceGetModel(color);
102                 CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
103                 if(model==kCGColorSpaceModelRGB)
104                 {
105                         if(alpha==kCGImageAlphaLast)
106                                 data.fmt = RGBA;
107                         else if(alpha==kCGImageAlphaNoneSkipLast || alpha==kCGImageAlphaNoneSkipFirst)
108                                 data.fmt = RGBX;
109                         else if(alpha==kCGImageAlphaNone)
110                                 data.fmt = RGB;
111                         else
112                                 throw unsupported_image_format("unknown alpha mode");
113                 }
114                 else
115                         throw unsupported_image_format("unknown colorspace");
116
117                 CGDataProviderRef dp = CGImageGetDataProvider(image);
118                 CFDataRef image_data = CGDataProviderCopyData(dp);
119                 data.data = new char[data.height*data.stride];
120                 unsigned offset = (alpha==kCGImageAlphaNoneSkipFirst);
121                 CFRange range = CFRangeMake(offset, CFDataGetLength(image_data)-offset);
122                 CFDataGetBytes(image_data, range, reinterpret_cast<UInt8 *>(data.data));
123                 CFRelease(image_data);
124
125                 CFRelease(image);
126         }
127         catch(...)
128         {
129                 CFRelease(image);
130                 throw;
131         }
132 }
133
134 } // namespace Graphics
135 } // namespace Msp