如何使用RGB坐标创建颜色渐变?

huangapple go评论65阅读模式
英文:

How to make a color gradient using RGB coordinates?

问题

我试图打印一个颜色渐变。运行时,没有显示任何内容,但当我用鼠标光标选择整个窗口区域时,颜色出现了,但没有颜色渐变。

  • 函数 smooth 获取颜色和尺寸信息并启动了 ncurses 环境。
  • 颜色使用 init_color 函数定义,并使用 init_pair 组合成一对一对的自定义颜色对。
  • 使用 mvaddch 函数在屏幕上放置一个空字符(' ')以显示像素,放置在适当的位置上。每一列被分成三等分,每一部分都用不同的颜色对显示。

以下是代码部分:

#include <ncurses.h>

struct Color {
    int red, green, blue;
};

void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
    initscr();
    start_color();
    cbreak();
    noecho();
    curs_set(0);

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            int r, g, b;
            r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
            g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
            b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);

            init_color(COLOR_BLACK, 0, 0, 0);
            init_color(COLOR_RED, r * 1000 / 255, 0, 0);
            init_color(COLOR_GREEN, 0, g * 1000 / 255, 0);
            init_color(COLOR_BLUE, 0, 0, b * 1000 / 255);
            init_pair(1, COLOR_RED, COLOR_BLACK);
            init_pair(2, COLOR_GREEN, COLOR_BLACK);
            init_pair(3, COLOR_BLUE, COLOR_BLACK);

            attron(COLOR_PAIR(1));
            mvaddch(i, j, ' ');
            attroff(COLOR_PAIR(1));

            attron(COLOR_PAIR(2));
            mvaddch(i, j + cols, ' ');
            attroff(COLOR_PAIR(2));

            attron(COLOR_PAIR(3));
            mvaddch(i, j + 2 * cols, ' ');
            attroff(COLOR_PAIR(3));
        }
    }

    refresh();
    getch();

    endwin();
}

int main() {
    int y, x;
    struct Color left, right;
    printf("Enter the RGB values for the left color: ");
    scanf("%d %d %d", &left.red, &left.green, &left.blue);
    printf("Enter the RGB values for the right color: ");
    scanf("%d %d %d", &right.red, &right.green, &right.blue);
    printf("Height: ");
    scanf("%d", &y);
    printf("Width: ");
    scanf("%d", &x);

    smooth(y, x, left, right);

    return 0;
}
英文:

I'm trying to print a color gradient. When running, nothing is displayed, but when I select the entire window area with the mouse cursor, the colors appear but not a color gradient.

如何使用RGB坐标创建颜色渐变?

  • Function smooth takes the color and dimension information and starts the ncurses environment.

  • Colors are defined using the init_color function for and combined in pairs using init_pair to create custom color pairs.

  • Pixels are displayed using the mvaddch functions to place an empty character (' ') on the screen in the appropriate positions. Each column is divided into three equal parts, and each part is displayed with a different pair of colors.

The code:

#include &lt;ncurses.h&gt;
struct Color {
int red, green, blue;
};
void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
for (int i = 0; i &lt; rows; i++) {
for (int j = 0; j &lt; cols; j++) {
int r, g, b;
r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);
init_color(COLOR_BLACK, 0, 0, 0);
init_color(COLOR_RED, r * 1000 / 255, 0, 0);
init_color(COLOR_GREEN, 0, g * 1000 / 255, 0);
init_color(COLOR_BLUE, 0, 0, b * 1000 / 255);
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLUE, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvaddch(i, j, &#39; &#39;);
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2));
mvaddch(i, j + cols, &#39; &#39;);
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
mvaddch(i, j + 2 * cols, &#39; &#39;);
attroff(COLOR_PAIR(3));
}
}
refresh();
getch();
endwin();
}
int main() {
int y, x;
struct Color left, right;
printf(&quot;Enter the RGB values for the left color: &quot;);
scanf(&quot;%d %d %d&quot;, &amp;left.red, &amp;left.green, &amp;left.blue);
printf(&quot;Enter the RGB values for the right color: &quot;);
scanf(&quot;%d %d %d&quot;, &amp;right.red, &amp;right.green, &amp;right.blue);
printf(&quot;Height: &quot;);
scanf(&quot;%d&quot;, &amp;y);
printf(&quot;Width: &quot;);
scanf(&quot;%d&quot;, &amp;x);
smooth(y, x, left, right);
return 0;
}

答案1

