Add getImageSize for all image loaders

This commit is contained in:
Benau 2022-08-11 14:46:00 +08:00
parent c698d4a601
commit eace871c66
11 changed files with 189 additions and 43 deletions

View File

@ -43,8 +43,7 @@ public:
/** \param file File handle to check.
\return Pointer to newly created image, or 0 upon error. */
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const = 0;
virtual core::dimension2du getImageSize(io::IReadFile* file) const { return core::dimension2du(0, 0); }
virtual bool supportThreadedLoading() const { return false; }
virtual bool getImageSize(io::IReadFile* file, core::dimension2du* dim) const { return false; }
};

View File

@ -42,6 +42,7 @@ namespace io
//! Get name of file.
/** \return File name as zero terminated character string. */
virtual const io::path& getFileName() const = 0;
virtual void* getFileHandle() const { return NULL; }
};
//! Internal function, please do not use.

View File

@ -214,12 +214,11 @@ void CImageLoaderBMP::decompress4BitRLE(u8*& bmpData, s32 size, s32 width, s32 h
}
//! creates a surface from the file
IImage* CImageLoaderBMP::loadImage(io::IReadFile* file, bool skip_checking) const
SBMPHeader CImageLoaderBMP::getHeader(io::IReadFile* file) const
{
SBMPHeader header;
file->seek(0);
file->read(&header, sizeof(header));
#ifdef __BIG_ENDIAN__
@ -238,6 +237,27 @@ IImage* CImageLoaderBMP::loadImage(io::IReadFile* file, bool skip_checking) cons
header.Colors = os::Byteswap::byteswap(header.Colors);
header.ImportantColors = os::Byteswap::byteswap(header.ImportantColors);
#endif
return header;
}
bool CImageLoaderBMP::getImageSize(io::IReadFile* file, core::dimension2du* dim) const
{
if (!file || !dim)
return false;
SBMPHeader header = getHeader(file);
if (header.Id != 0x4d42)
return false;
*dim = core::dimension2du(header.Width, header.Height);
file->seek(0);
return true;
}
//! creates a surface from the file
IImage* CImageLoaderBMP::loadImage(io::IReadFile* file, bool skip_checking) const
{
SBMPHeader header = getHeader(file);
s32 pitch = 0;

View File

@ -83,11 +83,14 @@ public:
//! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const;
virtual bool getImageSize(io::IReadFile* file, core::dimension2du* dim) const;
private:
void decompress8BitRLE(u8*& BmpData, s32 size, s32 width, s32 height, s32 pitch) const;
void decompress4BitRLE(u8*& BmpData, s32 size, s32 width, s32 height, s32 pitch) const;
SBMPHeader getHeader(io::IReadFile* file) const;
};

View File

@ -11,6 +11,8 @@
#include "os.h"
#include "irrString.h"
#include <stdio.h>
namespace irr
{
namespace video
@ -43,6 +45,78 @@ bool CImageLoaderJPG::isALoadableFileExtension(const io::path& filename) const
#ifdef _IRR_COMPILE_WITH_LIBJPEG_
/* portions derived from IJG code */
#define readbyte(a,b) do if(((a)=getc((b))) == EOF) return 0; while (0)
#define readword(a,b) do { int cc_=0,dd_=0; \
if((cc_=getc((b))) == EOF \
|| (dd_=getc((b))) == EOF) return 0; \
(a) = (cc_<<8) + (dd_); \
} while(0)
int scanhead (FILE * infile, unsigned * image_width, unsigned * image_height) {
int marker=0;
int dummy=0;
if ( !infile || getc(infile) != 0xFF || getc(infile) != 0xD8 )
return 0;
for (;
;){
int discarded_bytes=0;
readbyte(marker,infile);
while (marker != 0xFF) {
discarded_bytes++;
readbyte(marker,infile);
}
do readbyte(marker,infile); while (marker == 0xFF);
if (discarded_bytes != 0) return 0;
switch (marker) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC5:
case 0xC6:
case 0xC7:
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCD:
case 0xCE:
case 0xCF: {
readword(dummy,infile); /* usual parameter length count */
readbyte(dummy,infile);
readword((*image_height),infile);
readword((*image_width),infile);
readbyte(dummy,infile);
return 1;
break;
}
case 0xDA:
case 0xD9:
return 0;
default: {
int length = 0;
readword(length,infile);
if (length < 2)
return 0;
length -= 2;
while (length > 0) {
readbyte(dummy, infile);
length--;
}
}
break;
}
}
}
// struct for handling jpeg errors
struct irr_jpeg_error_mgr
{
@ -283,7 +357,19 @@ IImage* CImageLoaderJPG::loadImage(io::IReadFile* file, bool skip_checking) cons
#endif
}
bool CImageLoaderJPG::getImageSize(io::IReadFile* file, core::dimension2du* dim) const
{
#ifndef _IRR_COMPILE_WITH_LIBJPEG_
return false;
#else
if (!dim || !file || !isALoadableFileFormat(file))
return false;
file->seek(0);
scanhead((FILE*)file->getFileHandle(), &dim->Width, &dim->Height);
file->seek(0);
return true;
#endif
}
//! creates a loader which is able to load jpeg images
IImageLoader* createImageLoaderJPG()

View File

@ -51,6 +51,7 @@ public:
//! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const;
virtual bool getImageSize(io::IReadFile* file, core::dimension2du* dim) const;
private:
#ifdef _IRR_COMPILE_WITH_LIBJPEG_

View File

