write PNG IDAT and IEND chunks, unit test

This commit is contained in:
nick black 2021-07-15 00:11:29 -04:00 committed by nick black
parent 9c92b83387
commit a55a37a838
3 changed files with 63 additions and 14 deletions

View File

@ -367,7 +367,6 @@ static void
tinfo_debug_styles(const notcurses* nc, struct ncplane* n, const char* indent){
const tinfo* ti = &nc->tcache;
ncplane_putstr(n, indent);
tinfo_debug_style(n, "blink", NCSTYLE_BLINK, ' ');
tinfo_debug_style(n, "bold", NCSTYLE_BOLD, ' ');
tinfo_debug_style(n, "ital", NCSTYLE_ITALIC, ' ');
tinfo_debug_style(n, "struck", NCSTYLE_STRUCK, ' ');
@ -380,7 +379,7 @@ tinfo_debug_styles(const notcurses* nc, struct ncplane* n, const char* indent){
tinfo_debug_cap(n, "sex", ti->caps.sextants, ' ');
tinfo_debug_cap(n, "braille", ti->caps.braille, ' ');
tinfo_debug_cap(n, "images", notcurses_canopen_images(nc), ' ');
tinfo_debug_cap(n, "videos", notcurses_canopen_videos(nc), '\n');
tinfo_debug_cap(n, "video", notcurses_canopen_videos(nc), '\n');
ncplane_set_fg_default(n);
}

View File

@ -13,7 +13,7 @@
// PNG generally allows unsigned 32-bit values to only reach 2**31 "to assist
// [loser] languages which have difficulty dealing with unsigned values."
#define CHUNK_MAX_DATA 0x80000000llu
static const unsigned char PNGHEADER[] = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
static const unsigned char PNGHEADER[] = "\x89PNG\x0d\x0a\x1a\x0a";
// number of bytes necessary to encode (uncompressed) the visual specified by
// |ncv|. if alphap is non-zero, an alpha channel will be used, increasing the
@ -49,7 +49,7 @@ chunk_crc(const char* buf){
}
// write the ihdr at |buf|, which is guaranteed to be large enough (25B).
static int
static size_t
write_ihdr(const ncvisual* ncv, char* buf, unsigned alphap){
uint32_t length = htonl(IHDR_DATA_BYTES);
memcpy(buf, &length, 4);
@ -74,6 +74,22 @@ write_ihdr(const ncvisual* ncv, char* buf, unsigned alphap){
return CHUNK_DESC_BYTES + IHDR_DATA_BYTES; // 25
}
// write 1+ IDAT chunks at |buf|.
static size_t
write_idats(const ncvisual* ncv, char* buf, unsigned alphap){
uint32_t written = 0;
// FIXME
return written;
}
// write the constant 12B IEND chunk at |buf|. it contains no data.
static size_t
write_iend(char* buf){
static const char iend[] = "\x00\x00\x00\x00IEND\xae\x42\x60\x82";
memcpy(buf, iend, CHUNK_DESC_BYTES);
return CHUNK_DESC_BYTES;
}
// write a PNG at the provided buffer using the ncvisual
int create_png(const ncvisual* ncv, void* buf, size_t* bsize, unsigned alphap){
size_t totalsize = compute_png_size(ncv, alphap);
@ -84,13 +100,15 @@ int create_png(const ncvisual* ncv, void* buf, size_t* bsize, unsigned alphap){
*bsize = totalsize;
size_t written = sizeof(PNGHEADER) - 1;
memcpy(buf, PNGHEADER, written);
int r = write_ihdr(ncv, (char*)buf + written, alphap);
if(r < 0){
return -1;
}
size_t r = write_ihdr(ncv, (char*)buf + written, alphap);
written += r;
// FIXME fill in data chunks
// FIXME fill in IEND
r = write_idats(ncv, (char*)buf + written, alphap);
written += r;
r = write_iend((char*)buf + written);
written += r;
if(written != *bsize){
logwarn("PNG was %zuB, not %zuB\n", written, *bsize);
}
return 0;
}
@ -102,17 +120,19 @@ mmap_round_size(size_t s){
// write a PNG, creating the buffer ourselves. it must be munmapped. the
// resulting length is written to *bsize on success. returns MMAP_FAILED
// on a failure.
void* create_png_mmap(const ncvisual* ncv, size_t* bsize){
// on a failure. if |fname| is NULL, an anonymous map will be made.
void* create_png_mmap(const ncvisual* ncv, size_t* bsize, const char* fname){
const unsigned alphap = 1; // FIXME 0 if no alpha used, for smaller output
*bsize = compute_png_size(ncv, alphap);
*bsize = mmap_round_size(*bsize);
if(*bsize == 0){
return MAP_FAILED;
}
// FIXME open and ftruncate file if fname is set
// FIXME hugetlb?
void* map = mmap(NULL, *bsize, PROT_WRITE|PROT_READ,
MAP_SHARED_VALIDATE|MAP_ANONYMOUS, -1, 0);
void* map = mmap(NULL, *bsize, PROT_WRITE | PROT_READ,
MAP_SHARED_VALIDATE |
(fname ? 0 : MAP_ANONYMOUS), -1, 0);
if(map == MAP_FAILED){
logerror("Couldn't get %zuB map\n", *bsize);
return MAP_FAILED;

30
src/tests/png.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "main.h"
#include "png.h"
#include "visual-details.h"
#include <vector>
#include <cmath>
TEST_CASE("PNG") {
auto nc_ = testing_notcurses();
REQUIRE(nullptr != nc_);
ncplane* ncp_ = notcurses_stdplane(nc_);
REQUIRE(ncp_);
auto n_ = notcurses_stdplane(nc_);
REQUIRE(n_);
#ifndef NOTCURSES_USE_MULTIMEDIA
#else
// write a 10x10 opaque PNG out, and ensure we can read it back
SUBCASE("ReadWrittenOpaquePNG") {
std::array<uint32_t, 100> pixels;
pixels.fill(htole(0x00ff0000ull)); // green, opaque set later
auto ncv = ncvisual_from_rgb_loose(pixels.data(), 10, 40, 10, 0xff);
REQUIRE(nullptr != ncv);
// FIXME write out ncvisual to PNG, read it back, render it
CHECK(0 == notcurses_render(nc_));
ncvisual_destroy(ncv);
}
#endif
CHECK(!notcurses_stop(nc_));
}