Added EXIF parser for jpeg image orientation.

This commit is contained in:
Branimir Karadžić
2017-07-19 22:52:47 -07:00
parent 3e2758c2ee
commit aca9cf49c6
3 changed files with 226 additions and 71 deletions

View File

@@ -133,6 +133,19 @@ namespace bimg
};
};
///
struct Orientation
{
///
enum Enum
{
R0,
R90,
R180,
R270,
};
};
/// Texture info.
///
/// @attention C99 equivalent is `bgfx_texture_info_t`.
@@ -156,6 +169,7 @@ namespace bimg
void* m_data;
TextureFormat::Enum m_format;
Orientation::Enum m_orientation;
uint32_t m_size;
uint32_t m_offset;

View File

@@ -1756,21 +1756,22 @@ namespace bimg
ImageContainer* imageContainer = (ImageContainer*)BX_ALLOC(_allocator, size + sizeof(ImageContainer) );
imageContainer->m_allocator = _allocator;
imageContainer->m_data = imageContainer + 1;
imageContainer->m_format = _format;
imageContainer->m_size = size;
imageContainer->m_offset = 0;
imageContainer->m_width = _width;
imageContainer->m_height = _height;
imageContainer->m_depth = _depth;
imageContainer->m_numLayers = _numLayers;
imageContainer->m_numMips = numMips;
imageContainer->m_hasAlpha = false;
imageContainer->m_cubeMap = _cubeMap;
imageContainer->m_ktx = false;
imageContainer->m_ktxLE = false;
imageContainer->m_srgb = false;
imageContainer->m_allocator = _allocator;
imageContainer->m_data = imageContainer + 1;
imageContainer->m_format = _format;
imageContainer->m_orientation = Orientation::R0;
imageContainer->m_size = size;
imageContainer->m_offset = 0;
imageContainer->m_width = _width;
imageContainer->m_height = _height;
imageContainer->m_depth = _depth;
imageContainer->m_numLayers = _numLayers;
imageContainer->m_numMips = numMips;
imageContainer->m_hasAlpha = false;
imageContainer->m_cubeMap = _cubeMap;
imageContainer->m_ktx = false;
imageContainer->m_ktxLE = false;
imageContainer->m_srgb = false;
if (NULL != _data)
{
@@ -2171,21 +2172,22 @@ namespace bimg
return false;
}
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)bx::seek(_reader);
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_numLayers = uint16_t(arraySize);
_imageContainer.m_numMips = uint8_t( (caps[0] & DDSCAPS_MIPMAP) ? mips : 1);
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = cubeMap;
_imageContainer.m_ktx = false;
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = srgb;
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)bx::seek(_reader);
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_orientation = Orientation::R0;
_imageContainer.m_numLayers = uint16_t(arraySize);
_imageContainer.m_numMips = uint8_t( (caps[0] & DDSCAPS_MIPMAP) ? mips : 1);
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = cubeMap;
_imageContainer.m_ktx = false;
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = srgb;
return true;
}
@@ -2491,21 +2493,22 @@ namespace bimg
}
}
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)offset;
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_numLayers = uint16_t(bx::uint32_max(numberOfArrayElements, 1) );
_imageContainer.m_numMips = uint8_t(bx::uint32_max(numMips, 1) );
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = numFaces > 1;
_imageContainer.m_ktx = true;
_imageContainer.m_ktxLE = fromLittleEndian;
_imageContainer.m_srgb = false;
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)offset;
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_orientation = Orientation::R0;
_imageContainer.m_numLayers = uint16_t(bx::uint32_max(numberOfArrayElements, 1) );
_imageContainer.m_numMips = uint8_t(bx::uint32_max(numMips, 1) );
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = numFaces > 1;
_imageContainer.m_ktx = true;
_imageContainer.m_ktxLE = fromLittleEndian;
_imageContainer.m_srgb = false;
if (TextureFormat::Unknown == format)
{
@@ -2655,21 +2658,22 @@ namespace bimg
}
}
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)offset;
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_numLayers = 1;
_imageContainer.m_numMips = uint8_t(bx::uint32_max(numMips, 1) );
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = numFaces > 1;
_imageContainer.m_ktx = false;
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = colorSpace > 0;
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
_imageContainer.m_offset = (uint32_t)offset;
_imageContainer.m_width = width;
_imageContainer.m_height = height;
_imageContainer.m_depth = depth;
_imageContainer.m_format = format;
_imageContainer.m_orientation = Orientation::R0;
_imageContainer.m_numLayers = 1;
_imageContainer.m_numMips = uint8_t(bx::uint32_max(numMips, 1) );
_imageContainer.m_hasAlpha = hasAlpha;
_imageContainer.m_cubeMap = numFaces > 1;
_imageContainer.m_ktx = false;
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = colorSpace > 0;
return TextureFormat::Unknown != format;
}
@@ -2703,9 +2707,10 @@ namespace bimg
TextureCreate tc;
bx::read(_reader, tc);
_imageContainer.m_format = tc.m_format;
_imageContainer.m_offset = UINT32_MAX;
_imageContainer.m_allocator = NULL;
_imageContainer.m_format = tc.m_format;
_imageContainer.m_orientation = Orientation::R0;
_imageContainer.m_offset = UINT32_MAX;
_imageContainer.m_allocator = NULL;
if (NULL == tc.m_mem)
{
_imageContainer.m_data = NULL;

View File

@@ -466,31 +466,41 @@ namespace bimg
{
BX_ERROR_SCOPE(_err);
const int isHdr = stbi_is_hdr_from_memory((const uint8_t*)_data, (int)_size);
const int isHdr = stbi_is_hdr_from_memory( (const uint8_t*)_data, (int)_size);
void* data;
uint32_t width = 0;
uint32_t height = 0;
int comp = 0;
if (isHdr) { data = stbi_loadf_from_memory((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 4); }
else { data = stbi_load_from_memory ((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 0); }
if (isHdr)
{
data = stbi_loadf_from_memory( (const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 4);
}
else
{
data = stbi_load_from_memory ( (const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 0);
}
if (NULL == data)
{
return NULL;
}
bimg::TextureFormat::Enum format;
bimg::TextureFormat::Enum format = bimg::TextureFormat::RGBA8;
if (isHdr)
{
format = bimg::TextureFormat::RGBA32F;
}
else
{
if (1 == comp) { format = bimg::TextureFormat::R8; }
else if (2 == comp) { format = bimg::TextureFormat::RG8; }
else if (3 == comp) { format = bimg::TextureFormat::RGB8; }
else/*if (4 == comp)*/ { format = bimg::TextureFormat::RGBA8; }
switch (comp)
{
case 1: format = bimg::TextureFormat::R8; break;
case 2: format = bimg::TextureFormat::RG8; break;
case 3: format = bimg::TextureFormat::RGB8; break;
default: break;
}
}
ImageContainer* output = imageAlloc(_allocator
@@ -508,6 +518,131 @@ namespace bimg
return output;
}
static ImageContainer* imageParseJpeg(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
{
bx::MemoryReader reader(_data, _size);
bx::Error err;
uint16_t magic = 0;
bx::readHE(&reader, magic, false, &err);
if (!err.isOk()
|| 0xffd8 != magic)
{
return NULL;
}
Orientation::Enum orientation = Orientation::R0;
while (err.isOk() )
{
bx::readHE(&reader, magic, false, &err);
uint16_t size;
bx::readHE(&reader, size, false, &err);
if (!err.isOk() )
{
return NULL;
}
if (0xffe1 != magic)
{
bx::seek(&reader, size-2);
continue;
}
char exif00[6];
bx::read(&reader, exif00, 6, &err);
if (0 == bx::memCmp(exif00, "Exif\0\0", 6) )
{
uint16_t iimm = 0;
bx::read(&reader, iimm, &err);
const bool littleEndian = iimm == 0x4949; //II - Intel - little endian
if (!err.isOk()
&& !littleEndian
&& iimm != 0x4d4d) // MM - Motorola - big endian
{
return NULL;
}
bx::readHE(&reader, magic, littleEndian, &err);
if (!err.isOk()
|| 0x2a != magic)
{
return NULL;
}
uint32_t ifd0;
bx::readHE(&reader, ifd0, littleEndian, &err);
if (!err.isOk()
|| 8 > ifd0)
{
return NULL;
}
bx::seek(&reader, ifd0-8);
uint16_t numEntries;
bx::readHE(&reader, numEntries, littleEndian, &err);
for (uint32_t ii = 0; err.isOk() && ii < numEntries; ++ii)
{
// https://sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
uint16_t tag;
bx::readHE(&reader, tag, littleEndian, &err);
uint16_t format;
bx::readHE(&reader, format, littleEndian, &err);
uint32_t length;
bx::readHE(&reader, length, littleEndian, &err);
uint32_t data;
bx::readHE(&reader, data, littleEndian, &err);
switch (tag)
{
case 0x112: // orientation
if (3 == format)
{
switch (data)
{
default:
case 1: orientation = Orientation::R0; break; // Horizontal (normal)
case 2: orientation = Orientation::R0; break; // Mirror horizontal
case 3: orientation = Orientation::R180; break; // Rotate 180
case 4: orientation = Orientation::R0; break; // Mirror vertical
case 5: orientation = Orientation::R0; break; // Mirror horizontal and rotate 270 CW
case 6: orientation = Orientation::R90; break; // Rotate 90 CW
case 7: orientation = Orientation::R0; break; // Mirror horizontal and rotate 90 CW
case 8: orientation = Orientation::R270; break; // Rotate 270 CW
}
}
break;
default:
break;
}
}
}
break;
}
ImageContainer* image = imageParseStbImage(_allocator, _data, _size, _err);
if (NULL != image)
{
image->m_orientation = orientation;
}
return image;
}
ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
@@ -517,6 +652,7 @@ namespace bimg
input = NULL == input ? imageParsePvr3 (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseLodePng (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseTinyExr (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseJpeg (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseStbImage(_allocator, _data, _size, _err) : input;
if (NULL == input)