#ifndef __WEBP_Support_hpp__
#define __WEBP_Support_hpp__ 1
#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
#include "public/include/XMP_Const.h"
#include "public/include/XMP_IO.hpp"
#include "XMPFiles/source/XMPFiles_Impl.hpp"
#include "source/Endian.h"
#include "source/XMPFiles_IO.hpp"
#include <array>
#include <map>
#include <vector>
// forward declaration:
class WEBP_MetaHandler;
namespace WEBP {
// Read 16, 24 or 32 bits stored in little-endian order.
//
// The inline functions provided in EndianUtils.hpp and XIO.hpp operate on
// pointers to XMP_Uns32, and then flip the bytes if the desired endianness
// differs from the host's. It seems to me that it is much simpler to read
// the data into XMP_Uns8 (i.e. unsigned char) arrays and just use shift
// operators (which operate on values rather than their representation
// in memory) to convert between values and the bytes read from or written to
// a file in a platform-independent way. And besides, WEBP stores dimensions
// in 24 bit LE, and converting that to and from a 32 bit pointer, having to
// account for the platform's endianness, would be a nightmare.
static inline XMP_Uns32 GetLE16(const XMP_Uns8* const data)
{
return (XMP_Uns32)(data[0] << 0) | (data[1] << 8);
}
static inline XMP_Uns32 GetLE24(const XMP_Uns8* const data)
{
return GetLE16(data) | (data[2] << 16);
}
static inline XMP_Uns32 GetLE32(const XMP_Uns8* const data)
{
return (XMP_Uns32)GetLE16(data) | (GetLE16(data + 2) << 16);
}
// Store 16, 24 or 32 bits in little-endian order.
static inline void PutLE16(XMP_Uns8* const data, XMP_Uns32 val)
{
assert(val < (1 << 16));
data[0] = (val >> 0);
data[1] = (val >> 8);
}
static inline void PutLE24(XMP_Uns8* const buf, XMP_Uns32 val)
{
assert(val < (1 << 24));
PutLE16(buf, val & 0xffff);
buf[2] = (val >> 16);
}
static inline void PutLE32(XMP_Uns8* const data, XMP_Uns32 val)
{
PutLE16(data, (XMP_Uns32)(val & 0xffff));
PutLE16(data + 2, (XMP_Uns32)(val >> 16));
}
#define WEBP_MKFOURCC(a, b, c, d) \
((XMP_Uns32)(a) | (b) << 8 | (c) << 16 | (d) << 24)
// VP8X Feature Flags.
typedef enum FeatureFlagBits {
FRAGMENTS_FLAG_BIT, // Experimental, not enabled by default
ANIMATION_FLAG_BIT,
XMP_FLAG_BIT,
EXIF_FLAG_BIT,
ALPHA_FLAG_BIT,
ICCP_FLAG_BIT
} FeatureFlagBits;
typedef enum ChunkId {
WEBP_CHUNK_VP8X, // VP8X
WEBP_CHUNK_ICCP, // ICCP
WEBP_CHUNK_ANIM, // ANIM
WEBP_CHUNK_ANMF, // ANMF
WEBP_CHUNK_FRGM, // FRGM
WEBP_CHUNK_ALPHA, // ALPH
WEBP_CHUNK_IMAGE, // VP8/VP8L
WEBP_CHUNK_EXIF, // EXIF
WEBP_CHUNK_XMP, // XMP
WEBP_CHUNK_UNKNOWN, // Other chunks.
WEBP_CHUNK_NIL
} ChunkId;
const XMP_Uns32 kChunk_RIFF = WEBP_MKFOURCC('R', 'I', 'F', 'F');
const XMP_Uns32 kChunk_WEBP = WEBP_MKFOURCC('W', 'E', 'B', 'P');
const XMP_Uns32 kChunk_VP8_ = WEBP_MKFOURCC('V', 'P', '8', ' ');
const XMP_Uns32 kChunk_VP8L = WEBP_MKFOURCC('V', 'P', '8', 'L');
const XMP_Uns32 kChunk_VP8X = WEBP_MKFOURCC('V', 'P', '8', 'X');
const XMP_Uns32 kChunk_XMP_ = WEBP_MKFOURCC('X', 'M', 'P', ' ');
const XMP_Uns32 kChunk_ANIM = WEBP_MKFOURCC('A', 'N', 'I', 'M');
const XMP_Uns32 kChunk_ICCP = WEBP_MKFOURCC('I', 'C', 'C', 'P');
const XMP_Uns32 kChunk_EXIF = WEBP_MKFOURCC('E', 'X', 'I', 'F');
const XMP_Uns32 kChunk_ANMF = WEBP_MKFOURCC('A', 'N', 'M', 'F');
const XMP_Uns32 kChunk_FRGM = WEBP_MKFOURCC('F', 'R', 'G', 'M');
const XMP_Uns32 kChunk_ALPH = WEBP_MKFOURCC('A', 'L', 'P', 'H');
static std::map<XMP_Uns32, ChunkId> chunkMap = {
{ kChunk_VP8X, WEBP_CHUNK_VP8X }, { kChunk_ICCP, WEBP_CHUNK_ICCP },
{ kChunk_ANIM, WEBP_CHUNK_ANIM }, { kChunk_ANMF, WEBP_CHUNK_ANMF },
{ kChunk_FRGM, WEBP_CHUNK_FRGM }, { kChunk_ALPH, WEBP_CHUNK_ALPHA },
{ kChunk_VP8_, WEBP_CHUNK_IMAGE }, { kChunk_VP8L, WEBP_CHUNK_IMAGE },
{ kChunk_EXIF, WEBP_CHUNK_EXIF }, { kChunk_XMP_, WEBP_CHUNK_XMP }
};
class Container;
class Chunk {
public:
Chunk(Container* parent, WEBP_MetaHandler* handler);
Chunk(Container* parent, XMP_Uns32 tag);
virtual ~Chunk();
virtual void write(WEBP_MetaHandler* handler);
Container* parent;
XMP_Uns32 tag;
RawDataBlock data;
XMP_Int64 pos;
XMP_Int64 size;
bool needsRewrite;
};
class XMPChunk
: public Chunk {
public:
XMPChunk(Container* parent, WEBP_MetaHandler* handler);
XMPChunk(Container* parent);
void write(WEBP_MetaHandler* handler);
};
class VP8XChunk
: public Chunk {
public:
VP8XChunk(Container* parent, WEBP_MetaHandler* handler);
VP8XChunk(Container* parent);
bool xmp();
void xmp(bool);
XMP_Uns32 width();
XMP_Uns32 height();
void width(XMP_Uns32);
void height(XMP_Uns32);
};
typedef std::array<std::vector<Chunk*>, WEBP_CHUNK_NIL> Chunks;
class Container
: public Chunk {
public:
Container(WEBP_MetaHandler* handler);
~Container();
void write(WEBP_MetaHandler* handler);
void addChunk(Chunk*);
Chunk* getExifChunk();
Chunks chunks;
VP8XChunk* vp8x;
};
} // namespace WEBP
#endif // __WEBP_Support_hpp__