Java Graphics setColor does not work - java

I am trying to implement a plot of a Julia Set using a Canvas inside a JFrame. For some reason it seems that setColor() does not work. Here's the responsible code:
#Override
public void paint(Graphics aGraphics)
{
// store on screen graphics
Graphics cScreenGraphics = aGraphics;
// render on background image
aGraphics = m_cBackGroundImage.getGraphics();
for(int i = 0; i < m_iWidth; i++)
{
for(int j = 0; j < m_iHeight; j++)
{
int r = m_iPixelRed[i][j];
int g = m_iPixelGreen[i][j];
int b = m_iPixelBlue[i][j];
aGraphics.setColor(new Color(r, g, b));
aGraphics.drawRect(i, j, 0, 0);
}
}
// rendering is done, draw background image to on screen graphics
cScreenGraphics.drawImage(m_cBackGroundImage, 1, 1, null);
}
At first I suspected that the values were not passed to m_iPixel... correctly, so I hardcoded the values to 0xff in the calling function. I checked this via r, g, b and am certain that they are all set to that value, yet the canvas is black.
The funny thing is: when I enter aGraphics.setColor(Color.WHITE) or aGraphics.setColor(0xff, 0xff, 0xff) instead of the variables r, g, b it works! Even though I checked the variables to be at the same value and hard coded them earlier to 0xff. I am completely out of ideas as to what could be the issue...
EDIT:
The values were hardcoded as follows:
public void setPixelColour(int i, int j, int r, int g, int b)
{
m_iPixelRed[i][j] = 0xff;
m_iPixelGreen[i][j] = 0xff;
m_iPixelBlue[i][j] = 0xff;
}
setPixelColour was called by the superclass in this method:
private void calcColour(int i, int j, int aIterations)
{
m_cCanvas.setPixelColour(i, j, 0XFF, 0xff, 0XFF);
}
Which was in turn called by this loop.
for(int i = 0; i < iCanvasHeight; i++){
for(int j = 0; j < iCanvasWidth; j++){
cSum.setRe(m_cCoordPlane[i][j].getRe());
cSum.setIm(m_cCoordPlane[i][j].getIm());
m_iIterations[i][j] = 0;
do{
m_iIterations[i][j]++;
cSum = cSum.square();
cSum = cSum.add(m_cSummand);
m_dAbsSqValues[i][j] = cSum.getAbsSq();
}while((m_iIterations[i][j] < MAXITER) && (m_dAbsSqValues[i][j] < m_iDivergThresh));
this.calcColour(i, j, m_iIterations[i][j]);
m_cMsgIter = "x = " + i + " , y = " + j;
this.repaint();
}
}
I checked made sure that this loop is definitely completed. I checked the values again using the debugger right before setColor(). Since I don't trust the debugger (out of experience) I checked another time with the console by adding System.out.println("r = " + Integer.toString(r) + " g = " + Integer.toString(g) + " b = " + Integer.toString(b)); right before setColor().
EDIT:
This is my paint method of the JFrame:
public void paint(Graphics aGraphics)
{
Graphics cScreenGraphics = aGraphics;
// render on background image
aGraphics = m_cBackGroundImage.getGraphics();
this.paintComponents(aGraphics);
// drawString() calls are debug code only...
aGraphics.setColor(Color.BLACK);
aGraphics.drawString(m_cSMsg, 10, 450);
aGraphics.drawString(m_cMsgIter, 10, 465);
aGraphics.drawString(m_cMsgDivThresh, 10, 480);
// rendering is done, draw background image to on screen graphics
cScreenGraphics.drawImage(m_cBackGroundImage, 0, 0, null);
}

