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
| |||
//+------------------------------------------------------------------+
|