Default to 800x600 transparent image output

This commit is contained in:
Josh Holtrop 2023-10-11 09:58:21 -04:00
parent f8fc3518dd
commit 6e04286cc2
3 changed files with 70 additions and 24 deletions

View File

@ -40,4 +40,6 @@ struct Color
{ {
return cast(ubyte)(0xFF * v); return cast(ubyte)(0xFF * v);
} }
public static immutable Color TRANSPARENT = Color(0, 0, 0, 0);
} }

View File

@ -1,7 +1,27 @@
import fart.png; module fart.main;
import fart.png;
import fart.color;
/**
* Main program entry point.
*
* @param args
* Program arguments.
*/
int main(string[] args) int main(string[] args)
{ {
png_test(); size_t width = 800;
size_t height = 600;
string output_filename = "out.png";
Color[] pixels = [];
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
pixels ~= Color.TRANSPARENT;
}
}
write_png(output_filename, width, height, pixels);
return 0; return 0;
} }

View File

@ -1,7 +1,6 @@
module fart.png; module fart.png;
import std.zlib; import std.zlib;
import std.math;
import std.digest; import std.digest;
import fart.bfile; import fart.bfile;
@ -9,8 +8,14 @@ import fart.crc32;
import fart.hton; import fart.hton;
import fart.color; import fart.color;
/**
* PNG file header.
*/
private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
/**
* PNG IHDR chunk.
*/
struct IHDR struct IHDR
{ {
uint width; uint width;
@ -22,10 +27,10 @@ struct IHDR
ubyte interlace; ubyte interlace;
ubyte[0] end; ubyte[0] end;
this(uint width, uint height) this(size_t width, size_t height)
{ {
this.width = htonl(width); this.width = htonl(cast(uint)width);
this.height = htonl(height); this.height = htonl(cast(uint)height);
this.bit_depth = 8; this.bit_depth = 8;
this.color_type = 6; this.color_type = 6;
this.compression = 0; this.compression = 0;
@ -44,6 +49,9 @@ struct IHDR
} }
} }
/**
* PNG IDAT chunk.
*/
struct IDAT struct IDAT
{ {
private const(ubyte)[] m_data; private const(ubyte)[] m_data;
@ -64,6 +72,9 @@ struct IDAT
} }
} }
/**
* PNG IEND chunk.
*/
struct IEND struct IEND
{ {
public const(void) * data() public const(void) * data()
@ -77,6 +88,16 @@ struct IEND
} }
} }
/**
* Write a PNG chunk to the output file.
*
* @param file
* Output file
* @param chunk_type
* Chunk type.
* @param chunk
* Chunk to write.
*/
private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk) private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk)
{ {
size_t chunk_data_length = chunk.data_length(); size_t chunk_data_length = chunk.data_length();
@ -89,11 +110,24 @@ private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk)
file.writeObject(crc_be32); file.writeObject(crc_be32);
} }
public void write_png(string filename, uint width, uint height, const(Color)[] data) /**
* Write a PNG image from the given metadata and pixel data.
*
* @param filename
* Name of file to write.
* @param width
* Width of image.
* @param height
* Height of image.
* @param data
* Pixel color data.
*/
public void write_png(string filename, size_t width, size_t height, const(Color)[] data)
{ {
if (data.length != width * height) if (data.length != width * height)
return; return;
/* Convert Color values to 32-bit RGBA values. */
ubyte[] pixel_data; ubyte[] pixel_data;
size_t data_index; size_t data_index;
for (size_t y = 0; y < height; y++) for (size_t y = 0; y < height; y++)
@ -105,30 +139,20 @@ public void write_png(string filename, uint width, uint height, const(Color)[] d
pixel_data ~= data[data_index++].rgba32(); pixel_data ~= data[data_index++].rgba32();
} }
} }
/* Open output file. */
BFile file = BFile(filename); BFile file = BFile(filename);
/* Write PNG header. */
file.write(HEADER); file.write(HEADER);
/* Write IHDR chunk. */
IHDR ihdr = IHDR(width, height); IHDR ihdr = IHDR(width, height);
write_chunk(file, "IHDR", ihdr); write_chunk(file, "IHDR", ihdr);
/* Write IDAT chunk. */
IDAT idat = IDAT(pixel_data); IDAT idat = IDAT(pixel_data);
write_chunk(file, "IDAT", idat); write_chunk(file, "IDAT", idat);
/* Write IEND chunk. */
IEND iend; IEND iend;
write_chunk(file, "IEND", iend); write_chunk(file, "IEND", iend);
/* Close output file. */
file.close(); file.close();
} }
void png_test()
{
Color[] pixel_data = [];
for (size_t y = 0; y < 500; y++)
{
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 ~= Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
}
}
write_png("out.png", 500, 500, pixel_data);
}