尝试使用颜色图绘制垂直线性渐变,但仅使用前9种颜色:为什么?

时间:2019-01-01 14:55:58

标签: java colors bufferedimage

(注意:在此问题的末尾提供了一个最小,完整和可验证的示例)

摘要

  1. 上下文,目标和问题

  2. 我已经尝试过的东西

  3. 相关信息来源

  4. 预期结果,实际结果和问题

  5. 最小,完整和可验证的示例

上下文,目标和问题

我正在尝试对一些像素进行动画处理以在Java中生成火灾动画。每个像素都有颜色,以便绘制从白色到黄色,从黄色到红色以及从红色到黑色的垂直线性渐变。此渐变从画布的底部到顶部。

在执行开始时,除由坐标y = height - 1定义的白线(height是画布的高度)外,所有像素均为黑色。这条白线用于初始化渐变(“ 白色到黄色,黄色到...,等等。”)。

问题是渐变正确开始,但使用第9种颜色时渐变停止。然后只用这种颜色来填充我的渐变,我不知道为什么。

我已经尝试过的东西

我有一个定义渐变的RGB值图。

知道要应用于称为“ A”的像素的颜色的想法是,检索位于其下方的像素的RGB,然后在我的地图的所有RGB中获取该RGB的ID。然后,我在同一张地图中以该ID +1获取RGB,并将其应用于像素A。

所以:

  1. 我检查了返回给定RGB的RGB ID的函数:由于我没有引发任何异常,这似乎还可以

  2. 我检查了我使用的缓冲图像是否正确更新。换句话说:如果一个像素已经被着色的事实确实可以决定上面的像素的颜色:也可以

解释了相关消息来源

绘制渐变的调用方法

该想法是将所有像素设置为黑色,但底线为白色。然后,我在每个画布的像素上进行迭代,并为其下面直接垂直相邻的像素指定颜色。更准确地说,在我的颜色图中,给它指定ID为该相邻像素的颜色的ID + 1的颜色。

    Colors colors = new FireColors(new ArrayList<>());
    gui.colorize(colors.getColorAtIndex(34), -1, -1);  // Setting black anywhere
    gui.colorize(colors.getColorAtIndex(0), -1, height - 1);  // Setting white, in a lower line

    try {
        for(int y = height - 2; y >= 0; y--) {
            for(int x = 0; x < width; x++) {
                int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
                int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
                int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
                gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
            }
        }
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }

我如何为像素着色

我只是遍历画布。

void colorize(Color color, int x_parameter, int y_parameter) {
    for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
        for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
            buffered_image.setRGB(x, y, color.getRGB());
        }
    }
    panel.repaint();
}

如何在颜色列表中找到像素颜色的索引?

int getIndexOfColor(int rgb) throws Exception {
    for (int x = 0; x < colors.size(); x++) {
        if(colors.get(x).getRGB() == rgb) {
            return x;
        }
    }
    throw new Exception("Color not found in the list!");
}

预期结果,实际结果和问题

我希望有几个垂直渐变(每个从下到上)。 “几个”是因为画布的高度大于渐变颜色的数量,并且因为我使用模数来选择要应用的颜色。

实际结果是:我得到了一个从白色到黄色的渐变,只有9种颜色,仅此而已。没有橙色,没有红色,没有黑色。实际上:https://imgur.com/oQFJ52k

我的问题是:由于检索了良好的ID,并且为给定像素选择了良好的邻居,为什么我的渐变色被阻止为第9种颜色?换句话说:为什么从一刻开始就没有选择好的颜色?

最小,完整和可验证的示例

Launcher.java

import java.util.ArrayList;

public class Launcher {

    public static void main(String args[]) {
        int width = 150, height = 150;
        Gui gui = new Gui(width, height);
        gui.setUp("DOOM-like fire");
        gui.setVisible(true);

        Colors colors = new FireColors(new ArrayList<>());
        gui.colorize(colors.getColorAtIndex(34), -1, -1);  // Setting black anywhere
        gui.colorize(colors.getColorAtIndex(0), -1, height - 1);  // Setting white, in a lower line

        try {
            for(int y = height - 2; y >= 0; y--) {
                for(int x = 0; x < width; x++) {
                    int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
                    int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
                    int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
                    gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
                }
            }
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }

}

Gui.java

import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;

class Gui extends JFrame {