@ -252,24 +252,23 @@ IImage* CImageLoaderPng::loadImage(io::IReadFile* file, bool skip_checking) cons
#endif // _IRR_COMPILE_WITH_LIBPNG_
}
core::dimension2du CImageLoaderPng::getImageSize(io::IReadFile* file) const
bool CImageLoaderPng::getImageSize(io::IReadFile* file, core::dimension2du* dim) const
{
#ifdef _IRR_COMPILE_WITH_LIBPNG_
if (!file || !isALoadableFileFormat(file))
return core::dimension2du(0, 0);
core::dimension2d<u32> dim;
if (!dim || !file || !isALoadableFileFormat(file))
return false;
file->seek(16);
file->read(&dim.Width, 4);
file->read(&dim->Width, 4);
file->seek(20);
file->read(&dim.Height, 4);
file->read(&dim->Height, 4);
file->seek(0);
#ifndef __BIG_ENDIAN__
dim.Width = os::Byteswap::byteswap(dim.Width);
dim.Height = os::Byteswap::byteswap(dim.Height);
dim->Width = os::Byteswap::byteswap(dim->Width);
dim->Height = os::Byteswap::byteswap(dim->Height);
#endif
return dim;
return true;
#else
return core::dimension2du(0, 0);
return false;
#endif // _IRR_COMPILE_WITH_LIBPNG_
}

View File

@ -34,8 +34,8 @@ public:
//! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const;
virtual core::dimension2du getImageSize(io::IReadFile* file) const;
virtual bool supportThreadedLoading() const { return true; }
virtual bool getImageSize(io::IReadFile* file, core::dimension2du* dim) const;
};

View File

@ -64,25 +64,23 @@ bool CImageLoaderSVG::isALoadableFileFormat(io::IReadFile* file) const
}
//! creates a surface from the file
IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) const
struct NSVGimage* CImageLoaderSVG::getSVGImage(io::IReadFile* file, float* scale) const
{
// check IMG_LoadSVG_RW
if (!file)
return NULL;
file->seek(0);
struct NSVGimage *img = 0;
struct NSVGrasterizer *rasterizer = 0;
video::IImage* image = 0;
int w, h;
// read all the characters in the svg file to data
long filesize = file->getSize();
char* data = new char[filesize+1];
int readsize = file->read(data,filesize);
data[filesize] = '\0';
if( (long)readsize != filesize) {
os::Printer::log("Couldn't read SVG image file", file->getFileName(), ELL_ERROR);
delete[] data;
return 0;
return NULL;
}
// parse the svg image
@ -90,10 +88,57 @@ IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) cons
if ( !img ) {
os::Printer::log("Couldn't parse SVG image", ELL_ERROR);
delete[] data;
return 0;
return NULL;
}
delete[] data;
// only rescale the icons
if ( strstr(file->getFileName().c_str(),"gui/icons/") )
{
#ifndef SERVER_ONLY
// determine scaling based on screen size
float screen_height = (float)GE::getDriver()->getCurrentRenderTargetSize().Height;
float desired_icon_size = 0.21*screen_height + 30.0f; // phenomenological
*scale = desired_icon_size/img->height;
#endif
}
return img;
}
core::dimension2du CImageLoaderSVG::getImageSize(struct NSVGimage* img, float scale) const
{
core::dimension2du dim;
dim.Width = (unsigned)(img->width*scale);
dim.Height = (unsigned)(img->height*scale);
return dim;
}
bool CImageLoaderSVG::getImageSize(io::IReadFile* file, core::dimension2du* dim) const
{
if (!dim || !file || !isALoadableFileFormat(file))
return false;
float scale = 1.0f;
struct NSVGimage *img = getSVGImage(file, &scale);
if (!img)
return false;
*dim = getImageSize(img, scale);
nsvgDelete(img);
file->seek(0);
return true;
}
//! creates a surface from the file
IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) const
{
// check IMG_LoadSVG_RW
float scale = 1.0f;
struct NSVGimage *img = getSVGImage(file, &scale);
struct NSVGrasterizer *rasterizer = 0;
video::IImage* image = 0;
rasterizer = nsvgCreateRasterizer();
if ( !rasterizer ) {
os::Printer::log("Couldn't create SVG rasterizer", ELL_ERROR);
@ -101,22 +146,7 @@ IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) cons
return 0;
}
float scale =1.0f;
// only rescale the icons
if ( strstr(file->getFileName().c_str(),"gui/icons/") )
{
#ifndef SERVER_ONLY
// determine scaling based on screen size
float screen_height = (float)GE::getDriver()->getCurrentRenderTargetSize().Height;
float desired_icon_size = 0.21*screen_height + 30.0f; // phenomenological
scale = desired_icon_size/img->height;
#endif
}
// create surface
w = (int)(img->width*scale);
h = (int)(img->height*scale);
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(w, h));
image = new CImage(ECF_A8R8G8B8, getImageSize(img, scale));
if ( !image ) {
os::Printer::log("LOAD SVG: create image struct failure", file->getFileName(), ELL_ERROR);
nsvgDeleteRasterizer( rasterizer );

View File

@ -48,6 +48,11 @@ public:
//! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const;
virtual bool getImageSize(io::IReadFile* file, core::dimension2du* dim) const;
private:
struct NSVGimage* getSVGImage(io::IReadFile* file, float* scale) const;
core::dimension2du getImageSize(struct NSVGimage* img, float scale) const;
};

View File

@ -47,6 +47,8 @@ namespace io
//! returns name of file
virtual const io::path& getFileName() const;
virtual void* getFileHandle() const { return (void*)File; }
private:
//! opens the file