174 lines
5.3 KiB
MQL5
174 lines
5.3 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| PNG.mqh |
|
|
//| Copyright 2022, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "CRC32.mqh"
|
|
|
|
#define PNG_CTYPE_TRUECOLOR 2
|
|
#define PNG_CTYPE_TRUECOLORALPHA 6
|
|
|
|
namespace PNG
|
|
{
|
|
|
|
const uchar Signature[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Chunk type |
|
|
//| supported chuck types: |
|
|
//| - 0x49484452 'IHDR' |
|
|
//| - 0x49444154 'IDAT' |
|
|
//| - 0x49454E44 'IEND' (crc=0xAE426082) |
|
|
//+------------------------------------------------------------------+
|
|
union ChunkType
|
|
{
|
|
uint num;
|
|
uchar bytes[4];
|
|
ChunkType(uint n): num(MathSwap(n)) { }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Base chunk |
|
|
//+------------------------------------------------------------------+
|
|
struct Chunk
|
|
{
|
|
uint length; // size of content in bytes
|
|
ChunkType type;
|
|
// followed by the following in descendants:
|
|
// C content; // uchar data[];
|
|
// uint crc; // CRC32 of type and content
|
|
Chunk(const uint t, const uint l = 0): type(t), length(l) {}
|
|
void write(const int h)
|
|
{
|
|
FileWriteInteger(h, MathSwap(length));
|
|
FileWriteInteger(h, type.num);
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IHDR chunk fields |
|
|
//+------------------------------------------------------------------+
|
|
struct IHDRfields
|
|
{
|
|
uint width, height;
|
|
uchar depth;
|
|
uchar ctype;
|
|
uchar compression;
|
|
uchar filter;
|
|
uchar interlace;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IHDR chunk bytes |
|
|
//+------------------------------------------------------------------+
|
|
union IHDRbytes
|
|
{
|
|
IHDRfields ihdr;
|
|
uchar bytes[13];
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IHDR chunk |
|
|
//+------------------------------------------------------------------+
|
|
struct IHDR: public Chunk
|
|
{
|
|
IHDRbytes hb;
|
|
|
|
IHDR(const uint w, const uint h, const uchar c = PNG_CTYPE_TRUECOLOR, const uchar d = 8) :
|
|
Chunk(0x49484452, 13)
|
|
{
|
|
IHDRbytes hd = {{MathSwap(w), MathSwap(h), d, c, 0, 0, 0}};
|
|
hb = hd;
|
|
}
|
|
|
|
uint size() const
|
|
{
|
|
return 13;
|
|
}
|
|
|
|
void write(const int h)
|
|
{
|
|
Chunk::write(h);
|
|
FileWriteArray(h, hb.bytes);
|
|
CRC32 crc32;
|
|
const uint c0 = crc32.compute(type.bytes);
|
|
const uint c1 = crc32.compute(hb.bytes, c0) ^ 0xFFFFFFFF;
|
|
FileWriteInteger(h, MathSwap(c1));
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IDAT chunk |
|
|
//+------------------------------------------------------------------+
|
|
struct IDAT: public Chunk
|
|
{
|
|
uchar raw[];
|
|
IDAT(uchar &data[]) : Chunk(0x49444154, ArraySize(data))
|
|
{
|
|
// deflated block begins with 2 bytes:
|
|
// compression method and check bits,
|
|
// then image data follows trailed by Adler32 checksum
|
|
ArraySwap(data, raw);
|
|
}
|
|
uint size() const
|
|
{
|
|
return ArraySize(raw);
|
|
}
|
|
void write(const int h)
|
|
{
|
|
Chunk::write(h);
|
|
FileWriteArray(h, raw);
|
|
CRC32 crc32;
|
|
const uint c0 = crc32.compute(type.bytes);
|
|
const uint c1 = crc32.compute(raw, c0) ^ 0xFFFFFFFF;
|
|
FileWriteInteger(h, MathSwap(c1));
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IEND chunk |
|
|
//+------------------------------------------------------------------+
|
|
struct IEND: public Chunk
|
|
{
|
|
IEND(): Chunk(0x49454E44) { }
|
|
uint size() const
|
|
{
|
|
return 0;
|
|
}
|
|
void write(const int h)
|
|
{
|
|
Chunk::write(h);
|
|
/*
|
|
CRC32 crc32;
|
|
const uint c0 = crc32.compute(type.bytes) ^ 0xFFFFFFFF;
|
|
PrintFormat("%X", c0);
|
|
*/
|
|
FileWriteInteger(h, MathSwap(0xAE426082)); // crc is constant here
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Minimalistic PNG image |
|
|
//+------------------------------------------------------------------+
|
|
struct Image
|
|
{
|
|
PNG::IHDR ihdr;
|
|
PNG::IDAT idat;
|
|
PNG::IEND iend;
|
|
|
|
Image(const int w, const int h, uchar &data[],
|
|
const uchar c = PNG_CTYPE_TRUECOLOR, const uchar d = 8): ihdr(w, h, c, d), idat(data)
|
|
{
|
|
}
|
|
|
|
void write(const int h)
|
|
{
|
|
FileWriteArray(h, Signature);
|
|
ihdr.write(h);
|
|
idat.write(h);
|
|
iend.write(h);
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
//+------------------------------------------------------------------+
|