From 6fcaad3c5d6e095f0239d4bdf2a7a46f4bc544b6 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 8 Jun 2021 16:32:03 -0400 Subject: [PATCH] generalize ncvisual_inflate() to ncvisual_resize_noninterpolative() #1738 --- NEWS.md | 3 +++ USAGE.md | 6 ++--- doc/man/man3/notcurses_visual.3.md | 21 ++++++++------- include/notcurses/notcurses.h | 12 ++++++--- src/lib/internal.h | 1 + src/lib/visual.c | 41 +++++++++++++----------------- src/tests/bitmap.cpp | 4 +-- src/tests/visual.cpp | 4 +-- 8 files changed, 47 insertions(+), 45 deletions(-) diff --git a/NEWS.md b/NEWS.md index bf53f13ee..f4a9dd56a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,9 @@ rearrangements of Notcurses. scaling was not performed without a linked multimedia backend). * `NCVISUAL_OPTION_BLEND` used with `NCBLIT_PIXEL` will now, when the Kitty graphics protocol is in use, cut the alpha of each pixel in half. + * `ncvisual_inflate()` has been rewritten as a wrapper around the new + function `ncvisual_resize_noninterpolative()`, and deprecated. It will be + removed for ABI3. Godspeed, `ncvisual_inflate()`; we hardly knew ye. * 2.3.2 (2021-06-03) * Fixed a bug affecting certain scalings of `ncvisual` objects created from diff --git a/USAGE.md b/USAGE.md index 892e4ad74..deeb8fdb3 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3127,9 +3127,9 @@ int ncvisual_rotate(struct ncvisual* n, double rads); // transformation, unless the size is unchanged. int ncvisual_resize(struct ncvisual* n, int rows, int cols); -// Inflate each pixel in the image to 'scale'x'scale' pixels. It is an error -// if 'scale' is less than 1. The original color is retained. -int ncvisual_inflate(struct ncvisual* n, int scale); +// Scale the visual to 'rows' X 'columns' pixels, using non-interpolative +// (naive) scaling. No new colors will be introduced as a result. +int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols); // Polyfill at the specified location within the ncvisual 'n', using 'rgba'. int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba); diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md index bfd1b6eea..fa2951396 100644 --- a/doc/man/man3/notcurses_visual.3.md +++ b/doc/man/man3/notcurses_visual.3.md @@ -78,7 +78,7 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*); **int ncvisual_resize(struct ncvisual* ***n***, int ***rows***, int ***cols***);** -**int ncvisual_inflate(struct ncvisual* ***n***, int ***scale***);** +**int ncvisual_resize_noninterpolative(struct ncvisual* ***n***, int ***rows***, int ***cols***);** **int ncvisual_polyfill_yx(struct ncvisual* ***n***, int ***y***, int ***x***, uint32_t ***rgba***);** @@ -114,13 +114,13 @@ per frame. **ncvisual_decode_loop** will return to the first frame, as if **ncvisual_decode** had never been called. Once the visual is loaded, it can be transformed using **ncvisual_rotate**, -**ncvisual_resize**, and **ncvisual_inflate**. These are persistent operations, -unlike any scaling that takes place at render time. If a subtitle is associated -with the frame, it can be acquired with **ncvisual_subtitle**. -**ncvisual_resize** uses the media layer's best scheme to enlarge or shrink the -original data, typically involving some interpolation. **ncvisual_inflate** -maps each pixel to ***scale***x***scale*** pixels square, retaining the -original color; it is an error if ***scale*** is less than one. +**ncvisual_resize**, and **ncvisual_resize_noninterpolative**. These are +persistent operations, unlike any scaling that takes place at render time. If a +subtitle is associated with the frame, it can be acquired with +**ncvisual_subtitle**. **ncvisual_resize** uses the media layer's best scheme +to enlarge or shrink the original data, typically involving some interpolation. +**ncvisual_resize_noninterpolative** performs a naive linear sampling, +retaining only original colors. **ncvisual_from_rgba** and **ncvisual_from_bgra** both require a number of ***rows***, a number of image columns **cols**, and a virtual row length of @@ -228,9 +228,8 @@ instance **NCSCALE_SCALE_HIRES** and a large image), more rows and columns will result in more effective resolution. A string can be transformed to a scaling mode with **notcurses_lex_scalemode**, -recognizing **stretch**, **scalehi**, **hires**, **scale**, **inflate**, and -**none**. Conversion in the opposite direction is performed with -**notcurses_str_scalemode**. +recognizing **stretch**, **scalehi**, **hires**, **scale**, and **none**. +Conversion in the opposite direction is performed with **notcurses_str_scalemode**. Assuming a cell is twice as tall as it is wide, **NCBLIT_1x1** (and indeed any NxN blitter) will stretch an image by a factor of 2 in the vertical diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 3b043e194..af5f80adb 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2530,9 +2530,9 @@ API int ncvisual_rotate(struct ncvisual* n, double rads) API int ncvisual_resize(struct ncvisual* n, int rows, int cols) __attribute__ ((nonnull (1))); -// Inflate each pixel in the image to 'scale'x'scale' pixels. It is an error -// if 'scale' is less than 1. The original color is retained. -API int ncvisual_inflate(struct ncvisual* n, int scale) +// Scale the visual to 'rows' X 'columns' pixels, using non-interpolative +// (naive) scaling. No new colors will be introduced as a result. +API int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols) __attribute__ ((nonnull (1))); // Polyfill at the specified location within the ncvisual 'n', using 'rgba'. @@ -4269,6 +4269,12 @@ channels_set_bg_default(uint64_t* channels){ return ncchannels_set_bg_default(channels); } +// Inflate each pixel in the image to 'scale'x'scale' pixels. It is an error +// if 'scale' is less than 1. The original color is retained. +// Deprecated; use ncvisual_resize_noninterpolative(), which this now wraps. +API __attribute__ ((deprecated)) int ncvisual_inflate(struct ncvisual* n, int scale) + __attribute__ ((nonnull (1))); + typedef ncpalette palette256; typedef nccell cell; // FIXME backwards-compat, remove in ABI3 diff --git a/src/lib/internal.h b/src/lib/internal.h index 0fa1b11f4..442ba4472 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -1620,6 +1620,7 @@ resize_bitmap(const uint32_t* bmap, int srows, int scols, size_t sstride, if(dstride < dcols * sizeof(*bmap)){ return NULL; } + // FIXME if parameters match current setup, do nothing, and return bmap size_t size = drows * dstride; uint32_t* ret = (uint32_t*)malloc(size); if(ret == NULL){ diff --git a/src/lib/visual.c b/src/lib/visual.c index e9d3efdba..ddf72d339 100644 --- a/src/lib/visual.c +++ b/src/lib/visual.c @@ -640,18 +640,7 @@ ncvisual* ncvisual_from_bgra(const void* bgra, int rows, int rowstride, int cols int ncvisual_resize(ncvisual* nc, int rows, int cols){ if(!visual_implementation){ - size_t dstride = pad_for_image(cols * 4); - uint32_t* r = resize_bitmap(nc->data, nc->pixy, nc->pixx, nc->rowstride, - rows, cols, dstride); - if(r == NULL){ - return -1; - } - ncvisual_set_data(nc, r, true); - nc->rowstride = dstride; - nc->pixy = rows; - nc->pixx = cols; - ncvisual_details_seed(nc); - return 0; + return ncvisual_resize_noninterpolative(nc, rows, cols); } if(visual_implementation->visual_resize(nc, rows, cols)){ return -1; @@ -659,6 +648,21 @@ int ncvisual_resize(ncvisual* nc, int rows, int cols){ return 0; } +int ncvisual_resize_noninterpolative(ncvisual* n, int rows, int cols){ + size_t dstride = pad_for_image(cols * 4); + uint32_t* r = resize_bitmap(n->data, n->pixy, n->pixx, n->rowstride, + rows, cols, dstride); + if(r == NULL){ + return -1; + } + ncvisual_set_data(n, r, true); + n->rowstride = dstride; + n->pixy = rows; + n->pixx = cols; + ncvisual_details_seed(n); + return 0; +} + // by the end, disprows/dispcols refer to the number of source rows/cols (in // pixels), which will be mapped to a region of cells scaled by the encodings). // the blit will begin at placey/placex (in terms of cells). begy/begx define @@ -1119,16 +1123,5 @@ int ncvisual_inflate(ncvisual* n, int scale){ if(scale <= 0){ return -1; } - size_t dstride = pad_for_image(4 * n->pixx * scale); - uint32_t* inflaton = resize_bitmap(n->data, n->pixy, n->pixx, n->rowstride, - n->pixy * scale, n->pixx * scale, dstride); - if(inflaton == NULL){ - return -1; - } - ncvisual_set_data(n, inflaton, true); - n->pixy *= scale; - n->pixx *= scale; - n->rowstride = dstride; - ncvisual_details_seed(n); - return 0; + return ncvisual_resize_noninterpolative(n, n->pixy * scale, n->pixx * scale); } diff --git a/src/tests/bitmap.cpp b/src/tests/bitmap.cpp index e99dd6282..4f61e7b98 100644 --- a/src/tests/bitmap.cpp +++ b/src/tests/bitmap.cpp @@ -272,7 +272,7 @@ TEST_CASE("Bitmaps") { ncplane_set_base(bigp, "x", 0, white); CHECK(vopts.n == ncvisual_render(nc_, ncv, &vopts)); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_inflate(ncv, 4)); + CHECK(0 == ncvisual_resize_noninterpolative(ncv, ncv->pixy * 4, ncv->pixx * 4)); CHECK(4 * nc_->tcache.cellpixy == ncv->pixy); CHECK(4 * nc_->tcache.cellpixx == ncv->pixx); vopts.y = 1; @@ -345,7 +345,7 @@ TEST_CASE("Bitmaps") { vopts.scaling = NCSCALE_SCALE; ncvisual_render(nc_, ncv, &vopts); CHECK(4 == ncplane_dim_x(vopts.n)); - ncvisual_inflate(ncv, 4); + CHECK(0 == ncvisual_resize_noninterpolative(ncv, ncv->pixy * 4, ncv->pixx * 4)); vopts.n = nullptr; vopts.y = 2; vopts.x = 5; diff --git a/src/tests/visual.cpp b/src/tests/visual.cpp index b1b0f3afd..d0a675e27 100644 --- a/src/tests/visual.cpp +++ b/src/tests/visual.cpp @@ -136,7 +136,7 @@ TEST_CASE("Visual") { }; auto newn = ncvisual_render(nc_, ncv, &vopts); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_inflate(ncv, 3)); + CHECK(0 == ncvisual_resize_noninterpolative(ncv, ncv->pixy * 3, ncv->pixx * 3)); CHECK(6 == ncv->pixy); CHECK(6 == ncv->pixx); for(int y = 0 ; y < 3 ; ++y){ @@ -772,7 +772,7 @@ TEST_CASE("Visual") { CHECK(0 == ncvisual_blitter_geom(nc_, ncv, &opts, &odimy, &odimx, nullptr, nullptr, nullptr)); CHECK(ncvisual_render(nc_, ncv, &opts)); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_inflate(ncv, 2)); + CHECK(0 == ncvisual_resize_noninterpolative(ncv, ncv->pixy * 2, ncv->pixx * 2)); CHECK(0 == ncvisual_blitter_geom(nc_, ncv, &opts, &ndimy, &ndimx, nullptr, nullptr, nullptr)); CHECK(ndimy == odimy * 2); CHECK(ndimx == odimx * 2);