I've got a method that sets the text and images tints of a parent to some color. Now if the background of the parent and the foreground (the tint I'm settings) are close in contrast the text won't be readable.
How can I check for the difference between those 2 colors and change one (make it lighter or darker) up to a point where they become readable?
Here's what I've got till now:
public static void invokeContrastSafety(ViewGroup parent, int tint, boolean shouldPreserveForeground) {
Drawable background = parent.getBackground();
if (background instanceof ColorDrawable) {
if (isColorDark(((ColorDrawable) background).getColor())) {
// Parent background is dark
if (isColorDark(tint)) {
// Tint (foreground) color is also dark.
if (shouldPreserveForeground) {
// We can't modify tint color, changing background to make things readable.
} else {
// Altering foreground to make things readable
}
invokeInternal(parent, tint);
} else {
// Everything is readable. Just pass it on.
invokeInternal(parent, tint);
}
} else {
// Parent background is light
if (!isColorDark(tint)) {
if (shouldPreserveForeground) {
} else {
}
} else {
invokeInternal(parent, tint);
}
}
}
}
private static boolean isColorDark(int color){
double darkness = 1-(0.299* Color.red(color) + 0.587*Color.green(color) + 0.114*Color.blue(color))/255;
return darkness >= 0.2;
}
Try this one it works for me. This function returns that the color is dark or light.
public static boolean isBrightColor(int color) {
if (android.R.color.transparent == color)
return true;
boolean rtnValue = false;
int[] rgb = { Color.red(color), Color.green(color), Color.blue(color) };
int brightness = (int) Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1]
* rgb[1] * .691 + rgb[2] * rgb[2] * .068);
// Color is Light
if (brightness >= 200) {
rtnValue = true;
}
return rtnValue;
}
You can change your custom logic in this function if you need.
Related
Hi I would like to write a program that can tell me the color of a pixel base on the RGB values. Currently I am using the following code to read pixels from a buffered image. However, this program can only identify 7 colors and is very inaccurate. If possible, I want the program to be able to identify whether the color is light or dark. ie. "light red" "dark red"
Public static void main(String args[]){
boolean isRed=false;
boolean isGreen=false;
boolean isBlue=false;
String color="";
//read color from a color array
blue = color[i][j].getBlue();
red = color[i][j].getRed();
green = color[i][j].getGreen();
if(blue>(255-blue)) {
isBlue=true;
}
if(red>(255-red)) {
isRed=true;
}
if(green>(255-green)) {
isGreen=true;
}
if(isRed==false&&isGreen==false&&isBlue==false) {
color="black";
}else if(isRed==true&&isGreen==true&&isBlue==true) {
color="white";
}else if(isRed==true&&isGreen==false&&isBlue==false) {
color="red";
}else if(isRed==false&&isGreen==true&&isBlue==false) {
color="green";
}else if(isRed==false&&isGreen==false&&isBlue==true) {
color="blue";
}else if(isRed==true&&isGreen==true&&isBlue==false) {
color="yellow";
}else if(isRed==false&&isGreen==true&&isBlue==true) {
color="cyan";
}else if(isRed==true&&isGreen==false&&isBlue==true) {
color="magenta";
}
System.out.println(color);
}
I want an RGB value when the colour name is given as input. The following code is working for some colors (I guess for primary colors like red) and failing for some others (like cyan and mauve):
import java.awt.Color;
import javax.swing.text.html.StyleSheet;
public class ColourTest {
public static void main(String[] args) {
StyleSheet s = new StyleSheet();
String colourName = "RED";
Color clr = s.stringToColor(colourName);
int r = clr.getRed();
int g = clr.getGreen();
int b = clr.getBlue();
System.out.println("red:" + r + " green :" + g + " blue:" + b);
}
}
Is there another way to get the RGB values for the color names?
Here's what I have found in the javax.swing.text.html.CSS class:
/**
* Convert a color string such as "RED" or "#NNNNNN" or "rgb(r, g, b)"
* to a Color.
*/
static Color stringToColor(String str) {
Color color;
if (str == null) {
return null;
}
if (str.length() == 0)
color = Color.black;
else if (str.startsWith("rgb(")) {
color = parseRGB(str);
}
else if (str.charAt(0) == '#')
color = hexToColor(str);
else if (str.equalsIgnoreCase("Black"))
color = hexToColor("#000000");
else if(str.equalsIgnoreCase("Silver"))
color = hexToColor("#C0C0C0");
else if(str.equalsIgnoreCase("Gray"))
color = hexToColor("#808080");
else if(str.equalsIgnoreCase("White"))
color = hexToColor("#FFFFFF");
else if(str.equalsIgnoreCase("Maroon"))
color = hexToColor("#800000");
else if(str.equalsIgnoreCase("Red"))
color = hexToColor("#FF0000");
else if(str.equalsIgnoreCase("Purple"))
color = hexToColor("#800080");
else if(str.equalsIgnoreCase("Fuchsia"))
color = hexToColor("#FF00FF");
else if(str.equalsIgnoreCase("Green"))
color = hexToColor("#008000");
else if(str.equalsIgnoreCase("Lime"))
color = hexToColor("#00FF00");
else if(str.equalsIgnoreCase("Olive"))
color = hexToColor("#808000");
else if(str.equalsIgnoreCase("Yellow"))
color = hexToColor("#FFFF00");
else if(str.equalsIgnoreCase("Navy"))
color = hexToColor("#000080");
else if(str.equalsIgnoreCase("Blue"))
color = hexToColor("#0000FF");
else if(str.equalsIgnoreCase("Teal"))
color = hexToColor("#008080");
else if(str.equalsIgnoreCase("Aqua"))
color = hexToColor("#00FFFF");
else if(str.equalsIgnoreCase("Orange"))
color = hexToColor("#FF8000");
else
color = hexToColor(str); // sometimes get specified without leading #
return color;
}
Thus if you are passing any color which is not present in the code above, you will unfortunately get a NullPointerException
However, I have found a hack to solve your problem. Use this code:
public static void main(String[] args) {
StyleSheet s = new StyleSheet();
String colourName = "Cyan";
Color clr = stringToColorCustom(colourName);
int r = clr.getRed();
int g = clr.getGreen();
int b = clr.getBlue();
System.out.println("red:" + r + " green :" + g + " blue:" + b);
}
static Color stringToColorCustom(String str) {
Color color;
if (str == null) {
return null;
}
if (str.length() == 0)
color = Color.black;
else if (str.charAt(0) == '#')
color = hexToColor(str);
else if (str.equalsIgnoreCase("Black"))
color = hexToColor("#000000");
else if (str.equalsIgnoreCase("Silver"))
color = hexToColor("#C0C0C0");
else if (str.equalsIgnoreCase("Gray"))
color = hexToColor("#808080");
else if (str.equalsIgnoreCase("White"))
color = hexToColor("#FFFFFF");
else if (str.equalsIgnoreCase("Maroon"))
color = hexToColor("#800000");
else if (str.equalsIgnoreCase("Red"))
color = hexToColor("#FF0000");
else if (str.equalsIgnoreCase("Purple"))
color = hexToColor("#800080");
else if (str.equalsIgnoreCase("Fuchsia"))
color = hexToColor("#FF00FF");
else if (str.equalsIgnoreCase("Green"))
color = hexToColor("#008000");
else if (str.equalsIgnoreCase("Lime"))
color = hexToColor("#00FF00");
else if (str.equalsIgnoreCase("Olive"))
color = hexToColor("#808000");
else if (str.equalsIgnoreCase("Yellow"))
color = hexToColor("#FFFF00");
else if (str.equalsIgnoreCase("Navy"))
color = hexToColor("#000080");
else if (str.equalsIgnoreCase("Blue"))
color = hexToColor("#0000FF");
else if (str.equalsIgnoreCase("Teal"))
color = hexToColor("#008080");
else if (str.equalsIgnoreCase("Aqua"))
color = hexToColor("#00FFFF");
else if (str.equalsIgnoreCase("Orange"))
color = hexToColor("#FF8000");
else if (str.equalsIgnoreCase("Cyan")) // Add your color
color = hexToColor("#00FFFF"); // Add the RGB
else
color = hexToColor(str); // Sometimes get specified
// without a leading #
return color;
}
static final Color hexToColor(String value) {
String digits;
int n = value.length();
if (value.startsWith("#")) {
digits = value.substring(1, Math.min(value.length(), 7));
}
else {
digits = value;
}
String hstr = "0x" + digits;
Color c;
try {
c = Color.decode(hstr);
}
catch (NumberFormatException nfe) {
c = null;
}
return c;
}
In the above code I have created a custom stringToColorCustom method, and now I can add whatever colors I want in that method.
I suggest to use the kind of a translation table via HashMap:
HashMap<NamedColor, RgbColor> table = new HashMap<>();
table.put(new NamedColor("red"), new RgbColor("#ff0000"));
table.put(new NamedColor("blue"), new RgbColor("#0000ff"));
How the conversion works:
class ColorConverter {
// If you need reverse color conversion you can use handy bidirectoinal
// maps from http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/bidimap/DualHashBidiMap.html
private HashMap<Color, RgbColor> table;
public static RgbColor convert(NamedColor color) {
return table.get(color);
}
Adjust this outline to your needs.
Easiest in javafx:
import javafx.scene.paint.Color;
Color color = Color.web("orange");
System.out.printf("Color: %s, RGBA #%x%n", color, color.hashCode());
For java.awt.Color one can use (slow) reflection on all those constants define there:
private static Optional<java.awt.Color> color(String name) {
try {
Field field = java.awt.Color.class.getDeclaredField(name.toUpperCase());
int modifiers = field.getModifiers();
if (field.getType() == java.awt.Color.class && Modifier.isStatic(modifiers
&& Modifier.isPublic(modifiers))) {
return Optional.of((java.awt.Color)field.get(null));
}
} catch (NoSuchFieldException e) {
}
return Optional.empty();
}
Here there are some problems with names using underscore (which were removed in javafx).
System.out.println("RGBA " + color("orange")
.map(c -> String.format("#%x", c.getRGB()))
.orElse("(unknown)"));
Because of CSS support in java's HTML with color names, there should exist an other solution, but I have never sought.
I am practicing Objects & Constructors and ended up making this code, however when I run it, the String colorGenerated comes up as null, thus appearing as "The Color Generated was: null". I have tried to change and fix it but failed to do so. Thank you for reading.
public class Color{
int colorValue;
String colorGenerated1;
public Color(String colorGenerated){
System.out.println("The Color Generated was: " + colorGenerated);
}
public void randomizeColor(){
Random randomColor= new Random();
colorValue = randomColor.nextInt(3);
}
public int getColor(){
if(colorValue == 1){
colorGenerated1 = "Red";
} else if(colorValue == 2){
colorGenerated1 = "Blue";
} else if(colorValue == 3){
colorGenerated1 = "Yellow";
}
return colorValue;
}
public static void main(String[] args){
Color color = new Color("colorGenerated");
color.randomizeColor();
color.getColor();
}
}
You are printing the color generated before you set it with randomize color. And you should only get your Random once (instead of once per method invocation). I would do something like
public class Color {
private static Random random = new Random();
int colorValue = random.nextInt(3) + 1; // nextInt excludes 3 and includes 0
#Override
public String toString() {
if (colorValue == 1) {
return "Red";
} else if (colorValue == 2) {
return "Blue";
} else if (colorValue == 3) {
return "Yellow";
}
return "Unknown";
}
public static void main(String[] args) {
Color color = new Color();
System.out.println("The Color Generated was: " + color);
}
}
First you make an instance of the class Color. Actually you run the constructor. The parameter is a string. That is showing up.
After that you initialize colorgenerated. You must after color.getColor() show the colorgenerated, Because then it's actually initialized.
Please have a read . Your code is working fine as expected .
You added print statement in your constructor & you initializing an object very first .
Then you added code for randomize the color & there is no method for print the color .
So , you will get only null when you call the constructor .
Hi every one i am having a bit of trouble with my java game, it is very simply made as i am new to java. and the game works fine well as good as i can achieve. But i am stuck on how i can change the images in real time. I am trying to figure out how to make my Monsters face me "the hero frylark" when they chase me. i have made 2 simple methods in my monster class. left and right How could i apply these methods to make the image change from image = getImage("/Game/images/police-right.png"); to image = getImage("/Game/images/police-left.png");.
Oh and in my project library is golden_0_2_3.jar which contains some game engine stuff.
Please.
Many thanks from edwin.
import com.golden.gamedev.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.awt.event.KeyEvent;
public class MyGame extends Game {
// set the values
public Random random;
private Hero frylark;
private Monster[] monsters = new Monster[3];
private Token coin;
private GameBackGround grass;
private BufferedImage image;
public void initResources() {
// set a new random number
random = new Random();
// get the background image.
image = getImage("/Game/images/background.png");
// set the name "grass" to background and given the image from the image set above.
grass = new GameBackGround("grass", image);
// get the monsters image.
image = getImage("/Game/images/police.png");
// give the monsters their names "" and set them their image from the image set above.
monsters[0] = new Monster("Monster", image);
monsters[1] = new Monster("Monster2", image);
monsters[2] = new Monster("Monster3", image);
// get the tokens image.
image = getImage("/Game/images/donut.png");
// set the name "coin" for the token, then its x and y position, and set the image from the image set above.
coin = new Token("coin", 400, 300, image);
// get the heros image.
image = getImage("/Game/images/snake.png");
// set the name "frylark" for the hero, then his score "0" and lives "5".
frylark = new Hero("Frylark", 0, 5);
//set the monsters random x and y positions.
monsters[0].setX(random.nextInt(750));
monsters[0].setY(random.nextInt(550));
monsters[1].setX(random.nextInt(750));
monsters[1].setY(random.nextInt(550));
monsters[2].setX(random.nextInt(750));
monsters[2].setY(random.nextInt(550));
}
// update method
public void update(long elapsedTime) {
// Pause the hero "frylark" on hold of the space bar.
if (!keyDown(KeyEvent.VK_SPACE)){
// if dead stop frylark moving on the 5 second game over sequence, being displays details and playing the game over sound.
if (Hero.dead(frylark)){
if(keyDown(KeyEvent.VK_LEFT))
{
// Move left
frylark.moveLeft();
}
if (keyDown(KeyEvent.VK_RIGHT))
{
// Move right
frylark.moveRight();
}
if (keyDown(KeyEvent.VK_UP))
{
// Move up on press of up key
frylark.moveUp();
}
if (keyDown(KeyEvent.VK_DOWN))
{
// Move down on press of down key
frylark.moveDown();
}
}
if (keyDown(KeyEvent.VK_ESCAPE))
{
// Exit game on press of esc key.
System.exit(0);
}
}
if (!keyDown(KeyEvent.VK_SPACE))
{
// Pause the monsters on hold of the space bar
monsters[0].chase(frylark);
monsters[1].chase(frylark);
monsters[2].chase(frylark);
}
// if monster 0 has eaten frylark move to a random position and lose a life, plus play the lose life sound.
if (monsters[0].eaten(frylark)) {
monsters[0].setX(random.nextInt(750));
monsters[0].setY(random.nextInt(550));
frylark.loseLife();
playSound("/Game/sounds/lost_a_life.wav");
}
// if monster 1 has eaten frylark move to a random position and lose a life, plus play the lose life sound.
if (monsters[1].eaten(frylark)) {
monsters[1].setX(random.nextInt(750));
monsters[1].setY(random.nextInt(550));
frylark.loseLife();
playSound("/Game/sounds/lost_a_life.wav");
}
// if monster 2 has eaten frylark move to a random position and lose a life, plus play the lose life sound.
if (monsters[2].eaten(frylark)) {
monsters[2].setX(random.nextInt(750));
monsters[2].setY(random.nextInt(550));
frylark.loseLife();
playSound("/Game/sounds/lost_a_life.wav");
}
// if coin is collected increase score and move to a random position, and play the coin collect sound.
if (coin.collected(frylark)) {
coin.setX (random.nextInt(750));
coin.setY (random.nextInt(550));
frylark.increaseScore();
playSound("/Game/sounds/coin.wav");
}
}
public void render(Graphics2D g) {
// draw all the monsters, hero, and coin and background.
g.drawImage(grass.getImage(),grass.getX(),grass.getY(),null);
g.drawImage(monsters[0].getImage(), monsters[0].GetX(), monsters[0].GetY(), null);
g.drawImage(monsters[1].getImage(), monsters[1].GetX(), monsters[1].GetY(), null);
g.drawImage(monsters[2].getImage(), monsters[2].GetX(), monsters[2].GetY(), null);
g.drawImage(image,frylark.getX(),frylark.getY(),null);
g.drawImage(coin.getImage(),coin.getX(),coin.getY(),null);
// if monster 0 overlaps another monster mover him back
if (monsters[0].overlap(monsters)){
monsters[0].x -=20;
monsters[0].y -=70;
}
// if monster 1 overlaps another monster mover him back
if (monsters[1].overlap(monsters)){
monsters[1].x -=21;
monsters[1].y -=70;
}
// if monster 2 overlaps another monster mover him back
if (monsters[2].overlap(monsters)){
monsters[2].x -=22;
monsters[2].y -=70;
}
// draw the lives bar, and set the font colour and size
g.setColor(Color.RED);
g.setFont(new Font("default", Font.BOLD, 18));
for (int i = 0; i < frylark.getLives(); i++) {
g.fillRect( (i + 1) * 15, 10, 10, 10);
}
// draw the score
g.setColor(Color.GREEN);
g.drawString("Score: " + frylark.getScore(), 10, 50);
// draw the level
g.setColor(Color.YELLOW);
g.drawString("level: " + frylark.getScoreNum(), 10, 80);
// game over sequence, changes the font to size 40 and displays game over, as well as the payers score and level reached plus the game over sound.
if (frylark.getLives() ==0){
g.setColor(Color.RED);
g.setFont(new Font("override", Font.BOLD, 40));
g.drawString("Game over !", 280, 290);
playSound("/Game/sounds/game_over.wav");
g.drawString("You reached Level " + frylark.getScoreNum() + " Your Score: " + frylark.getScore(), 60, 330);
}
}
// main method which after all classes have been read and checked, "Game development environment OK! " will be printed to the console.
// then a new game is created and given dimensions and launched.
public static void main(String args[]) {
System.out.println("Game development environment OK! ");
GameLoader gameLoader = new GameLoader();
MyGame myGame = new MyGame();
gameLoader.setup(myGame,new Dimension(800,600),false);
gameLoader.start();
}
}
and my Monster class
import java.util.Random;
import java.awt.image.BufferedImage;
public class Monster {
private String name;
int x;
int y;
private BufferedImage image;
Random rand;
public Monster (String nameIn, BufferedImage imageIn)
{
name = nameIn;
x = 0;
y = 0;
image = imageIn;
}
public void chase(Hero hero) {
if (hero.getX() < x) { // if hero is to the left
x--;
}
if (hero.getX() > x) { // if hero is to the right
x++ ;
}
if (hero.getY() < y) { // if hero is to the above
y--;
}
if (hero.getY() > y) { // if hero is to the below
y++;
}
}
public boolean overlap(Monster monsters[]){
if (monsters[0].x == monsters[1].x && monsters[0].y == monsters[1].y || monsters[0].x == monsters[2].x && monsters[0].y == monsters[2].y ||
monsters[1].x == monsters[0].x && monsters[1].y == monsters[0].y || monsters[1].x == monsters[2].x && monsters[1].y == monsters[2].y ||
monsters[2].x == monsters[0].x && monsters[2].y == monsters[0].y || monsters[2].x == monsters[1].x && monsters[2].y == monsters[1].y) {
return true;
}
else{
return false;
}
}
public boolean eaten(Hero hero) {
if (hero.getX() == x && hero.getY() == y) {
return true;
}
else {
return false;
}
}
public BufferedImage getImage() {
return image;
}
public int GetX(){
return x;
}
public int GetY(){
return y;
}
public String getName()
{
return this.name;
}
public void setX(int xIn) {
x = xIn;
}
public void setY(int yIn) {
y = yIn;
}
public boolean left(Hero hero) {
if (hero.getX() < x) {
return true;
}
else {
return false;
}
}
public boolean right(Hero hero) {
if (hero.getX() > x) {
return true;
}
else {
return false;
}
}
}
I would modify your Monster constructor to accept both images. Then modify Monster.getImage() to call left() and return the correct one based on the result. You probably don't need to call right() as well, since if the monster is not facing left then you know it needs to face right. Unless you want to get more sophisticated and also add a view facing straight forward or backward.
In Java I want to essentially focus on the 1 pixel at the dead center of the screen and detect/call an action if there is a change of color (ex. Center is focused on a white background, and suddenly I open up a green background, that 1 pixel was detected as going from white -> green). I know I would need the height and width of the resolution and determine the center from that.
The only problem now is I have no idea what code I would need to further move on with this process. Can someone guide me through what I can do? I know this is kinda broad since it doesn't include any code.
Here is a quick and dirty example, maybe it helps:
public class PixelBot {
private final Robot bot;
private boolean running = true;
private int lastPixelValue = 0;
public static void main(String[] args) throws Exception {
new PixelBot();
}
public PixelBot() throws AWTException {
this.bot = new Robot();
this.runInBackground();
}
private void checkPixel() {
Rectangle areaOfInterest = getAreaOfInterest();
BufferedImage image = bot.createScreenCapture(areaOfInterest);
int clr = image.getRGB(0, 0);
if (clr != lastPixelValue) {
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
System.out.println("\nPixel color changed to: Red: " + red + ", Green: " + green + ", Blue: " + blue);
Toolkit.getDefaultToolkit().beep();
lastPixelValue = clr;
} else {
System.out.print(".");
}
}
private Rectangle getAreaOfInterest() {
// screen size may change:
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
// half of screen, minus 1 pixel to be captured:
int centerPointX = (int) (screenSize.getWidth() / 2 - 1);
int centerPointY = (int) (screenSize.getHeight() / 2 - 1);
Point centerOfScreenMinusOnePixel = new Point(centerPointX, centerPointY);
return new Rectangle(centerOfScreenMinusOnePixel, new Dimension(1, 1));
}
private void runInBackground() {
new Thread(new Runnable() {
#Override
public void run() {
while (running) {
checkPixel();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void stop() {
this.running = false;
}
}