rename ncvisual_open_plane->ncvisual_from_file() #560

pull/587/head
nick black 4 years ago committed by Nick Black
parent 7e9cc29f8e
commit 39548acc3a

@ -5,6 +5,8 @@ rearrangements of Notcurses.
* `notcurses_lex_margins()` has been added to lex margins expressed in either
of two canonical formats. Hopefully this will lead to more programs
supporting margins.
* `ncvisual_open_plane()` has been renamed `ncvisual_from_file()`. The former
has been retained as a deprecated alias. It will be removed by 1.6/2.0.
* 1.3.3 (2020-04-26)
* The `ncdplot` type has been added for plots based on `double`s rather than

@ -2375,7 +2375,7 @@ struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file, nc_er
// new plane will be exactly that large. Otherwise, the plane will be as large
// as possible (given the visible screen), either maintaining aspect ratio
// (NCSCALE_SCALE) or abandoning it (NCSCALE_STRETCH).
struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file, nc_err_e* err, int y, int x, ncscale_e style);
struct ncvisual* ncvisual_from_file(struct notcurses* nc, const char* file, nc_err_e* err, int y, int x, ncscale_e style);
// Destroy an ncvisual. Rendered elements will not be disrupted, but the visual
// can be neither decoded nor rendered any further.
@ -2440,3 +2440,19 @@ char* ncvisual_subtitle(const struct ncvisual* ncv);
int ncplane_rotate_cw(struct ncplane* n);
int ncplane_rotate_ccw(struct ncplane* n);
```
It is also possible to seed an `ncvisual` directly from memory, without involving
a file. Both RGBA and BGRA 8bpc arrangements can be used.
```c
// Prepare an ncvisual, and its underlying plane, based off RGBA content in
// memory at 'rgba'. 'rgba' must be a flat array of 32-bit 8bpc RGBA pixels.
// These must be arranged in 'rowstride' * 4b lines, where the first 'cols'
// * 4b are actual data. There must be 'rows' lines. The total size of 'rgba'
// must thus be at least (rows * rowstride * 4) bytes, of which (rows * cols
// * 4) bytes are actual data. The resulting plane will be 'rows' / 2 x 'cols'.
ncvisual* ncvisual_from_rgba(notcurses* nc, const void* rgba, int rows, int rowstride, int cols);
// ncvisual_from_rgba(), but for BGRA.
ncvisual* ncvisual_from_bgra(notcurses* nc, const void* bgra, int rows, int rowstride, int cols);
```

@ -24,10 +24,14 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
**struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file,
nc_err_e* err);**
**struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file,
**struct ncvisual* ncvisual_from_file(struct notcurses* nc, const char* file,
nc_err_e* err, int y, int x,
ncscale_e style);**
**struct ncvisual* ncvisual_from_rgba(struct notcurses* nc, const void* rgba, int rows, int rowstride, int cols);**
**struct ncvisual* ncvisual_from_bgra(struct notcurses* nc, const void* bgra, int rows, int rowstride, int cols);**
**void ncvisual_destroy(struct ncvisual* ncv);**
**nc_err_e ncvisual_decode(struct ncvisual* nc);**
@ -60,6 +64,18 @@ or **begx** are an error. It is an error to specify any region beyond the
boundaries of the frame. Supplying zero for either **leny** or **lenx** will
result in a zero-area rendering.
It is possible to create an **ncvisual** from memory, rather than from a
disk, but only using raw RGBA/BGRA 8bpc content. For RGBA, use
**ncvisual_from_rgba**. For BGRA, use **ncvisual_from_bgra**. Both require
a number of **rows**, a number of image columns **cols**, and a virtual row
length of **rowstride** columns. The input data must provide 32 bits per
pixel, and thus must be at least **rowstride** * **rows** * 4 bytes, of
which a **cols** * **rows** * 4-byte subset is used. It is not possible to
**mmap(2)** an image file and use it directly--decompressed, decoded data
is necessary. The resulting plane will be **rows** / 2 rows, and **cols**
columns. It will not be necessary to call **ncvisual_decode**, but it is
still necessary to call **ncvisual_render**.
Both **ncplane_rotate_cw** and **ncplane_rotate_ccw** execute a rotation of
π/2 radians, in the clockwise or counterclockwise direction respectively.
@ -71,7 +87,7 @@ be returned for multiple frames, or might not.
**notcurses_canopen** returns true if this functionality is enabled, or false
if Notcurses was not built with multimedia support. **ncplane_visual_open** and
**ncvisual_open_plane** return an **ncvisual** object on success, or **NULL**
**ncvisual_from_file** return an **ncvisual** object on success, or **NULL**
on failure. Success from these functions indicates that the specified **file**
was opened, and enough data was read to make a firm codec identification. It
does not mean that the entire file is properly-formed. On failure, **err**

@ -41,7 +41,7 @@ namespace ncpp
explicit Visual (const char *file, nc_err_e* ncerr, int y, int x, NCScale scale)
{
visual = ncvisual_open_plane (get_notcurses (), file, ncerr, y, x, static_cast<ncscale_e>(scale));
visual = ncvisual_from_file (get_notcurses (), file, ncerr, y, x, static_cast<ncscale_e>(scale));
if (visual == nullptr)
throw init_error ("notcurses failed to create a new visual");
}

@ -2031,7 +2031,7 @@ ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
API struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file,
nc_err_e* ncerr);
// How to scale the visual in ncvisual_open_plane(). NCSCALE_NONE will open a
// How to scale the visual in ncvisual_from_file(). NCSCALE_NONE will open a
// plane tailored to the visual's exact needs, which is probably larger than the
// visible screen (but might be smaller). NCSCALE_SCALE scales a visual larger
// than the visible screen down, maintaining aspect ratio. NCSCALE_STRETCH
@ -2048,9 +2048,33 @@ typedef enum {
// new plane will be exactly that large. Otherwise, the plane will be as large
// as possible (given the visible screen), either maintaining aspect ratio
// (NCSCALE_SCALE) or abandoning it (NCSCALE_STRETCH).
API struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file,
nc_err_e* ncerr, int y, int x,
ncscale_e style);
API struct ncvisual* ncvisual_from_file(struct notcurses* nc, const char* file,
nc_err_e* ncerr, int y, int x,
ncscale_e style);
// Remove by 1.6/2.0 FIXME
static inline struct ncvisual*
ncvisual_open_plane(struct notcurses* nc, const char* file, nc_err_e* ncerr,
int y, int x, ncscale_e style) __attribute__ ((deprecated));
static inline struct ncvisual*
ncvisual_open_plane(struct notcurses* nc, const char* file, nc_err_e* ncerr,
int y, int x, ncscale_e style){
return ncvisual_from_file(nc, file, ncerr, y, x, style);
}
// Prepare an ncvisual, and its underlying plane, based off RGBA content in
// memory at 'rgba'. 'rgba' must be a flat array of 32-bit 8bpc RGBA pixels.
// These must be arranged in 'rowstride' * 4b lines, where the first 'cols'
// * 4b are actual data. There must be 'rows' lines. The total size of 'rgba'
// must thus be at least (rows * rowstride * 4) bytes, of which (rows * cols
// * 4) bytes are actual data. The resulting plane will be 'rows' / 2 x 'cols'.
API struct ncvisual* ncvisual_from_rgba(struct notcurses* nc, const void* rgba,
int rows, int rowstride, int cols);
// ncvisual_from_rgba(), but 'bgra' is arranged as BGRA.
API struct ncvisual* ncvisual_from_bgra(struct notcurses* nc, const void* bgra,
int rows, int rowstride, int cols);
// Return the plane to which this ncvisual is bound.
API struct ncplane* ncvisual_plane(struct ncvisual* ncv);
@ -2715,6 +2739,14 @@ API int ncsubproc_destroy(struct ncsubproc* n);
// future compatability (provide 0 for no artificail bound).
API int ncplane_qrcode(struct ncplane* n, int maxversion, const void* data, size_t len);
// Promote an ncplane 'n' to an ncvisual. The plane should not be associated
// with an existing ncvisual, and may contain only spaces, half blocks, and
// full blocks. The latter will be checked, and any other glyph will result
// in a NULL being returned. This function exists so that planes can be
// subjected to ncvisual transformations. If possible, it's usually better
// to create the ncvisual from memory using ncvisual_from_rgba().
API struct ncvisual* ncvisual_from_plane(struct ncplane* n);
#undef API
#ifdef __cplusplus

@ -285,7 +285,9 @@ typedef enum {
NCSCALE_SCALE,
NCSCALE_STRETCH,
} ncscale_e;
struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file, nc_err_e* err, int y, int x, ncscale_e style);
struct ncvisual* ncvisual_from_file(struct notcurses* nc, const char* file, nc_err_e* err, int y, int x, ncscale_e style);
struct ncvisual* ncvisual_from_rgba(struct notcurses* nc, const void* rgba, int rows, int rowstride, int cols);
struct ncvisual* ncvisual_from_bgra(struct notcurses* nc, const void* bgra, int rows, int rowstride, int cols);
struct ncplane* ncvisual_plane(struct ncvisual* ncv);
void ncvisual_destroy(struct ncvisual* ncv);
nc_err_e ncvisual_decode(struct ncvisual* nc);

@ -20,7 +20,7 @@ chunli_draw(struct notcurses* nc, const char* ext, int count, const cell* b){
notcurses_refresh(nc, &dimy, &dimx);
snprintf(file, sizeof(file), "chunli%d.%s", i + 1, ext);
chuns[i].path = find_data(file);
chuns[i].ncv = ncvisual_open_plane(nc, chuns[i].path, &err, 0, 0, NCSCALE_NONE);
chuns[i].ncv = ncvisual_from_file(nc, chuns[i].path, &err, 0, 0, NCSCALE_NONE);
if(chuns[i].ncv == NULL){
return -1;
}
@ -66,7 +66,7 @@ int chunli_demo(struct notcurses* nc){
snprintf(file, sizeof(file), "chunli%02d.png", i);
char* path = find_data(file);
nc_err_e err;
struct ncvisual* ncv = ncvisual_open_plane(nc, path, &err, 0, 0, NCSCALE_NONE);
struct ncvisual* ncv = ncvisual_from_file(nc, path, &err, 0, 0, NCSCALE_NONE);
if(ncv == NULL){
free(path);
break;

@ -27,7 +27,7 @@ const char eagle1[] =
static int
outzoomed_map(struct notcurses* nc, const char* map){
nc_err_e ncerr;
struct ncvisual* ncv = ncvisual_open_plane(nc, map, &ncerr, 0, 0, NCSCALE_SCALE);
struct ncvisual* ncv = ncvisual_from_file(nc, map, &ncerr, 0, 0, NCSCALE_SCALE);
if(ncv == NULL){
return -1;
}
@ -50,7 +50,7 @@ zoom_map(struct notcurses* nc, const char* map){
// and begin opening it on larger and larger planes that fit on the screen
// less and less. eventually, reach our natural NCSCALE_NONE size and begin
// scrolling through the map, whooooooooosh.
struct ncvisual* ncv = ncvisual_open_plane(nc, map, &ncerr, 0, 0, NCSCALE_NONE);
struct ncvisual* ncv = ncvisual_from_file(nc, map, &ncerr, 0, 0, NCSCALE_NONE);
if(ncv == NULL){
return NULL;
}

@ -187,7 +187,7 @@ int luigi_demo(struct notcurses* nc){
if(fname == NULL){
return -1;
}
wmncv = ncvisual_open_plane(nc, fname, &ncerr, 0, 0, NCSCALE_NONE);
wmncv = ncvisual_from_file(nc, fname, &ncerr, 0, 0, NCSCALE_NONE);
free(fname);
if(wmncv == NULL){
return -1;

@ -39,9 +39,11 @@ const char* oiio_version(void);
#include "notcurses/notcurses.h"
#include "egcpool.h"
struct SwsContext;
struct esctrie;
// we can't define multipart ncvisual here, because OIIO requires C++ syntax,
// and we can't go throwing C++ syntax into this header. so it goes.
// A plane is memory for some rectilinear virtual window, plus current cursor
// state for that window. A notcurses context describes a single terminal, and
// has a z-order of planes (I see no advantage to maintaining a poset, and we
@ -634,6 +636,8 @@ enforce_utf8(void){
return true;
}
struct ncvisual* ncvisual_create(float timescale);
#ifdef __cplusplus
}
#endif

@ -10,16 +10,6 @@ struct AVCodecParameters;
struct AVPacket;
typedef struct ncvisual {
struct AVFormatContext* fmtctx;
struct AVCodecContext* codecctx; // video codec context
struct AVCodecContext* subtcodecctx; // subtitle codec context
struct AVFrame* frame;
struct AVFrame* oframe;
struct AVCodec* codec;
struct AVCodecParameters* cparams;
struct AVCodec* subtcodec;
struct AVPacket* packet;
struct SwsContext* swsctx;
int packet_outstanding;
int dstwidth, dstheight;
int stream_index; // match against this following av_read_frame()
@ -33,6 +23,16 @@ typedef struct ncvisual {
ncscale_e style; // none, scale, or stretch
struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane
#ifdef USE_FFMPEG
struct AVFormatContext* fmtctx;
struct AVCodecContext* codecctx; // video codec context
struct AVCodecContext* subtcodecctx; // subtitle codec context
struct AVFrame* frame;
struct AVFrame* oframe;
struct AVCodec* codec;
struct AVCodecParameters* cparams;
struct AVCodec* subtcodec;
struct AVPacket* packet;
struct SwsContext* swsctx;
AVSubtitle subtitle;
#endif
} ncvisual;
@ -42,6 +42,16 @@ ncplane* ncvisual_plane(ncvisual* ncv){
return ncv->ncp;
}
ncvisual* ncvisual_create(float timescale){
ncvisual* ret = malloc(sizeof(*ret));
if(ret == NULL){
return NULL;
}
memset(ret, 0, sizeof(*ret));
ret->timescale = timescale;
return ret;
}
void ncvisual_destroy(ncvisual* ncv){
if(ncv){
avcodec_close(ncv->codecctx);
@ -64,17 +74,6 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){
return true;
}
static ncvisual*
ncvisual_create(float timescale){
ncvisual* ret = malloc(sizeof(*ret));
if(ret == NULL){
return NULL;
}
memset(ret, 0, sizeof(*ret));
ret->timescale = timescale;
return ret;
}
/* static void
print_frame_summary(const AVCodecContext* cctx, const AVFrame* f){
char pfmt[128];
@ -386,7 +385,7 @@ ncvisual* ncplane_visual_open(ncplane* nc, const char* filename, nc_err_e* ncerr
return ncv;
}
ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
ncvisual* ncvisual_from_file(notcurses* nc, const char* filename,
nc_err_e* ncerr, int y, int x, ncscale_e style){
ncvisual* ncv = ncvisual_open(filename, ncerr);
if(ncv == NULL){
@ -509,6 +508,12 @@ int ncvisual_init(int loglevel){
// FIXME could also use av_log_set_callback() and capture the message...
return 0;
}
ncvisual* ncvisual_from_rgba(notcurses* nc, const void* rgba, int rows, int rowstride, int cols){
}
ncvisual* ncvisual_from_bgra(notcurses* nc, const void* bgra, int rows, int rowstride, int cols){
}
#else // built without ffmpeg
#ifndef USE_OIIO // built without ffmpeg or oiio
bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){
@ -551,7 +556,7 @@ ncvisual* ncplane_visual_open(ncplane* nc, const char* filename, nc_err_e* ncerr
return NULL;
}
ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
ncvisual* ncvisual_from_file(notcurses* nc, const char* filename,
nc_err_e* ncerr, int y, int x, ncscale_e style){
(void)nc;
(void)filename;
@ -577,5 +582,22 @@ void ncvisual_destroy(ncvisual* ncv){
(void)ncv;
}
ncvisual* ncvisual_from_rgba(notcurses* nc, const void* rgba, int rows, int rowstride, int cols){
(void)nc;
(void)rgba;
(void)rows;
(void)rowstride;
(void)cols;
return NULL;
}
ncvisual* ncvisual_from_bgra(notcurses* nc, const void* bgra, int rows, int rowstride, int cols){
(void)nc;
(void)bgra;
(void)rows;
(void)rowstride;
(void)cols;
return NULL;
}
#endif
#endif

@ -35,8 +35,7 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){
return true;
}
static ncvisual*
ncvisual_create(const char* filename, float timescale){
ncvisual* ncvisual_create(float timescale){
auto ret = new ncvisual;
if(ret == nullptr){
return nullptr;
@ -52,7 +51,7 @@ ncvisual_create(const char* filename, float timescale){
ret->ncobj = nullptr;
ret->frame = nullptr;
ret->raw = nullptr;
ret->filename = strdup(filename);
ret->filename = nullptr;
return ret;
}
@ -63,10 +62,16 @@ ncvisual_open(const char* filename, nc_err_e* err){
*err = NCERR_NOMEM;
return nullptr;
}
if((ncv->filename = strdup(filename)) == nullptr){
*err = NCERR_NOMEM;
delete ncv;
return nullptr;
}
ncv->image = OIIO::ImageInput::open(filename);
if(!ncv->image){
// fprintf(stderr, "Couldn't create %s (%s)\n", filename, strerror(errno));
*err = NCERR_DECODE;
ncvisual_destroy(ncv);
return nullptr;
}
/*const auto &spec = ncv->image->spec_dimensions();
@ -89,8 +94,8 @@ ncvisual* ncplane_visual_open(ncplane* nc, const char* filename, nc_err_e* ncerr
return ncv;
}
ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
nc_err_e* ncerr, int y, int x, ncscale_e style){
ncvisual* ncvisual_from_file(notcurses* nc, const char* filename, nc_err_e* ncerr,
int y, int x, ncscale_e style){
ncvisual* ncv = ncvisual_open(filename, ncerr);
if(ncv == nullptr){
return nullptr;
@ -291,7 +296,9 @@ int ncvisual_init(int loglevel){
void ncvisual_destroy(ncvisual* ncv){
if(ncv){
ncv->image->close();
if(ncv->image){
ncv->image->close();
}
if(ncv->ncobj){
ncplane_destroy(ncv->ncp);
}
@ -305,4 +312,9 @@ const char* oiio_version(void){
return OIIO_VERSION_STRING;
}
ncvisual* ncvisual_open_rgba(notcurses* nc, const void* rgba, int rows, int rowstride, int cols){
}
ncvisual* ncvisual_open_bgra(notcurses* nc, const void* bgra, int rows, int rowstride, int cols){
}
#endif

@ -1,5 +1,10 @@
#include "internal.h"
// ncvisual functionality independent of the underlying engine
ncvisual* ncvisual_from_plane(ncplane* n){
return NULL; // FIXME
int dimy, dimx;
ncplane_dim_yx(n, &dimy, &dimx);
ncvisual* ncv = ncvisual_create(1);
return ncv;
}

@ -1,26 +1,26 @@
#include "main.h"
void RotateCW(struct notcurses* nc, struct ncplane* n) {
void RotateCW(struct notcurses* nc, struct ncvisual* n) {
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == ncvisual_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == ncvisual_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == ncvisual_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == ncvisual_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
}
void RotateCCW(struct notcurses* nc, struct ncplane* n) {
void RotateCCW(struct notcurses* nc, struct ncvisual* n) {
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == ncvisual_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == ncvisual_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == ncvisual_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == ncvisual_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
}

@ -27,7 +27,7 @@ TEST_CASE("Multimedia") {
nc_err_e ncerr = NCERR_SUCCESS;
int dimy, dimx;
ncplane_dim_yx(ncp_, &dimy, &dimx);
auto ncv = ncvisual_open_plane(nc_, find_data("changes.jpg"), &ncerr, 0, 0, NCSCALE_STRETCH);
auto ncv = ncvisual_from_file(nc_, find_data("changes.jpg"), &ncerr, 0, 0, NCSCALE_STRETCH);
REQUIRE(ncv);
REQUIRE(NCERR_SUCCESS == ncerr);
ncerr = ncvisual_decode(ncv);
@ -110,7 +110,7 @@ TEST_CASE("Multimedia") {
nc_err_e ncerr = NCERR_SUCCESS;
int dimy, dimx;
ncplane_dim_yx(ncp_, &dimy, &dimx);
auto ncv = ncvisual_open_plane(nc_, find_data("notcursesI.avi"), &ncerr, 0, 0, NCSCALE_STRETCH);
auto ncv = ncvisual_from_file(nc_, find_data("notcursesI.avi"), &ncerr, 0, 0, NCSCALE_STRETCH);
REQUIRE(ncv);
CHECK(NCERR_SUCCESS == ncerr);
ncerr = ncvisual_decode(ncv);

Loading…
Cancel
Save