得分: 3

  1. 你颠倒了前景色和背景色。
    你使用了黑色背景和一个可变的前景色(嗯,并不是真正可变的,稍后会看到)。
    因此,由于你打印了一个空格,前景色是无用的。只有背景色起作用,而它是黑色。所以你看到了一个黑屏。

  2. 除非你使用鼠标选择了一些部分。在这种情况下,通常的行为是恢复前景色和背景色。所以在那里,你看到了你期望看到的东西。

  3. 一旦这个问题得到纠正,你应该得到这三种纯色作为结果。
    不是你期望的。但原因是另一个:你不能重用颜色和对。它们应该是唯一的。即使终端(现在大多数终端都是这样)有能力打印几乎无限数量的颜色,但是 curses 仍然需要在刷新时使用颜色索引(自己看看:尝试在循环中更新颜色,在绘制后 - 每次都做一些刷新 - 你会看到你已经打印的内容会更改颜色。颜色调色板不仅影响未来的打印,还影响过去的打印。
    因此,对于每个你使用的颜色,你需要一个不同的颜色编号和不同的对编号。不只是1、2、3这样循环使用。

  4. 此外,请不要重新定义 COLOR_BLACKCOLOR_RED 等。它们已经被定义了。

  5. 也不要使用预定义的颜色,除非你想搞乱你的终端(所以,在16以下不要使用颜色)。

总之,

#include <ncurses.h>
#include <unistd.h>

struct Color {
    int red, green, blue;
};

void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
    initscr();
    start_color();
    cbreak();
    noecho();
    curs_set(0);

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            int r, g, b;
            r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
            g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
            b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);

            // 我使用 j+16 的颜色索引,所以是唯一的,不会被后续更新
            // 我避免使用前16个,因为我喜欢我的默认终端颜色
            init_color(j+16, r*1000/255, 0, 0);
            init_pair(j+16, COLOR_BLACK, j+16); // 对于对也是一样的`
            // 对于绿色也是一样的
            init_color(j+16+cols, 0, g*1000/255, 0);
            init_pair(j+16+cols, COLOR_BLACK, j+16+cols);
            // 对于蓝色也是一样的
            init_color(j+16+2*cols, 0, 0, b*1000/255);
            init_pair(j+16+2*cols, COLOR_BLACK, j+16+2*cols);
            // 对于所有颜色都是一样的,因为我觉得你的红/绿/蓝渐变很奇怪,我怀疑这第四个才是你想要的
            init_color(j+16+3*cols, r*1000/255, g*1000/255, b*1000/255);
            init_pair(j+16+3*cols, COLOR_BLACK, j+16+3*cols);

            attron(COLOR_PAIR(16+j));
            mvaddch(i, j, 'r'); // 为了确保不被空格欺骗,我打印了一些东西
            attroff(COLOR_PAIR(16+j));

            attron(COLOR_PAIR(j+16+cols));
            mvaddch(i, j + cols, 'g');
            attroff(COLOR_PAIR(j+16+cols));

            attron(COLOR_PAIR(j+16+2*cols));
            mvaddch(i, j + 2 * cols, 'b');
            attroff(COLOR_PAIR(j+16+2*cols));

            attron(COLOR_PAIR(j+16+3*cols));
            mvaddch(i, j + 3 * cols, 'X');
            attroff(COLOR_PAIR(j+16+3*cols));
        }
    }

    refresh();
    getch();
    // 为了说明“不要重新使用颜色”的观点,这里展示了当你尝试重新使用它们时会发生什么
    for(int i=0; ;i++){
        for(int j=0; j<cols; j++){
            init_color((j+i)%cols+16, j*1000/cols, 0, 0);
            init_color((j+i)%cols+16+cols, 0, j*1000/cols, 0);
            init_color((j+i)%cols+16+2*cols, 0, 0, j*1000/cols);
            init_color((j+i)%cols+16+3*cols, j*1000/cols, j*1000/cols, j*1000/cols);
        }
        refresh();
        usleep(100000);
    }

    endwin();
}

