X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fquartz%2Fquartzloader.cpp;fp=source%2Fgraphics%2Fquartz%2Fquartzloader.cpp;h=23f7abbed319031ff0e3b23f99b096bf9159174d;hb=925757a29754bac7980b905b830d851811c50ba6;hp=0000000000000000000000000000000000000000;hpb=88814cd5cde0bddb56d299b2edbc48e8351a4311;p=libs%2Fgui.git diff --git a/source/graphics/quartz/quartzloader.cpp b/source/graphics/quartz/quartzloader.cpp new file mode 100644 index 0000000..23f7abb --- /dev/null +++ b/source/graphics/quartz/quartzloader.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +// Avoid messing up sigc++ headers +#undef nil +#include "quartzloader.h" + +using namespace std; + +namespace { + +size_t get_bytes(void *info, void *buffer, size_t count) +{ + Msp::IO::Seekable *io = reinterpret_cast(info); + char *cbuf = reinterpret_cast(buffer); + return io->read(cbuf, count); +} + +off_t skip_forward(void *info, off_t count) +{ + Msp::IO::Seekable *io = reinterpret_cast(info); + + off_t i = 0; + char buf[1024]; + while(iread(buf, min(sizeof(buf), count-i)); + + return i; +} + +void rewind(void *info) +{ + Msp::IO::Seekable *io = reinterpret_cast(info); + io->seek(0, Msp::IO::S_BEG); +} + +CGDataProviderSequentialCallbacks callbacks = +{ + 0, + &get_bytes, + &skip_forward, + &rewind, + 0 +}; + +} // namespace + + +namespace Msp { +namespace Graphics { + +struct QuartzLoader::Private +{ + CGDataProviderRef provider; + CGImageSourceRef source; +}; + + +ImageLoader::Register QuartzLoader::reg; + +QuartzLoader::QuartzLoader(IO::Seekable &io): + priv(new Private) +{ + priv->provider = CGDataProviderCreateSequential(&io, &callbacks); + priv->source = CGImageSourceCreateWithDataProvider(priv->provider, 0); +} + +QuartzLoader::~QuartzLoader() +{ + CFRelease(priv->source); + CFRelease(priv->provider); + delete priv; +} + +bool QuartzLoader::detect(const string &sig) +{ + CGImageSourceRef source = CGImageSourceCreateIncremental(0); + CFDataRef data = CFDataCreate(0, reinterpret_cast(sig.data()), sig.size()); + CGImageSourceUpdateData(source, data, false); + CGImageSourceStatus status = CGImageSourceGetStatus(source); + CFRelease(data); + CFRelease(source); + + return status==kCGImageStatusIncomplete; +} + +void QuartzLoader::load(Image::Data &data) +{ + CGImageRef image = CGImageSourceCreateImageAtIndex(priv->source, 0, 0); + + try + { + data.width = CGImageGetWidth(image); + data.height = CGImageGetHeight(image); + + CGColorSpaceRef color = CGImageGetColorSpace(image); + CGColorSpaceModel model = CGColorSpaceGetModel(color); + CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image); + if(model==kCGColorSpaceModelRGB) + { + if(alpha==kCGImageAlphaLast) + data.fmt = RGBA; + else if(alpha==kCGImageAlphaNone || alpha==kCGImageAlphaNoneSkipFirst || alpha==kCGImageAlphaNoneSkipLast) + data.fmt = RGB; + else + throw unsupported_image_format("unknown alpha mode"); + } + else + throw unsupported_image_format("unknown colorspace"); + + unsigned bytes_per_pixel = (CGImageGetBitsPerPixel(image)+7)/8; + + CGDataProviderRef dp = CGImageGetDataProvider(image); + CFDataRef image_data = CGDataProviderCopyData(dp); + data.data = new char[data.width*data.height*bytes_per_pixel]; + CFDataGetBytes(image_data, CFRangeMake(0, CFDataGetLength(image_data)), reinterpret_cast(data.data)); + CFRelease(image_data); + + CFRelease(image); + + if(alpha==kCGImageAlphaNoneSkipFirst || alpha==kCGImageAlphaNoneSkipLast) + { + const char *src = data.data; + if(alpha==kCGImageAlphaNoneSkipFirst) + ++src; + char *dest = data.data; + for(unsigned y=0; y