2017-07-18 20:53:00 +00:00
|
|
|
#include "compat.h"
|
|
|
|
#include "pngwrite.h"
|
|
|
|
#include "crc32.h"
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#include "vfs.h"
|
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
pngwrite_t png;
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#define png_write_buf(p, size) buildvfs_fwrite(p, size, 1, png.file)
|
2017-07-18 20:53:00 +00:00
|
|
|
|
2018-04-04 20:48:10 +00:00
|
|
|
static FORCE_INLINE void png_write_uint32(uint32_t const in)
|
2017-07-18 20:53:00 +00:00
|
|
|
{
|
2018-04-04 20:48:10 +00:00
|
|
|
uint32_t const buf = B_BIG32(in);
|
|
|
|
png_write_buf(&buf, sizeof(uint32_t));
|
2017-07-18 20:53:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void png_write_chunk(uint32_t const size, char const *const type,
|
|
|
|
uint8_t const *const data, uint32_t flags)
|
|
|
|
{
|
2018-10-25 23:30:03 +00:00
|
|
|
mz_ulong chunk_size = (flags & CHUNK_COMPRESSED) ? compressBound(size) : size;
|
2017-07-18 20:53:00 +00:00
|
|
|
uint8_t * const chunk = (uint8_t *) Xcalloc(1, 4 + chunk_size);
|
|
|
|
|
|
|
|
Bmemcpy(chunk, type, 4);
|
|
|
|
|
|
|
|
if (flags & CHUNK_COMPRESSED)
|
|
|
|
compress(chunk + 4, (mz_ulong *) &chunk_size, data, size);
|
|
|
|
else
|
|
|
|
Bmemcpy(chunk + 4, data, size);
|
|
|
|
|
|
|
|
png_write_uint32(chunk_size);
|
|
|
|
png_write_buf(chunk, chunk_size + 4);
|
|
|
|
|
|
|
|
uint32_t crc = Bcrc32(NULL, 0, 0L);
|
|
|
|
crc = Bcrc32(chunk, chunk_size + 4, crc);
|
|
|
|
png_write_uint32(crc);
|
|
|
|
|
|
|
|
Bfree(chunk);
|
|
|
|
}
|
|
|
|
|
|
|
|
void png_set_pal(uint8_t const * const data, int numentries)
|
|
|
|
{
|
|
|
|
png.pal_entries = numentries;
|
|
|
|
png.pal_data = (uint8_t *)Xmalloc(numentries * 3);
|
|
|
|
|
|
|
|
Bmemcpy(png.pal_data, data, numentries * 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void png_set_text(char const * const keyword, char const * const text)
|
|
|
|
{
|
|
|
|
unsigned const keylen = Bstrlen(keyword);
|
|
|
|
Bassert(keylen < 79);
|
|
|
|
unsigned const textlen = Bstrlen(text);
|
|
|
|
|
|
|
|
png.textlen = keylen + textlen + 1;
|
|
|
|
png.text = (uint8_t *) Xrealloc(png.text, png.textlen);
|
|
|
|
|
|
|
|
Bmemcpy(png.text, keyword, keylen);
|
|
|
|
*(png.text + keylen) = 0;
|
|
|
|
Bmemcpy(png.text + keylen + 1, text, textlen);
|
|
|
|
}
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
void png_write(buildvfs_FILE const file, uint32_t const width, uint32_t const height,
|
2018-04-04 20:48:10 +00:00
|
|
|
uint8_t const type, uint8_t const * const data)
|
2017-07-18 20:53:00 +00:00
|
|
|
{
|
|
|
|
png.file = file;
|
2017-07-29 20:39:46 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
png_write_buf("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
|
|
|
|
|
|
|
|
png_ihdr_t const png_header = { B_BIG32(width), B_BIG32(height), 8, type, 0 };
|
|
|
|
png_write_chunk(sizeof(png_ihdr_t), "IHDR", (uint8_t const *)&png_header, 0);
|
|
|
|
|
|
|
|
if (png.text)
|
|
|
|
{
|
|
|
|
png_write_chunk(png.textlen, "tEXt", png.text, 0);
|
|
|
|
DO_FREE_AND_NULL(png.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t const bytesPerPixel = (type == PNG_TRUECOLOR ? 3 : 1);
|
|
|
|
uint32_t const bytesPerLine = width * bytesPerPixel;
|
|
|
|
|
2018-04-04 20:48:10 +00:00
|
|
|
if (png.pal_data)
|
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
png_write_chunk(png.pal_entries * 3, "PLTE", png.pal_data, 0);
|
2018-04-04 20:48:10 +00:00
|
|
|
DO_FREE_AND_NULL(png.pal_data);
|
|
|
|
}
|
2017-07-18 20:53:00 +00:00
|
|
|
|
|
|
|
unsigned const linesiz = height * bytesPerLine + height;
|
|
|
|
uint8_t *lines = (uint8_t *) Xcalloc(1, linesiz);
|
|
|
|
|
2018-04-04 20:48:10 +00:00
|
|
|
for (unative_t i = 0; i < height; i++)
|
2017-07-18 20:53:00 +00:00
|
|
|
Bmemcpy(lines + i * bytesPerLine + i + 1, data + i * bytesPerLine, bytesPerLine);
|
|
|
|
|
|
|
|
png_write_chunk(linesiz, "IDAT", lines, CHUNK_COMPRESSED);
|
|
|
|
png_write_chunk(0, "IEND", NULL, 0);
|
|
|
|
|
|
|
|
Bfree(lines);
|
|
|
|
}
|