Not sure if posting big chunks of code in comments makes a whole lot of sense so here's my test code for you:
package test;
import javax.swing.JFrame;
public class Test
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
MyCanvas canvas = new MyCanvas();
frame.add(canvas);
frame.pack();
frame.setVisible(true);
for(int i = 0; i < 800; i++)
{
for(int j = 0; j < 600; j++)
{
canvas.setPixelColour(i, j, 0XFF, 0xff, 0XFF);
canvas.repaint();
}
}
}
}
And this is the MyCanvas class:
package test;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class MyCanvas extends java.awt.Canvas
{
private BufferedImage m_cBackGroundImage;
private int[][] m_iPixelRed, m_iPixelGreen, m_iPixelBlue;
private int m_iWidth, m_iHeight;
public MyCanvas()
{
setPreferredSize(new Dimension(800, 600));
m_iWidth = 800;
m_iHeight = 600;
m_cBackGroundImage = new BufferedImage(m_iWidth, m_iHeight, BufferedImage.TYPE_INT_ARGB);
m_iPixelRed = new int[m_iWidth][m_iHeight];
m_iPixelGreen = new int[m_iWidth][m_iHeight];
m_iPixelBlue = new int[m_iWidth][m_iHeight];
}
public void paint(Graphics aGraphics)
{
Graphics cScreenGraphics = aGraphics;
aGraphics = m_cBackGroundImage.getGraphics();
for(int i = 0; i < m_iWidth; i++)
{
for(int j = 0; j < m_iHeight; j++)
{
int r = m_iPixelRed[i][j];
int g = m_iPixelGreen[i][j];
int b = m_iPixelBlue[i][j];
aGraphics.setColor(new Color(r, g, b));
aGraphics.drawRect(i, j, 0, 0);
}
}
cScreenGraphics.drawImage(m_cBackGroundImage, 1, 1, null);
}
public void setPixelColour(int i, int j, int r, int g, int b)
{
m_iPixelRed[i][j] = r;
m_iPixelGreen[i][j] = g;
m_iPixelBlue[i][j] = b;
}
}
I tried staying as close to what you provided as possible (even though your naming convention is not really my kind of thing). The main changes were in the loop in the main method because I didn't need most of that code. I also obliterated the calcColor method because it simply called a different method.
Anyway, this works for me (= I get a white canvas). I also tried changing the 0xff s to (int)(Math.random() * 255) which will result in a... let's go with rainbow-colored canvas, so it seems to be working fine.

Related

Intergrating Proclipsing into Eclipse Project, screen won't appear

