I am working on a 2D platform game and I have a sprite sheet which includes the sprites of tiles and blocks.
I noticed that there was a pink-ish background behind the transparent sprites so I thought that Java wasn't loading the sprites as PNG and I tried to re-draw the sprite on a new bufferedImage, pixel by pixel checking if the pixel was R=255, G=63, B=52 but unfortunately, the code wasn't able to detect that either and at this point I have no more options left to try.
I made sure that the "pink" color values are correct by using a color picker.
original spritesheet (transparent):
The class that loads the sprite(s) is:
public class SpriteSheet {
private BufferedImage image;
public SpriteSheet(BufferedImage image) {
this.image = image;
}
public BufferedImage grabImage(int col, int row, int width, int height) {
BufferedImage alpha = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = image.getSubimage(
(col * width) - width,
(row * height) - height,
width,
height);
int w = img.getWidth();
int h = img.getHeight();
for(int y = 0; y < h; y++) {
for(int x = 0; x < w; x++) {
int pixel = img.getRGB(x, y);
int red, green, blue;
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel) & 0xff;
if(red == 255 && green == 63 && blue == 52)
alpha.setRGB(x, y, new Color(0, 0, 0, 0).getRGB());
else
alpha.setRGB(x, y, pixel);
}
}
return alpha;
}
}
the class that loads the sprite sheet is:
public class Texture {
SpriteSheet bs, ss;
private BufferedImage block_sheet = null;
public BufferedImage[] block = new BufferedImage[3];
public Texture() {
BufferedImageLoader loader = new BufferedImageLoader();
try {
block_sheet = loader.loadImage("/tiles.png");
} catch(Exception e) {
e.printStackTrace();
}
bs = new SpriteSheet(block_sheet);
getTextures();
}
private void getTextures() {
block[0] = bs.grabImage(1, 1, 32, 32);
block[1] = bs.grabImage(2, 1, 32, 32);
block[2] = bs.grabImage(4, 1, 32, 32);
}
}
How do I get rid of the pink-ish background and keep transparency?
I dont understand why you're using subImage.
try {
BufferedImage img = ImageIO.read(new File("D:/image.png"));
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
Color pixelcolor = new Color(img.getRGB(i, j));
int r = pixelcolor.getRed();
int g = pixelcolor.getGreen();
int b = pixelcolor.getBlue();
if (r == 255 && g == 63 && b == 52) {
int rgb = new Color(255, 255, 255).getRGB();
img.setRGB(i, j, rgb);
}
}
}
ImageIO.write(img, "png", new File("D:/transparent.png"));
} catch (Exception e) {
System.err.println(e.getMessage());
}
cough, It worked all along, I had forgotten to disable the test blocks which was representing the blocks. Realized this after some time.
So the transparency was working fine. I just saw the rectangle i was drawing behind it.
Related
I was trying to change a color in my BufferedImage using this function:
public LoadedImage replaceColor(Color color1, Color color2) {
for (int y = 0; y < this.image.getHeight(); y++) {
for (int x = 0; x < this.image.getWidth(); x++) {
int pixel = this.image.getRGB(x, y);
Color col = new Color(pixel);
if (col.getRGB() == color1.getRGB()) {
this.image.setRGB(x, y, color2.getRGB());
}
}
}
return this;
}
(this.image is the BufferedImage, this is a class that contains the BufferedImage)
This is the result that I get:
This is the result I want:
This is the image I am using:
(the gray is the background btw)
Why doesn't this work? The image gives different results when I change it to green or blue.
Here is the code that I am using:
BufferedImage img = null;
try {
img = ImageIO.read(new File("img/" + image));
} catch (IOException e) {
e.printStackTrace();
}
Color color1 = new Color(255, 255, 255, 255);
Color color2 = new Color(255, 0, 0, 255);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = img.getRGB(x, y);
Color col = new Color(pixel);
if (col.getRGB() == color1.getRGB()) {
img.setRGB(x, y, color2.getRGB());
}
}
}
I would like to know how to isolate a certain color in an image and set the rest to gray using java.
So far I managed to do so, but in a hardcode way by looping through all the pixels of the image and then checking the RGB values.
I am using BufferedImage to load the image and the Color class to deal with RGB values.
The isColorRed checks if the color is red or not.
private static boolean isColorRed(Color color) {
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
return ((red >= 70 && red <= 255) && (green >= 0 && green <= 80) && (blue >= 0 && blue <= 80));
}
The isolateColor method is responsible to set all pixels to grey except for the red ones.
private static void isolateColor(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Color c = new Color(image.getRGB(x, y));
if (!isColorRed(c)) {
int red = (int) (c.getRed() * 0.3);
int green = (int) (c.getGreen() * 0.587);
int blue = (int) (c.getBlue() * 0.114);
int gray = red + green + blue;
Color newColor = new Color(gray, gray, gray);
image.setRGB(x, y, newColor.getRGB());
} else {
Color newColor = new Color(c.getRed(), c.getGreen(), c.getBlue());
image.setRGB(x, y, newColor.getRGB());
}
}
}
File file;
try {
file = new File("src/grey.png");
ImageIO.write(image, "png", file);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
The original image :
After the treatment :
Is there any API built-in or external that can isolate one color or more in a single image
I'm trying to create a program that, when selecting an image, reverses the colors of the image.
But when I run the code, my BufferedImage changes the RGB I assigned earlier.
I leave you the code that reverses the image.
image is a static BufferedImage.
public static void saveImage(File input, File output) throws IOException{
image = ImageIO.read(input);
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
boolean isTransparent = isTransparent(x, y);
if (!isTransparent) {
Color color = new Color(image.getRGB(x, y));
int r = 255 - color.getRed();
int g = 255 - color.getGreen();
int b = 255 - color.getBlue();
color = new Color(r, g, b);
int rgb = color.getRGB();
image.setRGB(x, y, rgb);
System.out.println(rgb+" --> "+image.getRGB(x, y));
}
}
}
ImageIO.write(image, "png", output);
}
public static boolean isTransparent(int x, int y) {
int pixel = image.getRGB(x, y);
return (pixel >> 24) == 0x00;
}
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));
}
}
}
My real goal is to read the values from a graph in GIF format, into some meaningful data structure but in order to get started I need to be able to read the colour of each pixel of the GIF in question.
In order to test this i want to save the segment of the GIF i am reading to file for visual analysis, but am having trouble.
after reading this post I attempted to do something similar, however my output GIF always comes out completely black.
can anyone tell me what i've misunderstood?
BufferedImage bi = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/commons/3/36/Sunflower_as_GIF.gif"));
int x = 100;
int y = 100;
int width = 100;
int height = 100;
int[] data = grabPixels(bi, x, y, width, height);
BufferedImage img = createImage(data, width, height);
ImageIO.write(img, "gif", new File("part.gif"));
...
private int[] grabPixels(BufferedImage img, int x, int y, int width, int height)
{
try
{
PixelGrabber pg = new PixelGrabber(img, x, y, width, height, true);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0)
throw new RuntimeException("image fetch aborted or errored");
return convertPixels((int[]) pg.getPixels(), width, height);
}
catch (InterruptedException e)
{
throw new RuntimeException("interrupted waiting for pixels", e);
}
}
public int[] convertPixels(int[] pixels, int width, int height)
{
int[] newPix = new int[width * height * 3];
int n = 0;
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
int pixel = pixels[j * width + i];
newPix[n++] = (pixel >> 16) & 0xff;
newPix[n++] = (pixel >> 8) & 0xff;
newPix[n++] = (pixel) & 0xff;
}
}
return newPix;
}
private BufferedImage createImage(int[] pixels, int width, int height)
{
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0, 0, width, height, pixels);
return image;
}
All black sounds like zeros, as if the image hadn't loaded yet. You might check the result returned by grabPixels() or specify a timeout. Once you have a BufferedImage, you could use getRaster() and work with the WritableRaster.