generalize ncvisual_inflate() to ncvisual_resize_noninterpolative() #1738

This commit is contained in:
nick black 2021-06-08 16:32:03 -04:00
parent 9d47666dfe
commit 6fcaad3c5d
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
8 changed files with 47 additions and 45 deletions

View File

@ -8,6 +8,9 @@ rearrangements of Notcurses.
scaling was not performed without a linked multimedia backend). scaling was not performed without a linked multimedia backend).
* `NCVISUAL_OPTION_BLEND` used with `NCBLIT_PIXEL` will now, when the Kitty * `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. 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) * 2.3.2 (2021-06-03)
* Fixed a bug affecting certain scalings of `ncvisual` objects created from * Fixed a bug affecting certain scalings of `ncvisual` objects created from

View File

@ -3127,9 +3127,9 @@ int ncvisual_rotate(struct ncvisual* n, double rads);
// transformation, unless the size is unchanged. // transformation, unless the size is unchanged.
int ncvisual_resize(struct ncvisual* n, int rows, int cols); 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 // Scale the visual to 'rows' X 'columns' pixels, using non-interpolative
// if 'scale' is less than 1. The original color is retained. // (naive) scaling. No new colors will be introduced as a result.
int ncvisual_inflate(struct ncvisual* n, int scale); int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols);
// Polyfill at the specified location within the ncvisual 'n', using 'rgba'. // 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); int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);

View File

@ -78,7 +78,7 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
**int ncvisual_resize(struct ncvisual* ***n***, int ***rows***, int ***cols***);** **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***);** **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. as if **ncvisual_decode** had never been called.
Once the visual is loaded, it can be transformed using **ncvisual_rotate**, Once the visual is loaded, it can be transformed using **ncvisual_rotate**,
**ncvisual_resize**, and **ncvisual_inflate**. These are persistent operations, **ncvisual_resize**, and **ncvisual_resize_noninterpolative**. These are
unlike any scaling that takes place at render time. If a subtitle is associated persistent operations, unlike any scaling that takes place at render time. If a
with the frame, it can be acquired with **ncvisual_subtitle**. subtitle is associated with the frame, it can be acquired with
**ncvisual_resize** uses the media layer's best scheme to enlarge or shrink the **ncvisual_subtitle**. **ncvisual_resize** uses the media layer's best scheme
original data, typically involving some interpolation. **ncvisual_inflate** to enlarge or shrink the original data, typically involving some interpolation.
maps each pixel to ***scale***x***scale*** pixels square, retaining the **ncvisual_resize_noninterpolative** performs a naive linear sampling,
original color; it is an error if ***scale*** is less than one. retaining only original colors.
**ncvisual_from_rgba** and **ncvisual_from_bgra** both require a number of **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 ***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. result in more effective resolution.
A string can be transformed to a scaling mode with **notcurses_lex_scalemode**, A string can be transformed to a scaling mode with **notcurses_lex_scalemode**,
recognizing **stretch**, **scalehi**, **hires**, **scale**, **inflate**, and recognizing **stretch**, **scalehi**, **hires**, **scale**, and **none**.
**none**. Conversion in the opposite direction is performed with Conversion in the opposite direction is performed with **notcurses_str_scalemode**.
**notcurses_str_scalemode**.
Assuming a cell is twice as tall as it is wide, **NCBLIT_1x1** (and indeed 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 any NxN blitter) will stretch an image by a factor of 2 in the vertical

View File

@ -2530,9 +2530,9 @@ API int ncvisual_rotate(struct ncvisual* n, double rads)
API int ncvisual_resize(struct ncvisual* n, int rows, int cols) API int ncvisual_resize(struct ncvisual* n, int rows, int cols)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Inflate each pixel in the image to 'scale'x'scale' pixels. It is an error // Scale the visual to 'rows' X 'columns' pixels, using non-interpolative
// if 'scale' is less than 1. The original color is retained. // (naive) scaling. No new colors will be introduced as a result.
API int ncvisual_inflate(struct ncvisual* n, int scale) API int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Polyfill at the specified location within the ncvisual 'n', using 'rgba'. // 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); 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 ncpalette palette256;
typedef nccell cell; // FIXME backwards-compat, remove in ABI3 typedef nccell cell; // FIXME backwards-compat, remove in ABI3

View File

@ -1620,6 +1620,7 @@ resize_bitmap(const uint32_t* bmap, int srows, int scols, size_t sstride,
if(dstride < dcols * sizeof(*bmap)){ if(dstride < dcols * sizeof(*bmap)){
return NULL; return NULL;
} }
// FIXME if parameters match current setup, do nothing, and return bmap
size_t size = drows * dstride; size_t size = drows * dstride;
uint32_t* ret = (uint32_t*)malloc(size); uint32_t* ret = (uint32_t*)malloc(size);
if(ret == NULL){ if(ret == NULL){

View File

@ -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){ int ncvisual_resize(ncvisual* nc, int rows, int cols){
if(!visual_implementation){ if(!visual_implementation){
size_t dstride = pad_for_image(cols * 4); return ncvisual_resize_noninterpolative(nc, rows, cols);
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;
} }
if(visual_implementation->visual_resize(nc, rows, cols)){ if(visual_implementation->visual_resize(nc, rows, cols)){
return -1; return -1;
@ -659,6 +648,21 @@ int ncvisual_resize(ncvisual* nc, int rows, int cols){
return 0; 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 // 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). // 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 // 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){ if(scale <= 0){
return -1; return -1;
} }
size_t dstride = pad_for_image(4 * n->pixx * scale); return ncvisual_resize_noninterpolative(n, n->pixy * scale, 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;
} }

View File

@ -272,7 +272,7 @@ TEST_CASE("Bitmaps") {
ncplane_set_base(bigp, "x", 0, white); ncplane_set_base(bigp, "x", 0, white);
CHECK(vopts.n == ncvisual_render(nc_, ncv, &vopts)); CHECK(vopts.n == ncvisual_render(nc_, ncv, &vopts));
CHECK(0 == notcurses_render(nc_)); 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.cellpixy == ncv->pixy);
CHECK(4 * nc_->tcache.cellpixx == ncv->pixx); CHECK(4 * nc_->tcache.cellpixx == ncv->pixx);
vopts.y = 1; vopts.y = 1;
@ -345,7 +345,7 @@ TEST_CASE("Bitmaps") {
vopts.scaling = NCSCALE_SCALE; vopts.scaling = NCSCALE_SCALE;
ncvisual_render(nc_, ncv, &vopts); ncvisual_render(nc_, ncv, &vopts);
CHECK(4 == ncplane_dim_x(vopts.n)); 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.n = nullptr;
vopts.y = 2; vopts.y = 2;
vopts.x = 5; vopts.x = 5;

View File

@ -136,7 +136,7 @@ TEST_CASE("Visual") {
}; };
auto newn = ncvisual_render(nc_, ncv, &vopts); auto newn = ncvisual_render(nc_, ncv, &vopts);
CHECK(0 == notcurses_render(nc_)); 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->pixy);
CHECK(6 == ncv->pixx); CHECK(6 == ncv->pixx);
for(int y = 0 ; y < 3 ; ++y){ 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(0 == ncvisual_blitter_geom(nc_, ncv, &opts, &odimy, &odimx, nullptr, nullptr, nullptr));
CHECK(ncvisual_render(nc_, ncv, &opts)); CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_)); 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(0 == ncvisual_blitter_geom(nc_, ncv, &opts, &ndimy, &ndimx, nullptr, nullptr, nullptr));
CHECK(ndimy == odimy * 2); CHECK(ndimy == odimy * 2);
CHECK(ndimx == odimx * 2); CHECK(ndimx == odimx * 2);