I have a project that on it's own functions as I would like it to. It's a small game about the player (a blob) picking up randomly spawning items in an attempt to keep their "happiness" from hitting 0.
I originally wrote it in BlueJ, but I asked a friend who is more adept in programming about giving it graphics. He said that while the swing package would work, it would be better in Eclipse with Processing.
I set it up with him on my computer over Skype, moved all my files from BlueJ to Eclipse, and began working on making a class for the visuals to function it.
Here's the code (All variables and functions from the Map class are functioning):
public void setup()
{
//int x = gameMap.getXScale()*5 + 5*(xSC+2);
//int y = gameMap.getYScale()*5 + 5*(ySC+2) + 150;
gameMap = new Map(MapTypes.treasureRoom(), BlobTypes.trBlob());
xSC = gameMap.getXScale();
ySC = gameMap.getYScale();
sze = 100;
spc = 5;
int x = gameMap.getXScale()*5 + 5*(xSC+2);
int y = gameMap.getYScale()*5 + 5*(ySC+2) + 150;
size(x,y);
}
public void draw()
{
int[] rgb = gameMap.getBlob().getRGBVal();
int r = 204;
int g = 102;
int b = 0;
Node[][] n = gameMap.getMapOfNodes();
background(0);
for(int i = 0; i < ySC; i ++){
for(int j = 0; j < xSC; j++){
if(n[j][i].getNodeType() == 0){
r = 128;
g = 128;
b = 128;
}else if(n[j][i].getNodeType() == 1){
r = rgb[0];
g = rgb[1];
b = rgb[2];
}else if(n[j][i].getNodeType() == 2){
r = 204;
g = 153;
b = 255;
}else if(n[j][i].getNodeType() == 3){
r = 0;
g = 0;
b = 0;
}
rectt(j*10+spc, i*10+spc, sze, sze, 5, r, g, b);
}
}
fill(100);
rect(50, 50, 100, 100);
}
void rectt(float x, float y, float w, float h, float ra, int r, int b, int g)
{
fill(r,b,g);
rect(x, y, w, h, ra);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
It is inside a Game() class that extends PApplet. When I try running it (as an application), no screen shows up at all. What do I do?
EDIT: The Node[][] near the beginning of draw() is an array of each individual point on the Map that the player can be. Also, the MapTypes and BlobTypes objects are just a collection of methods for storing different Map objects and Blob (the player) objects.
you aren't calling anything in your main method class
public static void main(String[] args) {
// TODO Auto-generated method stub
}
I can't personally tell you what all you need to call from this class but it should be something like this
public static void main(String[] args) {
ThisClass main = new ThisClass(parameters if any);
main.setup();
while(game is not over){
main.draw();
update other game logic
}
}
As a note, one iteration of your while loop is equvilant to one frame. So everything you want to be accomplished per frame, must be placed in here.

(Java) Drawn Rectangles do not appear

So am working on a School Project, and I want to draw a game board made out of Rectangles which are saved in an array. I managed to do that, but only the last drawn Rectangle Stays on the Panel. I'm really desperate and i don't know where my mistake is.
The Field is a 4x5 field. The Coordinates saved in the Tile Class:
the first two represent the upper left Corner
the last two represent the bottom right corner of it
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class quoVadis{
public static void main(String[] args) {
new Frame();
}
}
class Tile {
Random rGen = new Random();
int sX,sY,eX,eY;
Color farbe;
public Tile(int sX, int sY,int eX,int eY){
this.sX = sX;
this.sY = sY;
this.eX = eX;
this.eY = eY;
farbe = new Color(rGen.nextInt(156)+100,rGen.nextInt(156)+100,rGen.nextInt(156)+100);
}
}
class Frame extends JFrame{
private Game game;
final int GAMESIZE = 400;
final int PANELSIZE = GAMESIZE/5;
public Frame() {
super("Quo Vadis");
this.setSize(GAMESIZE, GAMESIZE*5/4);
this.setLocation(50, 50);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game = new Game(GAMESIZE, PANELSIZE);
game.setLayout(null);
game.setBackground(Color.WHITE);
this.getContentPane().add(game);
this.setVisible(true);
}
}
class Game extends JPanel{
int GAMESIZE;
int PANELSIZE;
private Tile field[][]=new Tile[4][5];
Random rGen = new Random(4711);
Tile stein;
public Game(int g, int p) {
GAMESIZE = g;
PANELSIZE = p;
// The Mistake has to be in this following Part:
int idx=0;
for(Tile i:levels){
for(int j = i.sX; j <= i.eX; j++){
for(int k = i.sY; k <= i.eY; k++){
field[j][k] = levels[idx];
}
}
idx++;
}
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
draw((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
this.setVisible(true);
}
int rx, ry,rdx,rdy;
private void draw(int a, int b, int c, int d){
rx=a;
ry=b;
rdx=c;
rdy=d;
repaint(rx,ry,rdx,rdy);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(stein.farbe);
g.fillRect(rx, ry, rdx, rdy);
}
Tile[] levels = {
new Tile(1,0,2,1),
new Tile(0,0,0,1),
new Tile(3,0,3,1),
new Tile(0,2,0,3),
new Tile(1,2,2,2),
new Tile(3,2,3,3),
new Tile(0,4,0,4),
new Tile(1,3,1,3),
new Tile(2,3,2,3),
new Tile(3,4,3,4),
};
}
I already checked the Position of the Rectangles in numbers and they are correct in every way so they do not overlap or something like that.
Sorry for my bad english, it's not my primary language.
You need to draw each rectangle inside of your paintComponent method every time.
Currently you are calling your draw method for one rectangle then you call repaint and draw that single rectangle. paintComponent will redraw the entire panel each time it is called. This means that it will on preserve the last rectangle (the rest were "repainted over".
You want to loop through all of your tiles and use the drawRect method to draw them inside of your paintComponent method so they will be drawn every time.
public void paintComponent(Graphics g) {
super.paintComponent(g)
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
g.setColor(stein.farbe);
g.fillRect((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
}

Swing auto repaints JPanel after button clicked

I'm having this weird issue with Swing.
I am drawing few points and lines between them, directly on JPanel.
I'm just calling:
g.drawLine(pointAX, pointAY, pointBX, pointBY);
Where g is Graphics object taken from panel.getGraphics()
And this works alright, gives me nice output.
But then I'm trying to move it and I use ActionListener on my button, which does:
panel.revalidate();
panel.repaint();
drawPanel();
moveVector(moveX, moveY);
drawPoints();
drawConnections(connections);
The other methods:
drawPanel just draws some lines, so it's easier to see:
private void drawPanel(){
Graphics g = panel.getGraphics();
zeroX = panel.getWidth() / 2;
zeroY = panel.getHeight() / 2;
g.setColor(Color.GRAY);
for(int i = zeroX + 10; i < panel.getWidth(); i += 10){
g.drawLine(i, 0, i, panel.getHeight());
}
for(int i = zeroX + 10; i > 0; i -= 10){
g.drawLine(i, 0, i, panel.getHeight());
}
for(int j = zeroY - 10; j < panel.getHeight(); j += 10){
g.drawLine(0, j, panel.getWidth(), j);
}
for(int j = zeroY - 10; j > 0; j -= 10){
g.drawLine(0, j, panel.getWidth(), j);
}
g.setColor(Color.BLACK);
g.drawLine(zeroX, 0, zeroX, panel.getHeight());
g.drawLine(0, zeroY, panel.getWidth(), zeroY);
panel.paintComponents(g);
}
drawPoints looks like this
private void drawPoints() {
for(int i = 0; i < points.size(); i++){
int x = Integer.parseInt(points.get(i)[1]);
int y = Integer.parseInt(points.get(i)[2]);
drawPoint(x, y);
}
}
private void drawPoint(int x, int y) {
Graphics g = panel.getGraphics();
for (int i = -1; i < 2; i++) {
g.drawLine(zeroX + x + i, zeroY + y - 1, zeroX + x + i, zeroY + y);
}
panel.paintComponents(g);
}
g.setColor(Color.BLACK);
g.drawLine(zeroX, 0, zeroX, panel.getHeight());
g.drawLine(0, zeroY, panel.getWidth(), zeroY);
panel.paintComponents(g);
}
and drawConnections:
private void drawConnections(ArrayList<String[]> lines) {
for (String[] arr : lines) {
String x = arr[1];
String y = arr[2];
drawConnection(x, y);
}
}
private void drawConnection(String pointA, String pointB) {
int pointAX = 0, pointAY = 0, pointBX = 0, pointBY = 0;
Graphics g = panel.getGraphics();
for (String[] arr : points) {
if (arr[0].equals(pointA)) {
pointAX = Integer.parseInt(arr[1]);
pointAY = Integer.parseInt(arr[2]);
} else if (arr[0].equals(pointB)) {
pointBX = Integer.parseInt(arr[1]);
pointBY = Integer.parseInt(arr[2]);
}
}
g.drawLine(zeroX + pointAX, zeroY + pointAY, zeroX + pointBX, zeroY + pointBY);
panel.paintComponents(g);
}
What I don't understand here is that everything looks OK. I did debug and it looks ok and at the end of listener call, when everything is painted (although it paints over the old one instead of clearing it) it suddenly clears everything and nothing is visible at all.
You need to implement all the drawing in paintComponent(Graphics) in your JPanel class (or methods that are called from it). Calling getGraphics on the panel instance and using the Graphics object is not always guaranteed to work. It's also strange that you call panel.repaint() and immediately afterwards try to do additional drawing using the graphics object from the panel, that additional drawing should just be done in paintComponent(Graphics).
Using paintComponent(Graphics) will ensure your painting is done at the right time, and that the panel's graphics will be cleared (if you call the super method at least).
panel.repaint does not immediately repaint the panel, but it tells Swing that this panel should be repainted in the near future (see API docs: https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#repaint(long,%20int,%20int,%20int,%20int). So your custom painting will be cleared once the panel repaints itself.
Create a custom component by inheriting from JPanel and overwriting the method paintComponent with your custom painting code. Then, whenever the panel needs to be repainted, your code is called, and not only the user pressed a button.

BufferedImage, int[] pixels and rendering. How do they work they work together?

There is something in the following code that I am unable to understand. After digging through google for a while, I decided it would be better to ask someone.
I am following a game programming tutorial on youtube, and I feel I understand (to some degree) everything I have written, except for some lines which concern the rendering part of the program.
package com.thomas.game;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import com.thomas.game.graphics.Screen;
import com.thomas.game.input.Keyboard;
public class Game extends Canvas implements Runnable {
private static final int WIDTH = 300;
private static final int HEIGHT = (WIDTH / 16) * 9;
private static final int SCALE = 3;
private static final String TITLE = "Game";
private JFrame frame;
private Thread thread;
private Screen screen;
private BufferedImage image;
private Keyboard key;
private int[] pixels;
private boolean running = false;
private int x = 0, y = 0;
public Game() {
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
screen = new Screen(WIDTH, HEIGHT);
frame = new JFrame();
initializeFrame();
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
this is what I don't understand. I get the image raster, from which I get the databuffer. I typecast that databuffer into a (DatabufferInt), which allows me to retrieve an int[] through the getData() method. After this is done, pixel.length has a value of 48600, and every index contains the int value 0. Operating with this int[] makes the program render like it is supposed to. However, if I don't typecast and retrieve the int[] in the above manner, and instead say pixels = new int[48600], i end up with a black screen.
I guess what I want to know is: what is the difference between these two int[], or rather, what makes the first one work? How does it work?
key = new Keyboard();
addKeyListener(key);
setFocusable(true);
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1E9/60;
double delta = 0;
long now;
int ticks = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while(running) {
now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
while(delta >= 1) {
tick();
ticks++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer >= 1000) {
timer += 1000;
frame.setTitle(TITLE + " | ups: " + ticks + " fps: " + frames);
ticks = 0;
frames = 0;
}
}
}
private void render() {
BufferStrategy bs = getBufferStrategy(); // retrieves the bufferstrategy from the current component (the instance of Game that calls this method)
if(bs == null) {
createBufferStrategy(3);
return;
}
screen.clear();
screen.render(x, y);
getPixels();
Graphics g = bs.getDrawGraphics(); // retrieves a graphics object from the next in line buffer in the bufferstrategy, this graphics object draws to that buffer
g.drawImage(image, 0, 0, getWidth(), getHeight(), null); // draws the bufferedimage to the available buffer
g.dispose();
bs.show(); // orders the next in line buffer (which the graphics object g is tied to) to show its contents on the canvas
}
private void tick() {
key.update();
if(key.up)
y--;
if(key.down)
y++;
if(key.left)
x--;
if(key.right)
x++;
}
public void initializeFrame() {
frame.setTitle(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public synchronized void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Game game = new Game();
game.start();
}
public void getPixels() {
for(int i = 0; i < pixels.length; i++)
pixels[i] = screen.pixels[i];
}
}
It seems like the bufferedimage gets values from the pixels array. But I don't understand how these two communicate, or how they are connected. I haven't explicitly told the bufferedimage to get its pixels from the pixels array, so how does it know?
I will also attach the Screen class, which is responsible for updating the pixels array.
package com.thomas.game.graphics;
import java.util.Random;
public class Screen {
private int width, height;
public int[] pixels;
private final int MAP_SIZE = 64;
private final int MAP_SIZE_MASK = MAP_SIZE - 1;
private int[] tiles;
private int tileIndex;
private int xx, yy;
private Random r;
public Screen(int w, int h) {
width = w;
height = h;
pixels = new int[width * height];
tiles = new int[MAP_SIZE * MAP_SIZE];
r = new Random(0xffffff);
for(int i = 0; i < tiles.length; i++) {
tiles[i] = r.nextInt();
}
tiles[0] = 0;
}
public void clear() {
for(int i = 0; i < pixels.length; i++)
pixels[i] = 0;
}
public void render(int xOffset, int yOffset) {
for(int y = 0; y < height; y++) {
yy = y + yOffset;
for(int x = 0; x < width; x++) {
xx = x + xOffset;
tileIndex = (yy >> 4 & MAP_SIZE_MASK) * MAP_SIZE + (xx >> 4 & MAP_SIZE_MASK);
pixels[y * width + x] = tiles[tileIndex];
}
}
}
}
I really hope someone can explain this to me, it would be greatly appreciated. The program is working like it is supposed to, but I don't feel comfortable continuing on the tutorial until I grasp this.
Basic types like short, int, long etc are not Objects.
However, int[] is an array. Arrays are objects in java. Java manipulates objects by reference, not value.
In this line you are not creating a new object. You are storing a reference to the object int[] in your variable pixels. Anything you change in pixels, gets changed inside of the int[] object in image:
pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
I've created an example, try running this code:
public class Data {
private int[] values = {25,14};
public int[] getValues() {
return values;
}
public static void main(String[] args) {
Data d = new Data();
System.out.println(d.getValues()[0]);
int[] values = d.getValues();
values[0] = 15;
System.out.println(d.getValues()[0]);
}
}
Output:
25
15
Note that you have this code...
pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
while it should be like this...
pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
Change image to img.
Hope it works!

Java ImageIO.write is Colorizing a Greyscale Image

I'm having a problem that's been driving me crazy for days. Hopefully, someone here can help me understand what's happening. I'm trying to write a simple Java program that will take a directory of JPEGs, convert them to greyscale, and save them to the same folder.
My procedure is to set the red, green, and blue components of each pixel to that pixel's luminance value. The code runs fine and seems to do what I want. If I view the completed image in a JFrame, it shows up black and white. However, when I save the image (using ImageIO.write()), for some reason, it becomes colorized and looks rather red. I'd love to post the images but I guess my reputation is not good enough...
Since I can't put the images, I'll try to explain it as well as I can. Here's what I know:
If I view the newly created image using the Java program, it appears black and white as I desire.
If I save the image and try to view it using an external program, it does not appear black and white at all and just looks like a watered down version of the original image.
If I open that same saved image (the one that should be black and white but is not) using the Java program, it does indeed appear black and white.
If I save the file as a png instead, everything works fine.
Here's the relevant code I'm using if anyone would like to see it:
import java.io.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.*;
public class ImageEZ {
public static void displayImage(BufferedImage img) {
class ImageFrame extends JFrame {
ImageFrame(BufferedImage img) {
super();
class ImagePanel extends JPanel {
BufferedImage image;
ImagePanel(BufferedImage image) {
this.image = ImageEZ.duplicate(image);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), this);
}
}
ImagePanel panel = new ImagePanel(img);
add(panel);
}
}
JFrame frame = new ImageFrame(img);
frame.setSize(img.getWidth(), img.getHeight());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static BufferedImage duplicate(BufferedImage img) {
BufferedImage dup = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
dup.setRGB(0, 0, img.getWidth(), img.getHeight(), ImageEZ.getRGB(img), 0, img.getWidth());
return dup;
}
public static int[] getRedArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 8;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getRedArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 8;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] getGreenArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 16;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getGreenArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 16;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] getBlueArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 24;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getBlueArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 24;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] YBRtoRGB(int[] ybr) {
int[] y = getRedArray(ybr);
int[] r = getBlueArray(ybr);
int[] b = getGreenArray(ybr);
int[] red = new int[y.length];
int[] green = new int[y.length];
int[] blue = new int[y.length];
for (int i = 0; i < red.length; i++) {
red[i] = (int) (y[i] + 1.402*r[i]);
green[i] = (int) (y[i] + -.344*b[i] + -.714*r[i]);
blue[i] = (int) (y[i] + 1.772*b[i]);
}
int[] RGB = new int[red.length];
for (int i = 0; i < red.length; i++) {
RGB[i] = red[i] << 16 | green[i] << 8 | blue[i] | 255 << 24;
}
return RGB;
}
public static int[] getLumArray(BufferedImage img) {
int[] red = getRedArray(img); //Returns an array of the red values of the pixels
int[] green = getGreenArray(img);
int[] blue = getBlueArray(img);
int[] Y = new int[red.length];
for (int i = 0; i < red.length; i++) {
Y[i] = (int) (.299*red[i] + .587*green[i] + .114*blue[i]);
}
return Y;
}
// Converts an image to greyscale using the luminance of each pixel
public static BufferedImage deSaturate(BufferedImage original) {
BufferedImage deSaturated = new BufferedImage(original.getWidth(),
original.getHeight(),
BufferedImage.TYPE_INT_ARGB);
int[] Y = ImageEZ.getLumArray(original); //Returns an array of the luminances
for (int i = 0; i < Y.length; i++) {
Y[i] = 255 << 24 | Y[i] << 16;
}
int[] rgb = ImageEZ.YBRtoRGB(Y); //Converts the YCbCr colorspace to RGB
deSaturated.setRGB(0, 0, original.getWidth(), original.getHeight(),
rgb, 0, original.getWidth());
return deSaturated;
}
// Takes a folder of JPEGs and converts them to Greyscale
public static void main(String[] args) throws Exception {
File root = new File(args[0]);
File[] list = root.listFiles();
for (int i = 0; i < list.length; i++) {
BufferedImage a = ImageEZ.deSaturate(ImageIO.read(list[i]));
displayImage(a); //Displays the converted images.
boolean v = ImageIO.write(a, "jpg", new File(list[i].getParent() + "\\" + i + ".jpg"));
}
// Displays the first newly saved image
displayImage(ImageIO.read(new File(list[0].getParent() + "\\" + 0 + ".png")));
}
}
I just want to stress, this is not a question about alternative methods for turning making an image black and white. What I really want to know is why it works as a png but not as a jpg. Thanks a lot to all who read this far!
This is a known issue with ImageIO.
When saved/loaded as jpeg, the API doesn't know how to handle the alpha component (as I understand the problem).
The solution is to not write images with an alpha component to jpg format, or use a non-alpha based image, such as TYPE_INT_RGB instead...

Categories

Resources