    private JPanel panel;
    private BufferedImage buffered_image;

    Gui(int width, int height) {
        buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        panel = new JPanel() {
            public void paintComponent(Graphics graphics) {
                super.paintComponent(graphics);
                graphics.drawImage(buffered_image, 0, 0, null);
            }
        };
    }

    void setUp(String title) {
        setTitle(title);
        setLayout(null);
        setSize(buffered_image.getWidth(), buffered_image.getHeight());
        setContentPane(panel);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    void colorize(Color color, int x_parameter, int y_parameter) {
        for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
            for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
                buffered_image.setRGB(x, y, color.getRGB());
            }
        }
        panel.repaint();
    }

    int getRGBAtCoordinates(int x, int y) {
        return buffered_image.getRGB(x, y);
    }

}

Colors.java

import java.awt.Color;
import java.util.List;

abstract class Colors {
    List<Color> colors;

    Color getColorAtIndex(int index) {
        return colors.get(index);
    }

    int getIndexOfColor(int rgb) throws Exception {
        for (int x = 0; x < colors.size(); x++) {
            if(colors.get(x).getRGB() == rgb) {
                return x;
            }
        }
        throw new Exception("Color not found in the list!");
    }

    int getSize() {
        return colors.size();
    }
}

FireColors.java

import java.awt.Color;
import java.util.List;

class FireColors extends Colors {

    FireColors(List<Color> colors) {

        this.colors = colors;

        this.colors.add(new Color(255, 255, 255));
        this.colors.add(new Color(239, 239, 199));
        this.colors.add(new Color(223, 223, 159));
        this.colors.add(new Color(207, 207, 111));
        this.colors.add(new Color(183, 183, 55));
        this.colors.add(new Color(183, 183, 47));
        this.colors.add(new Color(183, 175, 47));
        this.colors.add(new Color(191, 175, 47));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(199, 151, 31));
        this.colors.add(new Color(199, 143, 23));
        this.colors.add(new Color(199, 135, 23));
        this.colors.add(new Color(207, 135, 23));
        this.colors.add(new Color(207, 127, 15));
        this.colors.add(new Color(207, 119, 15));
        this.colors.add(new Color(207, 111, 15));
        this.colors.add(new Color(215, 103, 15));
        this.colors.add(new Color(215, 95, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 79, 7));
        this.colors.add(new Color(199, 71, 7));
        this.colors.add(new Color(191, 71, 7));
        this.colors.add(new Color(175, 63, 7));
        this.colors.add(new Color(159, 47, 7));
        this.colors.add(new Color(143, 39, 7));
        this.colors.add(new Color(119, 31, 7));
        this.colors.add(new Color(103, 31, 7));
        this.colors.add(new Color(87, 23, 7));
        this.colors.add(new Color(71, 15, 7));
        this.colors.add(new Color(47, 15, 7));
        this.colors.add(new Color(7, 7, 7));

    }

}

1 个答案:

答案 0 :(得分:2)

您的问题是FireColors包含重复的颜色:

// FireColors, lines 20 and 21:
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 167, 39));
// more duplicate colors found later on!

问题与您的颜色选择算法有关:

// Launcher lines 20 to 22:
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();

对于第8行,它从其下面的行中读取颜色,找到其索引(7),将其加一并为与颜色#8对齐的颜色。

对于第9行,它从其下面的行中读取颜色,找到其索引(8),将其加一,并用与颜色#9(与颜色#8相同)对齐的颜色

对于第10行,它从其下一行读取颜色,找到其索引(8,因为getIndexOfColor()返回找到的第一个索引,即8,而不是9!),然后添加一个颜色与颜色#9(与颜色#8相同)

要解决此问题,您应该重新设计颜色选择算法或使FireColor颜色唯一。