forked from rosh/MQL5Book
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
| |
//+------------------------------------------------------------------+
|