From 054fca09f0bbd64fdbd6406a0643de938a9cd4fb Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 7 Feb 2021 18:13:51 +0200 Subject: [PATCH] Split image loading into headers and pixels --- source/graphics/bmploader.cpp | 12 +++++++++--- source/graphics/bmploader.h | 4 +++- source/graphics/devil/devilloader.cpp | 12 ++++++++++-- source/graphics/devil/devilloader.h | 3 ++- source/graphics/image.cpp | 10 +++++++++- source/graphics/image.h | 1 + source/graphics/imageloader.cpp | 13 ++++++++++++- source/graphics/imageloader.h | 5 ++++- source/graphics/jpeg/jpegloader.cpp | 5 ++++- source/graphics/jpeg/jpegloader.h | 3 ++- source/graphics/png/pngloader.cpp | 22 +++++++++++++++------- source/graphics/png/pngloader.h | 3 ++- source/graphics/quartz/quartzloader.cpp | 23 +++++++++++++---------- source/graphics/quartz/quartzloader.h | 3 ++- 14 files changed, 88 insertions(+), 31 deletions(-) diff --git a/source/graphics/bmploader.cpp b/source/graphics/bmploader.cpp index 39629f7..d88e2aa 100644 --- a/source/graphics/bmploader.cpp +++ b/source/graphics/bmploader.cpp @@ -29,7 +29,8 @@ namespace Graphics { BmpLoader::BmpLoader(IO::Base &i, unsigned sb): io(i), - sig_bytes(sb) + sig_bytes(sb), + invert_row_order(false) { // Image data location is stored at offset 10 and can't be skipped if(sig_bytes>10) @@ -44,7 +45,7 @@ bool BmpLoader::detect(const std::string &sig) return !sig.compare(0, sizeof(bmp_sig), bmp_sig, sizeof(bmp_sig)); } -void BmpLoader::load_(Image::Data &data) +void BmpLoader::load_headers_(Image::Data &data) { char bm_header[14]; read_full(io, bm_header+sig_bytes, sizeof(bm_header)-sig_bytes); @@ -92,8 +93,13 @@ void BmpLoader::load_(Image::Data &data) skip -= size; } + invert_row_order = (height<0); +} + +void BmpLoader::load_pixels_(Image::Data &data) +{ data.pixels = new char[data.stride*data.height]; - if(height<0) + if(invert_row_order) { for(unsigned y=0; y=FINISHED) throw logic_error("already loaded"); - load_(data); + if(state=HEADERS_LOADED) + throw logic_error("headers already loaded"); + + load_headers_(data); + state = HEADERS_LOADED; +} + ImageLoader::Registry &ImageLoader::get_registry() { static Registry registry; diff --git a/source/graphics/imageloader.h b/source/graphics/imageloader.h index cb3f54a..1ad6cc8 100644 --- a/source/graphics/imageloader.h +++ b/source/graphics/imageloader.h @@ -27,6 +27,7 @@ public: enum State { INITIAL, + HEADERS_LOADED, FINISHED }; @@ -74,8 +75,10 @@ public: static ImageLoader *open_io(IO::Seekable &); virtual void load(Image::Data &); + virtual void load_headers(Image::Data &); protected: - virtual void load_(Image::Data &) = 0; + virtual void load_headers_(Image::Data &) = 0; + virtual void load_pixels_(Image::Data &) = 0; public: State get_state() const { return state; } diff --git a/source/graphics/jpeg/jpegloader.cpp b/source/graphics/jpeg/jpegloader.cpp index f61f651..4dd9440 100644 --- a/source/graphics/jpeg/jpegloader.cpp +++ b/source/graphics/jpeg/jpegloader.cpp @@ -119,7 +119,7 @@ bool JpegLoader::detect(const string &sig) return !sig.compare(0, sizeof(jpeg_sig), jpeg_sig, sizeof(jpeg_sig)); } -void JpegLoader::load_(Image::Data &data) +void JpegLoader::load_headers_(Image::Data &data) { if(setjmp(priv->err_mgr.jmp)) throw bad_image_data(priv->err_mgr.message); @@ -132,7 +132,10 @@ void JpegLoader::load_(Image::Data &data) data.height = priv->jpeg.output_height; data.stride = priv->jpeg.output_width*priv->jpeg.output_components; data.fmt = RGB; +} +void JpegLoader::load_pixels_(Image::Data &data) +{ data.pixels = new char[data.stride*data.height]; JSAMPROW rows[8]; while(priv->jpeg.output_scanline(const_cast(sig.data())), 0, sig.size()); } -void PngLoader::load_(Image::Data &data) +void PngLoader::load_headers_(Image::Data &data) { - png_byte **rows = 0; - if(setjmp(png_jmpbuf(priv->png))) { - delete[] rows; throw bad_image_data(priv->message); } @@ -69,8 +67,7 @@ void PngLoader::load_(Image::Data &data) png_uint_32 height; int depth; int color; - int interlace; - png_get_IHDR(priv->png, priv->info, &width, &height, &depth, &color, &interlace, 0, 0); + png_get_IHDR(priv->png, priv->info, &width, &height, &depth, &color, &priv->interlace, 0, 0); unsigned nchans = png_get_channels(priv->png, priv->info); if(depth!=8) @@ -89,10 +86,21 @@ void PngLoader::load_(Image::Data &data) case PNG_COLOR_TYPE_RGB_ALPHA: data.fmt = RGBA; break; default: throw unsupported_image_format("unknown color type"); } +} + +void PngLoader::load_pixels_(Image::Data &data) +{ + png_byte **rows = 0; + + if(setjmp(png_jmpbuf(priv->png))) + { + delete[] rows; + throw bad_image_data(priv->message); + } data.pixels = new char[data.stride*data.height]; - if(interlace==PNG_INTERLACE_ADAM7) + if(priv->interlace==PNG_INTERLACE_ADAM7) { // ADAM7 requires all rows to be loaded at once unsigned n_passes = png_set_interlace_handling(priv->png); diff --git a/source/graphics/png/pngloader.h b/source/graphics/png/pngloader.h index 21c1c72..7c9390f 100644 --- a/source/graphics/png/pngloader.h +++ b/source/graphics/png/pngloader.h @@ -20,7 +20,8 @@ public: static unsigned get_signature_size() { return 8; } static bool detect(const std::string &); - virtual void load_(Image::Data &); + virtual void load_headers_(Image::Data &); + virtual void load_pixels_(Image::Data &); }; } // namespace Graphics diff --git a/source/graphics/quartz/quartzloader.cpp b/source/graphics/quartz/quartzloader.cpp index 472e066..e025b66 100644 --- a/source/graphics/quartz/quartzloader.cpp +++ b/source/graphics/quartz/quartzloader.cpp @@ -109,16 +109,6 @@ void QuartzLoader::load_(Image::Data &data) } else throw unsupported_image_format("unknown colorspace"); - - CGDataProviderRef dp = CGImageGetDataProvider(image); - CFDataRef image_data = CGDataProviderCopyData(dp); - data.pixels = new char[data.height*data.stride]; - unsigned offset = (alpha==kCGImageAlphaNoneSkipFirst); - CFRange range = CFRangeMake(offset, CFDataGetLength(image_data)-offset); - CFDataGetBytes(image_data, range, reinterpret_cast(data.pixels)); - CFRelease(image_data); - - CFRelease(image); } catch(...) { @@ -127,5 +117,18 @@ void QuartzLoader::load_(Image::Data &data) } } +void QuartzLoader::load_(Image::Data &data) +{ + CGDataProviderRef dp = CGImageGetDataProvider(image); + CFDataRef image_data = CGDataProviderCopyData(dp); + data.pixels = new char[data.height*data.stride]; + unsigned offset = (alpha==kCGImageAlphaNoneSkipFirst); + CFRange range = CFRangeMake(offset, CFDataGetLength(image_data)-offset); + CFDataGetBytes(image_data, range, reinterpret_cast(data.pixels)); + CFRelease(image_data); + + CFRelease(image); +} + } // namespace Graphics } // namespace Msp diff --git a/source/graphics/quartz/quartzloader.h b/source/graphics/quartz/quartzloader.h index cf4a447..3e856a9 100644 --- a/source/graphics/quartz/quartzloader.h +++ b/source/graphics/quartz/quartzloader.h @@ -22,7 +22,8 @@ public: static unsigned get_signature_size() { return 12; } static bool detect(const std::string &); - virtual void load_(Image::Data &); + virtual void load_headers_(Image::Data &); + virtual void load_pixels_(Image::Data &); }; } // namespace Graphics -- 2.43.0