MQL5Book/Include/PNG.mqh
super.admin 1c8e83ce31 convert
2025-05-30 16:09:41 +02:00

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