diff --git a/src/fart/main.d b/src/fart/main.d index 5f69c53..704b885 100644 --- a/src/fart/main.d +++ b/src/fart/main.d @@ -1,4 +1,7 @@ +import fart.png; + int main(string[] args) { + png_test(); return 0; } diff --git a/src/fart/png.d b/src/fart/png.d new file mode 100644 index 0000000..6c1d3c4 --- /dev/null +++ b/src/fart/png.d @@ -0,0 +1,121 @@ +module fart.png; + +import std.zlib; +import std.math; +import std.digest; + +import fart.bfile; +import fart.crc32; +import fart.hton; + +private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; + +struct IHDR +{ + uint width; + uint height; + ubyte bit_depth; + ubyte color_type; + ubyte compression; + ubyte filter; + ubyte interlace; + ubyte[0] end; + + this(uint width, uint height) + { + this.width = htonl(width); + this.height = htonl(height); + this.bit_depth = 8; + this.color_type = 6; + this.compression = 0; + this.filter = 0; + this.interlace = 0; + } + + public const(void) * data() + { + return &this; + } + + public size_t data_length() + { + return end.offsetof; + } +} + +struct IDAT +{ + private const(ubyte)[] m_data; + + this(ubyte[] data) + { + m_data = compress(data); + } + + public const(void) * data() + { + return m_data.ptr; + } + + public size_t data_length() + { + return m_data.length; + } +} + +struct IEND +{ + public const(void) * data() + { + return &this; + } + + public size_t data_length() + { + return 0; + } +} + +private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk) +{ + size_t chunk_data_length = chunk.data_length(); + uint chunk_length_be32 = htonl(cast(uint)chunk_data_length); + file.writeObject(chunk_length_be32); + file.write(chunk_type); + const(ubyte)[] chunk_data = (cast(const(ubyte) *)chunk.data())[0..chunk_data_length]; + file.write(chunk_data); + uint crc_be32 = htonl(crc32(chunk_type, chunk_data)); + file.writeObject(crc_be32); +} + +public void write_png(string filename, uint width, uint height, ubyte[] data) +{ + BFile file = BFile(filename); + file.write(HEADER); + IHDR ihdr = IHDR(width, height); + write_chunk(file, "IHDR", ihdr); + IDAT idat = IDAT(data); + write_chunk(file, "IDAT", idat); + IEND iend; + write_chunk(file, "IEND", iend); + file.close(); +} + +void png_test() +{ + ubyte[] pixel_data = []; + for (size_t y = 0; y < 500; y++) + { + /* Filter method 0 (None) */ + pixel_data ~= [0]; + for (size_t x = 0; x < 500; x++) + { + ubyte r = cast(ubyte)(x / 2); + ubyte g = 0x80; + ubyte b = cast(ubyte)((500 - y) / 2); + ubyte a = cast(ubyte)((abs(cast(int)x - 250) + abs(cast(int)y - 250)) / 2); + pixel_data ~= [r, g, b, a]; + } + } + write_png("out.png", 500, 500, pixel_data); +}