diff --git a/src/info/main.c b/src/info/main.c index 1bf57cc1b..e718e81b5 100644 --- a/src/info/main.c +++ b/src/info/main.c @@ -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); } diff --git a/src/lib/png.c b/src/lib/png.c index 8f0f71e6f..7521d0965 100644 --- a/src/lib/png.c +++ b/src/lib/png.c @@ -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; + r = write_idats(ncv, (char*)buf + written, alphap); written += r; - // FIXME fill in data chunks - // FIXME fill in IEND + 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; diff --git a/src/tests/png.cpp b/src/tests/png.cpp new file mode 100644 index 000000000..a1c313d4d --- /dev/null +++ b/src/tests/png.cpp @@ -0,0 +1,30 @@ +#include "main.h" +#include "png.h" +#include "visual-details.h" +#include +#include + +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 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_)); +}