X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fpng%2Fpngloader.cpp;fp=source%2Fgraphics%2Fpng%2Fpngloader.cpp;h=85530653afa8004cb6692fc2cd3fc6f1dcaf2f1b;hb=cfd3548464e6424fc9decf0539d6cd04b031ba10;hp=0000000000000000000000000000000000000000;hpb=12df88ecf9787f4ed59051646775165b74301cf0;p=libs%2Fgui.git diff --git a/source/graphics/png/pngloader.cpp b/source/graphics/png/pngloader.cpp new file mode 100644 index 0000000..8553065 --- /dev/null +++ b/source/graphics/png/pngloader.cpp @@ -0,0 +1,94 @@ +#include +#include "pngloader.h" + +using namespace std; + +namespace { + +void read(png_struct *png, png_byte *data, png_size_t size) +{ + Msp::IO::Base *in = reinterpret_cast(png_get_io_ptr(png)); + in->read(reinterpret_cast(data), size); +} + +void error(png_struct *png, const char *msg) +{ + string *message = reinterpret_cast(png_get_error_ptr(png)); + *message = msg; + longjmp(png_jmpbuf(png), 1); +} + +} // namespace + + +namespace Msp { +namespace Graphics { + +struct PngLoader::Private +{ + std::string message; + png_struct *png; + png_info *info; +}; + +PngLoader::PngLoader(IO::Base &io, const string &sig): + priv(new Private) +{ + priv->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &priv->message, error, 0); + priv->info = png_create_info_struct(priv->png); + + // These probably won't give any errors + png_set_read_fn(priv->png, &io, read); + png_set_sig_bytes(priv->png, sig.size()); +} + +PngLoader::~PngLoader() +{ + png_destroy_read_struct(&priv->png, &priv->info, 0); + delete priv; +} + +bool PngLoader::detect(const std::string &sig) +{ + return !png_sig_cmp(reinterpret_cast(const_cast(sig.data())), 0, sig.size()); +} + +void PngLoader::load(Image::Data &data) +{ + if(setjmp(png_jmpbuf(priv->png))) + throw bad_image_data(priv->message); + + png_read_info(priv->png, priv->info); + png_uint_32 width; + png_uint_32 height; + int depth; + int color; + png_get_IHDR(priv->png, priv->info, &width, &height, &depth, &color, 0, 0, 0); + data.width = width; + data.height = height; + if(depth!=8) + throw unsupported_image_format("depth!=8"); + switch(color) + { + case PNG_COLOR_TYPE_PALETTE: data.fmt = COLOR_INDEX; break; + case PNG_COLOR_TYPE_GRAY: data.fmt = LUMINANCE; break; + case PNG_COLOR_TYPE_GRAY_ALPHA: data.fmt = LUMINANCE_ALPHA; break; + case PNG_COLOR_TYPE_RGB: data.fmt = RGB; break; + case PNG_COLOR_TYPE_RGB_ALPHA: data.fmt = RGBA; break; + default: throw unsupported_image_format("unknown color type"); + } + + unsigned nchans = png_get_channels(priv->png, priv->info); + if(nchans==4 && data.fmt==RGB) + png_set_strip_alpha(priv->png); + + unsigned rowstride = data.width*nchans; + data.data = new char[rowstride*data.height]; + for(unsigned y=0; ypng, reinterpret_cast(data.data+rowstride*(data.height-1-y)), 0); + + png_read_end(priv->png, 0); +} + +} // namespace Graphics +} // namespace Msp