I've been trying to paint on canvas but i can't make it work, i can see the JFrame but it seems it doesn't call the paint method when the Mover() object is being added to it. This is the first time using canvas so i don't know what am i missing. Here is code:
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.io.File;
public class Move extends Canvas
{
private static int [][]imgRGB;
public Move()
{
try
{
BufferedImage hugeImage = ImageIO.read(new File("C:/Users/pc/Pictures/Nave.gif"));
imgRGB = convertToRGB(hugeImage);
}
catch(IOException e)
{
System.out.println(e);
}
}
public void Paint(Graphics g)
{
super.paint(g);
for(int i=0 ; i<imgRGB.length ; i++)
{
for(int j=0 ; j<imgRGB[i].length; j++)
{
g.setColor(new Color(imgRGB[i][j]));
g.drawLine(i,j,i,j);
}
}
}
private static int[][] convertToRGB(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
public static void main(String[] args)
{
JFrame container = new JFrame("pixel");
container.add(new Move());
container.setSize(400,400);
container.setVisible(true);
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
public void Paint(Graphics g)
Method names are case sensitive. You should override paint(...).
Always use the #Override annotation and the compiler will notify you when you attempt to override a method that doesn't exist:
#Override
public void paint(Graphics g)
{
...
}
However, you should not be overriding Canvas in a Swing application.
Instead you should extend JPanel and then you should be overriding the paintComponent(...) method.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
Related
Hey im trying to create a program which uses Floyd-Steinberg's dithering algorithm to produce a dithered version of a image.
the code for my program is below.
but I believe I am getting an error with with the rounding in the "calculateErr" multiplication with the diviser.
the image I am using to test is this cat one: Cat Image
and for some reason it ends up looking like this Dithered cat image
any solutions to what I am doing wrong would be greatly appreciated.
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Dithering extends Canvas {
public BufferedImage ditheredIMG = new BufferedImage(481,480,
BufferedImage.TYPE_BYTE_GRAY);
public void paint(Graphics g) {
BufferedImage i = null;
try {
i = displayImage(g);
} catch (IOException e) {
throw new RuntimeException(e);
}
getPixels(g, i);
g.drawImage(ditheredIMG,480,0,this);
}
public static void main(String[] args) {
Dithering d = new Dithering();
JFrame f =new JFrame();
f.add(d);
f.setSize( 960,481);
f.setVisible(true);
}
public BufferedImage displayImage(Graphics g) throws IOException {
final File file = new File("Cat.jpg");
final BufferedImage i = ImageIO.read(file);
g.drawImage(i, 0,0,this);
return i;
}
public void getPixels(Graphics g, BufferedImage i) {
for (int y = 1; y < i.getHeight()-1; y++){
for (int x = 1; x < i.getWidth()-1; x++) {
int pixelValue = i.getRGB(x, y);
int red = (pixelValue & 0x00ff0000) >> 16;
int green = (pixelValue & 0x0000ff00) >> 8;
int blue = pixelValue & 0x000000ff;
int newRed = quantisePixel(red);
int newGreen = quantisePixel(green);
int newBlue = quantisePixel(blue);
int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;
ditheredIMG.setRGB(x+1,y, (int) (calculateErr(pixelValue, newPixel) * (7/16.0)));
ditheredIMG.setRGB(x-1,y+1, (int) (calculateErr(pixelValue, newPixel) * (3/16.0)));
ditheredIMG.setRGB(x,y+1, (int) (calculateErr(pixelValue, newPixel) * (5/16.0)));
ditheredIMG.setRGB(x+1,y+1, (int) (calculateErr(pixelValue, newPixel)* (1/16.0)));
}
}
}
public int calculateErr(int oldVal, int newVal){
return oldVal-newVal;
}
public static int quantisePixel(int val){
if(val > 127){
return 255;
} else{
return 0;
}
}
}
hey so here is the updated version but I am unsure if its working correctly if anyone can tell me if it is or is not that would be greatly appreciated. I've changed it so now its supposed to be updating the surrounding pixels correctly but from my eyes it looks to be the exact same as without updating the neighbours.
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import static java.lang.Math.abs;
public class Dithering extends Canvas {
public BufferedImage ditheredIMG = new BufferedImage(481,480,
BufferedImage.TYPE_BYTE_GRAY);
public void paint(Graphics g) {
BufferedImage i = null;
try {
i = displayImage(g);
} catch (IOException e) {
throw new RuntimeException(e);
}
getPixels(g, i);
g.drawImage(ditheredIMG,480,0,this);
}
public static void main(String[] args) {
Dithering d = new Dithering();
JFrame f =new JFrame();
f.add(d);
f.setSize( 960,481);
f.setVisible(true);
}
public BufferedImage displayImage(Graphics g) throws IOException {
final File file = new File("Cat.jpg");
final BufferedImage i = ImageIO.read(file);
g.drawImage(i, 0,0,this);
return i;
}
public void getPixels(Graphics g, BufferedImage i) {
for (int y = 1; y < i.getHeight()-1; y++){
for (int x = 1; x < i.getWidth()-1; x++) {
int pixelValue = i.getRGB(x, y);
int red = (pixelValue & 0x00ff0000) >> 16;
int green = (pixelValue & 0x0000ff00) >> 8;
int blue = pixelValue & 0x000000ff;
int newRed = quantisePixel(red);
int newGreen = quantisePixel(green);
int newBlue = quantisePixel(blue);
int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;
ditheredIMG.setRGB(x,y,newPixel);
int newPixelValue = i.getRGB(x+1,y);
ditheredIMG.setRGB(x+1,y, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (7/16.0)));
newPixelValue = i.getRGB(x-1,y+1);
ditheredIMG.setRGB(x-1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (3/16.0)));
newPixelValue = i.getRGB(x,y+1);
ditheredIMG.setRGB(x,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (5/16.0)));
newPixelValue = i.getRGB(x+1,y+1);
ditheredIMG.setRGB(x+1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel)* (1/16.0)));
}
}
}
public int calculateErr(int oldVal, int newVal){
return oldVal-newVal;
}
public static int quantisePixel(int val){
if(val > 127){
return 255;
} else{
return 0;
}
}
}
I have a a lot of pixel art images that need to be scaled up to double the size.
It needs to be done so that each pixel in the image turns into a 2x2 set of pixels of the same exact same color, with no blending of colors.
example:
f I use ImageIO to read in a .png image as a BufferedImage with
BufferedImage foo = ImageIO.read(new File("C:\\path\\to\\image.png"));
how would I go about up-scaling it so it wont blend the pixels?
Hope it helps you
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageCovertTest {
public static void main(String[] args) throws IOException {
BufferedImage foo = ImageIO.read(new File("path/to/image"));
BufferedImage rs = cover(foo, 2);// cover X2
ImageIO.write(rs, "png", new File("path/to/output"));
}
private static int[][] convertToPixels(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel + 3 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel + 2 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
public static BufferedImage cover(BufferedImage image, int range) {
int[][] pixels = convertToPixels(image);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage imageResult = new BufferedImage(width* range, height* range, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width * range; x ++){
for (int y = 0; y < height * range; y++) {
imageResult.setRGB(x, y, pixels[y/ range][x/ range]);
}
}
return imageResult;
}
}
I want to layer two images together. A background and foreground. The foreground is stitched together as a grid of smaller images (3x3). I have been able to make all white pixels transparent as a workaround, however the inside of the shapes are white and I only want pixels outside the shapes transparent.
Say for example the grid of images contained a circle or square in each grid location. Is there a way I can iterate over each pixel and create two arrays of pixel locations - those outside the images making them transparent, and those inside the images where I can set the colour?
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
// Stitches a grid of images together, scales a background image to fit and layers them.
public class Layer {
public static void layerImages() {
// Grid layout of images to stitch.
int rows = 3;
int cols = 3;
int chunks = rows * cols;
int chunckWidth, chunkHeight;
// Image files to stitch
File[] imgFiles = new File[chunks];
for(int i = 0; i < chunks; i++) {
imgFiles[i] = new File("ocarina_sprite" + (i + 1) + ".png");
}
// Read images into array.
try {
BufferedImage[] buffImages = new BufferedImage[chunks];
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
}
chunckWidth = buffImages[0].getWidth();
chunkHeight = buffImages[0].getHeight();
BufferedImage finalImage = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);
// Calculate background width and height to cover stitched image.
int bwidth = 0;
int bheight = 0;
for(int i = 0; i < rows; i++) {
bwidth += buffImages[i].getWidth();
}
for(int i = 0; i < cols; i++) {
bheight += buffImages[i].getHeight();
}
// Background image
File dory = new File("dory.png");
BufferedImage original = ImageIO.read(dory);
// Scale background image.
BufferedImage background = scale(original, bwidth, bheight);
// Prepare final image by drawing background first.
Graphics2D g = finalImage.createGraphics();
g.drawImage(background, 0, 0, null);
// Prepare foreground image.
BufferedImage foreground = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);
// Stitch foreground images together
int num = 0;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < rows; j++) {
foreground.createGraphics().drawImage(buffImages[num],chunckWidth * j, chunkHeight * i, null);
num++;
}
}
// Set white pixels to transparent.
for (int y = 0; y < foreground.getHeight(); ++y) {
for (int x = 0; x < foreground.getWidth(); ++x) {
int argb = foreground.getRGB(x, y);
if ((argb & 0xFFFFFF) > 0xFFFFEE) {
foreground.setRGB(x, y, 0x00FFFFFF);
}
}
}
// Draw foreground image to final image.
Graphics2D g3 = finalImage.createGraphics();
g3.drawImage(foreground, 0, 0, null);
// Output final image
ImageIO.write(finalImage, "png", new File("finalImage.png"));
}
catch (Exception e) {
System.out.println(e);
}
}
// Scale image
public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight) {
BufferedImage scaledImage = null;
if (imageToScale != null) {
scaledImage = new BufferedImage(dWidth, dHeight, imageToScale.getType());
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
}
return scaledImage;
}
}
The floodfill solution mentioned in the comment was what I needed to solve the problem, however the recursion over a million+ pixels didn't work out so I implemented the forest fire algorithm which is floodfill using queues instead of recursion.
public static void forestFire(int width, int height, int x, int y) {
// Check if already set
int argb = foreground.getRGB(x, y);
if (((argb >> 24) & 0xFF) == 0) {
return;
}
coords.add(new Point(x, y));
// Set transparent pixel
foreground.setRGB(x, y, 0x00FFFFFF);
Point currentCoord = new Point();
while(!coords.isEmpty()) {
currentCoord.setLocation(coords.poll());
// Get current coordinates
x = (int)currentCoord.getX();
y = (int)currentCoord.getY();
// North
if(y != 0) {
int north = foreground.getRGB(x, y - 1);
// Check if transparent (already set) and check target colour (white)
if (((north >> 24) & 0xFF) > 0 && (north & 0xFFFFFF) > 0x111100) {
// Set transparent pixel
foreground.setRGB(x, y - 1, 0x00FFFFFF);
coords.add(new Point(x, y - 1));
}
}
// East
if(x != width - 1) {
int east = foreground.getRGB(x + 1, y);
if (((east >> 24) & 0xFF) > 0 && (east & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x + 1, y, 0x00FFFFFF);
coords.add(new Point(x + 1, y));
}
}
// South
if(y != height - 1) {
int south = foreground.getRGB(x, y + 1);
if (((south >> 24) & 0xFF) > 0 && (south & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x, y + 1, 0x00FFFFFF);
coords.add(new Point(x, y + 1));
}
}
// West
if(x != 0) {
int west = foreground.getRGB(x - 1, y);
if (((west >> 24) & 0xFF) > 0 && (west & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x - 1, y, 0x00FFFFFF);
coords.add(new Point(x - 1, y));
}
}
}
Programming Language: Java
I am trying to convert certain pixels of this image to a different color to reveal a "Secret Message."
Most of the pixels are:
Red = 0, Green = 64, Blue = 0
The pixels that I want changed to R = 255, G = 255, B = 255 are:
Red = 5, Green = 64, Blue = 5
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.awt.Color;
public class ASSN2p2
{
private static int makeRGBColor(int red, int green, int blue)
{
int rgb = 0;
rgb = red*65536 + green*256 + blue;
return rgb;
}
private static int getRed(int pixel)
{
return (pixel >> 16) & 0xFF;
}
private static int getGreen(int pixel)
{
return (pixel >> 8) & 0xFF;
}
private static int getBlue(int pixel)
{
return (pixel) & 0xFF;
}
public static void main(String args[]) throws IOException
{
// int width = 300;
// int height = 200;
BufferedImage image = null;
File f = null;
try
{
f = new File("D:\\2016-2017\\Fall2016\\201_CSCE_Programming\\Assignment 2\\secretmessage.png");
image = ImageIO.read(f);
image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
System.out.println("Reading Complete");
BufferedImage output = new BufferedImage(image.getWidth(), image.getHeight(),BufferedImage.TYPE_INT_ARGB);
//--------------------------------------
//-------------------------------------------
for (int y = 0; y < image.getHeight(); y++)
{
for (int x = 0; x < image.getWidth(); x++)
{
int pixel = image.getRGB(x, y);
int r,g,b;
r = getRed(pixel);
g = getGreen(pixel);
b = getBlue(pixel);
if ((r == 5) && (g == 64) && (b == 5))
{
r = 64;
b = 64;
b = 64;
image.setRGB(x,y,makeRGBColor(r,g,b));
} }
}
}
catch(IOException e)
{
System.out.println("Error: "+e);
}
// printPixelARGB(pixel);
// System.out.println("");
try
{
f = new File("D:\\2016-2017\\Fall2016\\201_CSCE_Programming\\Assignment 2\\output.png");
ImageIO.write(image, "png", f);
System.out.println("Writing Complete");
}
catch(IOException e)
{
System.out.println("Error: "+e);
}
}
}
This produces this:
I am having trouble understanding what has gone wrong!
Any assistance will be appreciated!
I believe that you're missing the alpha component of your new color. Change your code to:
private static int makeRGBColor(int red, int green, int blue) {
int rgb = 0xff000000 | (red << 16) | (green << 8) | blue;
return rgb;
}
to make sure that the alpha is set to full, otherwise your image will look completely transparent.
I'm trying to get the DCT of a bufferedImage using JTransform. When I visualise the transform it currently looks like this http://tinypic.com/r/2vcxhzo/8
In order to use Jtransform I need to convert the BufferedImage to a 2d double array. I've tried two different methods to change the bufferedImage to a double array
public double[][] convertTo2DArray(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster()
.getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
double[][] result = new double[height][width];
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
I've also tried
private double[][] bufferedImageToArray(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
int[][] array = new int[h][w];
double[][] result;
for (int count = 0; count < h; count++) {
for (int loop = 0; loop < w; loop++) {
int gray = image.getRGB(loop, count) & 0xFF;
// add values to array
array[count][loop] = gray;
}
}
result = toDoubleArray(array);
return result;
}
I've implemented the transform as
public double[][] applyDCT(double[][] image) {
DoubleDCT_2D transform = new DoubleDCT_2D(image.length, image[0].length);
transform.forward(image, true);
return image;
}
I tried using OpenCV's dct transform but it gives the same output as shown in the link.
Ty something like that (I kept only the blue channel for simplicity). It shows the energy compaction in the upper left corner of the result image.
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class TestDCT
{
public static void main(String[] args)
{
ImageIcon icon = new ImageIcon(args[0]);
Image image = icon.getImage();
int w = image.getWidth(null);
int h = image.getHeight(null);
GraphicsDevice gs = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(w, h, Transparency.OPAQUE);
img.getGraphics().drawImage(image, 0, 0, null);
int[] rgb1 = new int[w*h];
img.getRaster().getDataElements(0, 0, w, h, rgb1);
double[] array = new double[w*h];
for (int i=0; i<w*h; i++)
array[i] = (double) (rgb1[i] & 0xFF);
org.jtransforms.dct.DoubleDCT_2D tr = new org.jtransforms.dct.DoubleDCT_2D(w, h);
tr.forward(array, true);
for (int i=0; i<w*h; i++)
{
// Grey levels
int val= Math.min((int) (array[i]+128), 255);
rgb1[i] = (val <<16) | (val << 8) | val;
}
img.getRaster().setDataElements(0, 0, w, h, rgb1);
icon = new ImageIcon(img);
JFrame frame = new JFrame("FFT");
frame.setBounds(20, 30, w, h);
frame.add(new JLabel(icon));
frame.setVisible(true);
}
}