I am trying to diffuse a color in java Draw (which doesn't have the capability to diffuse normally) but I ran into an error and I can't seem to spot it.
The way I went about diffusing was by writing a small script that would draw my shape hundreds of times, each time smaller and slightly varying in color. This is my snippet:
import javax.swing.*;
import java.awt.*;
public class DiffuseDraw extends JFrame
{
//set size of window here
final int length = 350;
final int height = 370;
public DiffuseDraw()
{
super("Graphics Project Window");
Container container = getContentPane();
setBackground(new Color(0,0,0));
setSize(length, height);
setVisible(true);
}
// my problem comes here:
public void paint(Graphics g)
{
Draw.fillRectangle(g,0,0,length,height,new Color(19,24,32));
int rad = 325; // size of the biggest circle
float floatGreen = 0; // Color components for black
float floatBlue = 0;
float floatRed = 0;
int counter = 0; // the counter
while (counter < 290) {
rad = rad - 1; // Here we shrink the by a small incriment
floatRed = floatRed + 87/290; //red component slowly goes brighter
floatBlue = floatBlue + 178/290; // blue component slowly goes brighter
floatGreen = floatGreen + 211/290; // green component slowly goes brighter
int intRed = (int)Math.round(floatRed);
int intBlue = (int)Math.round(floatBlue);
int intGreen = (int)Math.round(floatGreen);
Draw.fillCircle(g,173,307,rad,new Color(intRed,intBlue,intGreen));
counter = counter + 1;
}
}
public static void main(String args[]) {
DiffuseDraw prog = new DiffuseDraw();
prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
When I compile and run, I only get a black screen. I am guessing that the problem is coming from the colors not changing. The number I am adding the float red blue and green by came from me wanting to diffuse a type of blue, so I took the the brightest color of blue that would appear and divided it by 290, the number of times the loop would run.
Instead of
87/290, 178/290, and 211/290,
try using
(float)87/290, (float)178/290, and (float)211/290.
That will, at least, add some color to the window- the problem is that by default, a number like 87/290 will be evaluated to 0; casting it to a float will give the desired result of 0.3 instead.
Related
I just started to study Java. I am trying to make a program that will show five circles (random color, size and placement). I thought I would try to draw one circle (before I try five). But I draw two circles! What is going on? How is it drawing two circles?
Here is my code:
import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JFrame;
import java.util.Random;
public class Rita extends JFrame
{
public Rita()
{
setTitle("Rita");
setSize(960, 960);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
// Initiateea random object
Random rand = new Random();
// loop to draw cicles
//for (int i = 0; i<5; i++);
//Initiate random color
int red = rand.nextInt(256);
int green = rand.nextInt(256);
int blue = rand.nextInt(256);
Color randomColor = new Color (red, green, blue);
// Generate random circle width 20 and X pixels
int width = rand.nextInt(201) + 20;
// Generate random X/Y koordinater
int radius = (int)(Math.random()*49) + 2;
int x = (int)(Math.random()*(960-radius*2) + radius);
int y = (int)(Math.random()*(960-radius*2) + radius);
//int x = rand.nextInt(960);
//int y = rand.nextInt(960);
// set the color
g.setColor(randomColor);
// Draw the circle
g.fillOval(x, y, width, width); // aka rita oval, storlek
}
public static void main(String[] args)
{
Rita rita= new Rita();
rita.paint(null);
}
}
I tried to put this code in to hopefully override the two circles drawn or something. It didn't work (of course I deleted the comment-slashes first). It still draws two circles.
// loop to draw cicles
//for (int i = 0; i<5; i++);
First off I am new to this and also coding. I apologize in advance for anything that is misleading.
I am currently writing a Java program that uses an image as input. What I have currently is scanning each pixel by the width and height of the image saving the HSB in an array and then outputting the percentage of each color in the image. I now want to omit the background from that calculation. To start off lets just say the background is white. There are also pixels in the image that are not in the background that is white though.
thank you,
Oh, it's not as simple as you hope.
You cannot simply detect what's a background and what is part of image pixel by pixel.
You might try looking at this post to see how to remove one color layer of the image.
But detecting if the white pixel is a part of background or already the image?!
There are multiple possible ways:
assuming that background is just around and when (looking from any
side to the center) color changes, that is the end of the
"background". You can check every row and column from side to center
and keep record of where the "background" color ends.
or similar approach - if at least at one (of four) direction looking from the pixel to the side there is no color changes (it goes white all the way to the side), than it is part of background.
Or just take a look at another
post. From this you can try working your way up.
Anyway - you have to create a logic of detecting which (i.e.) white pixels are part of the picture and which are part of background.
I hope this at least gives you a bit more knowledge.
I am not sure what you mean. There is no code, so I can only give you an example. From what I have understood, you want to skip doing a calculation when the color is the same as the background. That is very simple. You can do something like this:
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
Color pixelColor = get pixel color at x and y;
Color backgroundColor = the background color;
if(pixelColor != backgroundColor) {
//Calculation will be done here
}
}
}
If this does not help you or you have any other questions, ask me.
Here is an example of full working code.
You can add a cursor to pick color and jslider for fuzz or threshold. Use backColor and threshold for your needs.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Convert {
private static final Color backColor = new Color(255,255,255);
private static final int THRESHOLD = 35;
private static final int TRANSPARENT = 0; // 0x00000000;
static File base = new File("f://mortar1.png");
static File base2 = new File("f://outtrans.png");
public static void main(String[] args) throws IOException {
System.out.println("Convert.main()");
for (File file : base.listFiles())
{
BufferedImage initImage = ImageIO.read(base);
int width = initImage.getWidth(null),
height = initImage.getHeight(null);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.drawImage(initImage, 0, 0, null);
System.out.println("before: " + image.getRGB(0, 0));
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
Color color = new Color(pixel);
int dr = Math.abs(color.getRed() - backColor.getRed()),
dg = Math.abs(color.getGreen() - backColor.getGreen()),
db = Math.abs(color.getBlue() - backColor.getBlue());
if (dr < THRESHOLD && dg < THRESHOLD && db < THRESHOLD) {
image.setRGB(x, y, TRANSPARENT);
}
}
}
System.out.println(" after: " + image.getRGB(0, 0));
File file = new File("f://outtrans1.png");
ImageIO.write(image, "png", file);
}
}
}
Or simple set a png file with empty fill..
This idea seems good for me. But if you don't agree, please, tell me causes)
I was wondering if I could find some help on this problem. I was asked to use an image ("corn.jpg"), and flip it entirely upside down. I know I need to write a program which will switch pixels from the top left corner with the bottom left, and so on, but I wasn't able to get my program to work properly before time ran out. Could anyone provide a few tips or suggestions to solve this problem? I'd like to be able to write my code out myself, so suggestions only please. Please note that my knowledge of APImage and Pixel is very limited. I am programming in Java.
Here is what I managed to get done.
import images.APImage;
import images.Pixel;
public class Test2
{
public static void main(String [] args)
{
APImage image = new APImage("corn.jpg");
int width = image.getImageWidth();
int height = image.getImageHeight();
int middle = height / 2;
//need to switch pixels in bottom half with the pixels in the top half
//top half of image
for(int y = 0; y < middle; y++)
{
for (int x = 0; x < width; x++)
{
//bottom half of image
for (int h = height; h > middle; h++)
{
for(int w = 0; w < width; w++)
{
Pixel bottomHalf = image.getPixel(h, w);
Pixel topHalf = image.getPixel(x, y);
//set bottom half pixels to corresponding top ones?
bottomHalf.setRed(topHalf.getRed());
bottomHalf.setGreen(topHalf.getGreen());
bottomHalf.setBlue(topHalf.getBlue());
//set top half pixels to corresponding bottom ones?
topHalf.setRed(bottomHalf.getRed());
topHalf.setGreen(bottomHalf.getGreen());
topHalf.setBlue(bottomHalf.getBlue());
}
}
}
}
image.draw();
}
}
Thank you for your help!
See Transforming Shapes, Text, and Images.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FlipVertical {
public static BufferedImage getFlippedImage(BufferedImage bi) {
BufferedImage flipped = new BufferedImage(
bi.getWidth(),
bi.getHeight(),
bi.getType());
AffineTransform tran = AffineTransform.getTranslateInstance(0, bi.getHeight());
AffineTransform flip = AffineTransform.getScaleInstance(1d, -1d);
tran.concatenate(flip);
Graphics2D g = flipped.createGraphics();
g.setTransform(tran);
g.drawImage(bi, 0, 0, null);
g.dispose();
return flipped;
}
FlipVertical(BufferedImage bi) {
JPanel gui = new JPanel(new GridLayout(1,2,2,2));
gui.add(new JLabel(new ImageIcon(bi)));
gui.add(new JLabel(new ImageIcon(getFlippedImage(bi))));
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) throws AWTException {
final Robot robot = new Robot();
Runnable r = new Runnable() {
#Override
public void run() {
final BufferedImage bi = robot.createScreenCapture(
new Rectangle(0, 660, 200, 100));
new FlipVertical(bi);
}
};
SwingUtilities.invokeLater(r);
}
}
Whenever you're swapping variables, if your language doesn't allow for simultaneous assignment (and Java doesn't), you need to use a temporary variable.
Consider this:
a = 1;
b = 2;
a = b; // a is now 2, just like b
b = a; // b now uselessly becomes 2 again
Rather than that, do this:
t = a; // t is now 1
a = b; // a is now 2
b = t; // b is now 1
EDIT: And also what #vandale says in comments :P
If you are able to use the Graphics class, the following may be of use:
http://www.javaworld.com/javatips/jw-javatip32.html
And the Graphics class documentation:
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html
Instead of using
Pixel bottomHalf = image.getPixel(h, w);
Pixel topHalf = image.getPixel(x, y);
//set bottom half pixels to corresponding top ones?
bottomHalf.setRed(topHalf.getRed());
bottomHalf.setGreen(topHalf.getGreen());
bottomHalf.setBlue(topHalf.getBlue());
//set top half pixels to corresponding bottom ones?
topHalf.setRed(bottomHalf.getRed());
topHalf.setGreen(bottomHalf.getGreen());
topHalf.setBlue(bottomHalf.getBlue());
You should have stored the bottomHalf's RGB into a temporary Pixel and used that to set topHalf after replacing bottomHalf's values (if you follow). You could have also really used something like this.... assuming your pixel operates on integer rgb values (which would have improved your main method).
private static final Pixel updateRGB(Pixel in, int red, int green, int blue) {
in.setRed(red); in.setGreen(green); in.setBlue(blue);
}
You want to flip the image upside down, not swap the top and bottom half.
The loop could look like this.
int topRow = 0;
int bottomRow = height-1;
while(topRow < bottomRow) {
for(int x = 0; x < width; x++) {
Pixel t = image.getPixel(x, topRow);
image.setPixel(x, topRow, image.getPixel(x, bottomRow));
image.setPixel(x, bottomRow, t);
}
topRow++;
bottomRow--;
}
I am having a problem with my java code. I'm trying to make it so the top left quadrant produces a set number of lines input by a user through JOption Pane which are in random colors and in random positions. The programs builds successfully but it does not produce the number of lines the user input, nor does it set a random color (This it at the very bottom of my code). Can someone please explain how to fix this problem? Thanks very much.
Edit: fixed the curve braces but still will not work.
Edit: Everything works now except the random colors
import javax.swing.*; //for JFrame
import java.awt.*; //for Graphics and Container
import java.util.Random;
import javax.swing.JOptionPane;
// other import statements here
public class RandomGraphics
{
// constants are used to draw the grid, and for you to put shapes in the grid
public static final int MIDX = 400;
public static final int MIDY = 300;
public static final int MAXX = 799;
public static final int MAXY = 599;
public static final int COLOR = (int) (Math.random() * 256);
// make another constant for the color value that will
// be used to generate a random color
public static void main( String[] args )throws InterruptedException
{
//*** This next section sets up the graphics window.
//*** You are not required to understand it
Container contentPane;
Graphics g;
JFrame win = new JFrame("Random Graphics");
win.setSize(825,650);
win.setLocation(0,0);
win.setVisible(true);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = win.getContentPane();
contentPane.setBackground(Color.white);
g = contentPane.getGraphics();
Thread.sleep(50);
//*** done setting up graphics window
// Draws Grid - DO NOT CHANGE
// After you use JOptionPane to get the number of lines, you can move this
// section of code to just after that, so the lines will not disappear
g.drawRect(0,0,MAXX+1,MAXY+1);
g.drawLine(0,MIDY,MAXX,MIDY); // horizontal line
g.drawLine(MIDX,0,MIDX,MAXY); // vertical line
// Create Random object
Random r = new Random();
// Top left quadrant:
// Use a JOptionPane to ask the user to enter the number of lines 1 to 100.
int count = 0;
do
{
String morelines = JOptionPane.showInputDialog("Enter a number of lines between 1 to 100");
count = Integer.parseInt(morelines);
}
while(count > 100 || count < 1);
for(int i = 1; i >= count; i++)
{
g.setColor(new Color (r.nextInt(COLOR), r.nextInt(COLOR), r.nextInt(COLOR)));
g.drawLine(r.nextInt(MIDX), r.nextInt(MIDY), r.nextInt(MIDX), r.nextInt(MIDY));
}
g = contentPane.getGraphics();
Graphics objects are not persistent, the programmer needs to draw the GUI to them when asked to do so. For tips, see the Performing Custom Painting Lesson of the tutorial.
Beside the 'always include curly braces around loops advice', note..
for(int i = 1; i >= count; i++)
Should be..
for(int i = 1; i <= count; i++)
But don't ignore the advice about custom painting. The app. will not render reliably until that is fixed.
for(int i = 1; i >= count; i++)
g.setColor(new Color (r.nextInt(COLOR), r.nextInt(COLOR), r.nextInt(COLOR)));
g.drawLine(r.nextInt(MIDX), r.nextInt(MIDY), r.nextInt(MIDX), r.nextInt(MIDY));
Looking at your indenting, it looks like you want g.setColor(...) and g.drawLine(...) to be inside your for loop. You need to enclose them in curly braces {}, otherwise only the statement immediately following your for loop will be inside the loop.
I'd like to implement a simple bitmap font drawing in Java AWT-based application. Application draws on a Graphics object, where I'd like to implement a simple algorithm:
1) Load a file (probably using ImageIO.read(new File(fileName))), which is 1-bit PNG that looks something like that:
I.e. it's 16*16 (or 16*many, if I'd like to support Unicode) matrix of 8*8 characters. Black corresponds to background color, white corresponds to foreground.
2) Draw strings character-by-character, blitting relevant parts of this bitmap to target Graphics. So far I've only succeeded with something like that:
int posX = ch % 16;
int posY = ch / 16;
int fontX = posX * CHAR_WIDTH;
int fontY = posY * CHAR_HEIGHT;
g.drawImage(
font,
dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
null
);
It works, but, alas, it blits the text as is, i.e. I can't substitute black and white with desired foreground and background colors, and I can't even make background transparent.
So, the question is: is there a simple (and fast!) way in Java to blit part of one 1-bit bitmap to another, colorizing it in process of blitting (i.e. replacing all 0 pixels with one given color and all 1 pixels with another)?
I've researched into a couple of solutions, all of them look suboptimal to me:
Using a custom colorizing BufferedImageOp, as outlined in this solution - it should work, but it seems that it would be very inefficient to recolorize a bitmap before every blit operation.
Using multiple 32-bit RGBA PNG, with alpha channel set to 0 for black pixels and to maximum for foreground. Every desired foreground color should get its own pre-rendered bitmap. This way I can make background transparent and draw it as a rectangle separately before blitting and then select one bitmap with my font, pre-colorized with desired color and draw a portion of it over that rectangle. Seems like a huge overkill to me - and what makes this option even worse - it limits number of foreground colors to a relatively small amount (i.e. I can realistically load up and hold like hundreds or thousands of bitmaps, not millions)
Bundling and loading a custom font, as outlined in this solution could work, but as far as I see in Font#createFont documentation, AWT's Font seems to work only with vector-based fonts, not with bitmap-based.
May be there's already any libraries that implement such functionality? Or it's time for me to switch to some sort of more advanced graphics library, something like lwjgl?
Benchmarking results
I've tested a couple of algorithms in a simple test: I have 2 strings, 71 characters each, and draw them continuously one after another, right on the same place:
for (int i = 0; i < N; i++) {
cv.putString(5, 5, STR, Color.RED, Color.BLUE);
cv.putString(5, 5, STR2, Color.RED, Color.BLUE);
}
Then I measure time taken and calculate speed: string per second and characters per second. So far, various implementation I've tested yield the following results:
bitmap font, 16*16 characters bitmap: 10991 strings / sec, 780391 chars / sec
bitmap font, pre-split images: 11048 strings / sec, 784443 chars / sec
g.drawString(): 8952 strings / sec, 635631 chars / sec
colored bitmap font, colorized using LookupOp and ByteLookupTable: 404 strings / sec, 28741 chars / sec
You might turn each bitmap into a Shape (or many of them) and draw the Shape. See Smoothing a jagged path for the process of gaining the Shape.
E.G.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.util.Random;
/* Gain the outline of an image for further processing. */
class ImageShape {
private BufferedImage image;
private BufferedImage ImageShape;
private Area areaOutline = null;
private JLabel labelOutline;
private JLabel output;
private BufferedImage anim;
private Random random = new Random();
private int count = 0;
private long time = System.currentTimeMillis();
private String rate = "";
public ImageShape(BufferedImage image) {
this.image = image;
}
public void drawOutline() {
if (areaOutline!=null) {
Graphics2D g = ImageShape.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0,0,ImageShape.getWidth(),ImageShape.getHeight());
g.setColor(Color.RED);
g.setClip(areaOutline);
g.fillRect(0,0,ImageShape.getWidth(),ImageShape.getHeight());
g.setColor(Color.BLACK);
g.setClip(null);
g.draw(areaOutline);
g.dispose();
}
}
public Area getOutline(Color target, BufferedImage bi) {
// construct the GeneralPath
GeneralPath gp = new GeneralPath();
boolean cont = false;
int targetRGB = target.getRGB();
for (int xx=0; xx<bi.getWidth(); xx++) {
for (int yy=0; yy<bi.getHeight(); yy++) {
if (bi.getRGB(xx,yy)==targetRGB) {
if (cont) {
gp.lineTo(xx,yy);
gp.lineTo(xx,yy+1);
gp.lineTo(xx+1,yy+1);
gp.lineTo(xx+1,yy);
gp.lineTo(xx,yy);
} else {
gp.moveTo(xx,yy);
}
cont = true;
} else {
cont = false;
}
}
cont = false;
}
gp.closePath();
// construct the Area from the GP & return it
return new Area(gp);
}
public JPanel getGui() {
JPanel images = new JPanel(new GridLayout(1,2,2,2));
JPanel gui = new JPanel(new BorderLayout(3,3));
JPanel originalImage = new JPanel(new BorderLayout(2,2));
final JLabel originalLabel = new JLabel(new ImageIcon(image));
originalImage.add(originalLabel);
images.add(originalImage);
ImageShape = new BufferedImage(
image.getWidth(),
image.getHeight(),
BufferedImage.TYPE_INT_RGB
);
labelOutline = new JLabel(new ImageIcon(ImageShape));
images.add(labelOutline);
anim = new BufferedImage(
image.getWidth()*2,
image.getHeight()*2,
BufferedImage.TYPE_INT_RGB);
output = new JLabel(new ImageIcon(anim));
gui.add(output, BorderLayout.CENTER);
updateImages();
gui.add(images, BorderLayout.NORTH);
animate();
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
animate();
}
};
Timer timer = new Timer(1,al);
timer.start();
return gui;
}
private void updateImages() {
areaOutline = getOutline(Color.BLACK, image);
drawOutline();
}
private void animate() {
Graphics2D gr = anim.createGraphics();
gr.setColor(Color.BLUE);
gr.fillRect(0,0,anim.getWidth(),anim.getHeight());
count++;
if (count%100==0) {
long now = System.currentTimeMillis();
long duration = now-time;
double fraction = (double)duration/1000;
rate = "" + (double)100/fraction;
time = now;
}
gr.setColor(Color.WHITE);
gr.translate(0,0);
gr.drawString(rate, 20, 20);
int x = random.nextInt(image.getWidth());
int y = random.nextInt(image.getHeight());
gr.translate(x,y);
int r = 128+random.nextInt(127);
int g = 128+random.nextInt(127);
int b = 128+random.nextInt(127);
gr.setColor(new Color(r,g,b));
gr.draw(areaOutline);
gr.dispose();
output.repaint();
}
public static void main(String[] args) throws Exception {
int size = 150;
final BufferedImage outline = javax.imageio.ImageIO.read(new java.io.File("img.gif"));
ImageShape io = new ImageShape(outline);
JFrame f = new JFrame("Image Outline");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(io.getGui());
f.pack();
f.setResizable(false);
f.setLocationByPlatform(true);
f.setVisible(true);
}
}
I have to figure there is a factor of ten error in the FPS count on the top left of the blue image though. 50 FPS I could believe, but 500 FPS seems ..wrong.
Okay, looks like I've found the best solution. The key to success was accessing raw pixel arrays in underlying AWT structures. Initialization goes something like that:
public class ConsoleCanvas extends Canvas {
protected BufferedImage buffer;
protected int w;
protected int h;
protected int[] data;
public ConsoleCanvas(int w, int h) {
super();
this.w = w;
this.h = h;
}
public void initialize() {
data = new int[h * w];
// Fill data array with pure solid black
Arrays.fill(data, 0xff000000);
// Java's endless black magic to get it working
DataBufferInt db = new DataBufferInt(data, h * w);
ColorModel cm = ColorModel.getRGBdefault();
SampleModel sm = cm.createCompatibleSampleModel(w, h);
WritableRaster wr = Raster.createWritableRaster(sm, db, null);
buffer = new BufferedImage(cm, wr, false, null);
}
#Override
public void paint(Graphics g) {
update(g);
}
#Override
public void update(Graphics g) {
g.drawImage(buffer, 0, 0, null);
}
}
After this one, you've got both a buffer that you can blit on canvas updates and underlying array of ARGB 4-byte ints - data.
Single character can be drawn like that:
private void putChar(int dx, int dy, char ch, int fore, int back) {
int charIdx = 0;
int canvasIdx = dy * canvas.w + dx;
for (int i = 0; i < CHAR_HEIGHT; i++) {
for (int j = 0; j < CHAR_WIDTH; j++) {
canvas.data[canvasIdx] = font[ch][charIdx] ? fore : back;
charIdx++;
canvasIdx++;
}
canvasIdx += canvas.w - CHAR_WIDTH;
}
}
This one uses a simple boolean[][] array, where first index chooses character and second index iterates over raw 1-bit character pixel data (true => foreground, false => background).
I'll try to publish a complete solution as a part of my Java terminal emulation class set soon.
This solution benchmarks for impressive 26007 strings / sec or 1846553 chars / sec - that's 2.3x times faster than previous best non-colorized drawImage().