int main() {
    int y, x;
    struct Color left, right;
    // 因为我更喜欢最小的可重现示例,我硬编码了这些值(仅适用于 SO)
    // 人们不一定知道如何填写这些值(在0到255之间?在0到1之间?)
    // 此外,交互式程序浪费了人们的时间。只需打印一些东西,并解释你期望的结果
   

<details>
<summary>英文:</summary>

1. You inverted foreground and background.
You use a black background and a variable foreground color (well, not so variable, see later). 
So, since you print a space, foreground color is useless. And only background is taken into account. Which is black. So you have a black screen

2. Unless you select some part with the mouse. In which case, usual behaviour is to revert foreground and background. So there, you see what you expected to see.

3. Once that corrected, you should get those 3 plain colors as result.
Not what you expected. But that is for another reason: you can&#39;t recycle colors and pairs. They are supposed to be unique. And even if the terminal (which nowadays is the case of most terminal) has the ability to print a almost infinite number of colors, well, curses anyway needs that color index when you refresh (see for yourself: try to update colors in a loop, after the draw - and doing some refresh each times - you&#39;ll see that what you have already printed change colors. Color palette does not impact only future prints, but also past ones.
So, you need a different color number and a different pair number for each color you use. Not just 1,2,3 recycled

4. Also, don&#39;t redefine `COLOR_BLACK`, `COLOR_RED`, etc. They are already defined.

5. And don&#39;t use the predefined color, unless you want to mess up your terminal (so, no color under 16)


All together, 
```c
#include &lt;ncurses.h&gt;
#include &lt;unistd.h&gt;

struct Color {
    int red, green, blue;
};

void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
    initscr();
    start_color();
    cbreak();
    noecho();
    curs_set(0);

    for (int i = 0; i &lt; rows; i++) {
        for (int j = 0; j &lt; cols; j++) {
            int r, g, b;
            r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
            g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
            b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);

            // I use j+16 color index, so a unique one, that won&#39;t be update afterward
            // I avoid using 16 first ones, because I like my default terminal colors
            init_color(j+16, r*1000/255, 0, 0);
            init_pair(j+16, COLOR_BLACK, j+16); // likewise for pairs`
            // Likewise for green
            init_color(j+16+cols, 0, g*1000/255, 0);
            init_pair(j+16+cols, COLOR_BLACK, j+16+cols);
            // Likewise for blue
            init_color(j+16+2*cols, 0, 0, b*1000/255);
            init_pair(j+16+2*cols, COLOR_BLACK, j+16+2*cols);
            // And likewise for all together, since I find quite strange your 3 red/green/blue 
            // gradient, and suspect that this 4th one is the one you wanted
            init_color(j+16+3*cols, r*1000/255, g*1000/255, b*1000/255);
            init_pair(j+16+3*cols, COLOR_BLACK, j+16+3*cols);

            attron(COLOR_PAIR(16+j));
            mvaddch(i, j, &#39;r&#39;); // Just to be sure, and don&#39;t get fooled by space, I print something
            attroff(COLOR_PAIR(16+j));

            attron(COLOR_PAIR(j+16+cols));
            mvaddch(i, j + cols, &#39;g&#39;);
            attroff(COLOR_PAIR(j+16+cols));

            attron(COLOR_PAIR(j+16+2*cols));
            mvaddch(i, j + 2 * cols, &#39;b&#39;);
            attroff(COLOR_PAIR(j+16+2*cols));

            attron(COLOR_PAIR(j+16+3*cols));
            mvaddch(i, j + 3 * cols, &#39;X&#39;);
            attroff(COLOR_PAIR(j+16+3*cols));
        }
    }

    refresh();
    getch();
    // To make my point about &quot;don&#39;t reuse color&quot;, here what happens we you do anyway
    for(int i=0; ;i++){
        for(int j=0; j&lt;cols; j++){
            init_color((j+i)%cols+16, j*1000/cols, 0, 0);
            init_color((j+i)%cols+16+cols, 0, j*1000/cols, 0);
            init_color((j+i)%cols+16+2*cols, 0, 0, j*1000/cols);
            init_color((j+i)%cols+16+3*cols, j*1000/cols, j*1000/cols, j*1000/cols);
        }
        refresh();
        usleep(100000);
    }

    endwin();
}

int main() {
    int y, x;
    struct Color left, right;
    // Because I prefer minimal reproducible example, I hard code values (for SO only obviously)
    // People don&#39;t necessarily know what to fill these values (between 0 and 255? 0 and 1?) with
    // Besides, interactive program are wasting people time. Just print something, and explain
    // what you expected
    left.red=255; left.green=0; left.blue=0;
    right.red=0; right.green=255; right.blue=0;
    y=25;
    x=20;

    smooth(y, x, left, right);

    return 0;
}

See the animation at the end: I haven't reprinted anything. Just changed the color (not even the pairs). And int changes the whole terminal colors.
So, this is what happens when you init_color(1,...): it updates everything on the screen that will and that has been printed with color 1.

huangapple
  • 本文由 发表于 2023年7月11日 02:53:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76656552.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定