When a spaceship is destroyed I create list containg pixels of spaceship's image. Pixels are objects of my Pixel class. After creating list it's added to main list where various actions are performed on them. This is how my code looks like:
//Code which creates an array
List<Pixel> pixels = new LinkedList<>();
BufferedImage buff = (BufferedImage)image;
for (int px = 0; px < buff.getWidth(); px++) {
for (int py = 0; py < buff.getHeight(); py++) {
int rgb = buff.getRGB(px, py);
int red = (rgb & 0x00ff0000) >> 16;
int green = (rgb & 0x0000ff00) >> 8;
int blue = rgb & 0x000000ff;
int alpha = (rgb >> 24) & 0xff;
if (alpha == 255) {
pixels.add(new Pixel(px, py, red, green, blue));
}
}
}
//Pixel class constructor
Pixel(float x, float y, int red, int green, int blue) {
super(x, y);
BufferedImage buff = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = buff.getRaster();
//LOOKS EVERYTHING IS OKAY SINCE THIS LINE SO THE ERROR MUST BE SOMEWHERE IN THOSE 2 LINES
raster.setPixel(0, 0, new int[]{red, blue, green, 255});
image = buff;
}
Short explanation: image is private field of type Image. It's used in repaint() method which paints pixel using drawImage() method. And about my problem: Eveything works almost okay. Pixels are creating on right position but all are violet-color. They have different tones(brighter and darker) but are all violet instead of having the same colors as image's colors! Why is this happening? Why violet? Could someone help me unserstand this strange behaviour?
It's probably a mixup of green and blue values in your setPixel method. Colors are usually given in RGB order, which is how you unpacked them from your BufferedImage.
Instead of
raster.setPixel(0, 0, new int[]{red, blue, green, 255});
try
raster.setPixel(0, 0, new int[]{red, green, blue, 255});
If that doesn't work you may have to tinker with different variable orders in your array until it looks right.
Related
Now i am able to apply pixel of another image to source image pixel of pg to m. but problem is that i m loosing gradient or fading effect.
public static void main(String[] args){
try {
BufferedImage image = ImageIO.read(new File("c:\\m.png"));
BufferedImage patt = ImageIO.read(new File("c:\\pg.png"));
int f = 0;
int t = 0;
int n = 0;
BufferedImage bff = 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 argb = image.getRGB(x, y);
int nrg = patt.getRGB(x, y);
if(((argb>>24) & 0xff) == 0) {
bff.setRGB(x, y, (255<<24));
} else {
bff.setRGB(x, y, nrg);
}
}
}
System.out.println("Trans : " + t + " Normal : " + n);
File outputfile = new File("c://imagetest.png");
ImageIO.write(bff, "png", outputfile);
} catch (IOException ex) {
}
}
thanks.
0xff000000 is opaque black, 0x00000000 is completely transparent.
What is 0 (the colour you chose)?
Yes, it's transparent.
Try 0xff000000 or even better: argb ^ 0xff000000, which just changes the transparency, instead.
if(((argb>>24) & 0xff) == 0) {
bff.setRGB(x, y, argb ^ 0xff000000);
} else {
bff.setRGB(x, y, argb);
}
For BufferedImage.setRGB(int x, int y, int rgb) the rgb value is made up as follows:
11111111 11111111 11111111 11111111
Alpha Red Green Blue
In your code you test the following:
if (((argb >> 24) & 0xff) == 0)
which tests for an Alpha value of 0, thus completely transparent.
When you find it to be true, you then set the rgb value to 0 with
bff.setRGB(x, y, 0);
So you are setting it to transparent again.
Change that to
bff.setRGB(x, y, (255<<24));
or
bff.setRGB(x, y, 0xff000000); //This should be better
which will change it to an opaque black pixel. This will have a binary value of
11111111000000000000000000000000
Edit: Moritz Petersen's solution should work better as it retains the pixel's colour while removing transparency.
If you would like to set it to a specific colour you could do:
bff.setRGB(x, y, 0xffff0000); // red
bff.setRGB(x, y, 0xff00ff00); // green
bff.setRGB(x, y, 0xff0000ff); // blue
or any combination of red, green and blue values.
I'm wondering how a person could change the alpha transparency of a color, if given the hex color code. For example if given
Color.red.getRGB()
how could I change it's alpha to 0x80?
To put this in context, I'm working on a static method to tint a BufferedImage, by creating a graphics device from the given image, and rendering a half transparent mask with that, disposing of the graphics, and returning the image. It works, but you have to define the alpha yourself in the given hex color code. I want to give a Color object, and double between 0 and 1.0 to determine the intensity of the tinting. Here's my code so far:
public static Image tintImage(Image loadImg, int color) {
Image gImage = loadImg;
Graphics2D g = gImage.image.createGraphics();
Image image = new Image(new BufferedImage(loadImg.width, loadImg.height, BufferedImage.TYPE_INT_ARGB));
for(int x = 0; x < loadImg.width; x++) {
for(int y = 0; y < loadImg.height; y++) {
if(loadImg.image.getRGB(x, y) >> 24 != 0x00) {
image.image.setRGB(x, y, color);
}
}
}
g.drawImage(image.image, 0, 0, null);
g.dispose();
return gImage;
}
You can construct a new Color from the old one with the lower alpha.
Color cNew = new Color(cOld.getRed(), cOld.getGreen(), cOld.getBlue(), 0x80);
Using the Color(int r, int g, int b, int a) constructor.
I'm working on a simple image program where the user can alter the HSB values of an image. However, when I change the HSB values of an images and convert back to RGB, it seems to lose it's transparency or alpha values (it goes black where the transparency is). Here's what I have below (I've put the relevant parts together):
public static BufferedImage getEnhancedImagesHSB(BufferedImage image, float[] hsbOrg)
{
int height = image.getHeight();
int width = image.getWidth();
float[] hsb = new float[]{0,0,0,0};
int[] originalPixels = image.getRGB(0,0, width, height, null, 0, width);
int[] enhancedImagePixels = image.getRGB(0,0, width, height, null, 0, width);
for (int i = 0; i < originalPixels.length; i++)
{
Color c = new Color( originalPixels[i]);
int red =c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
hsb = Color.RGBtoHSB(red, green, blue, hsb);
hsb[ 3 ] = c.getAlpha() / 255f;
hsb[0] = (float)(hsb[0] +( hsbOrg[0]/360.0));//hue
hsb[1] *= (hsbOrg[1]/100);
if(hsb[1] > 1.0)
hsb[1] = (float)0.9;
hsb[2] *= (hsbOrg[2]/100);
if(hsb[2] > 1.0)
{hsb[2] = (float)0.9;}
enhancedImagePixels[i] = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
}
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB );
newImage.setRGB(0, 0, width, height, enhancedImagePixels, 0, width);
return newImage;
}
According to the docs getRGB(), setRGB() use the default RGB color model (TYPE_INT_ARGB) so the alpha values should be preserved. But changing the images HSB values results in the new buffered image having a black color where the transparency should be. How can I edit the images HSB values and then create a new image without losing the images transparency?
Edit:
Below is an image from before and after some random Hue, saturation and brightness has been applied. As you can see, the image has lost its transparency.
Color c2 = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
enhancedImagePixels[i] = new Color(c2.getRed(), c2.getGreen(), c2.getBlue(),
c.getAlpha());
Which is ugly. There seems to be no conversion for hsb[3] (alpha).
Using a image.getAlphaRaster() might be the solution.
Thanks to Joop Eggen for pointing me into the right direction. I wrote directly into the image raster (using setPixel()) the adjusted Hue, saturation, brightness and alpha values. Below is a great article discussing the subject matter.
Article.
I am making an image editing like program, and when I want to edit large images it really starts to slow down. What is a good way to edit large image quickly? This example adjusts the image's brightness, it works, but when I get large images such as 3456x2304 its really slow.
I have a slider, which calls this function every time it moves.
// Slider in a dialog box
private void sldBrightnessStateChanged(javax.swing.event.ChangeEvent evt) {
// Get the position of the slider
int val = sldBrightness.getValue();
// Set the text in the textbox
txtBrightness.setText("" + val);
// New Brightness class (see below)
Brightness adjustment = new Brightness();
adjustment.amount(val);
adjustment.applyFilter();
// get the result built by applyFilter();
Canvas.preview = Preview.getImage();
// Update main program
this.getParent().repaint();
}
Then the filter:
package pocketshop.graphics.adjustments;
import java.awt.image.BufferedImage;
import pocketshop.Canvas;
import pocketshop.graphics.Colors;
import pocketshop.graphics.Preview;
public class Brightness{
protected int amount = 0;
public void amount(int amount){
this.amount = amount;
}
public void applyFilter(){
int width = Canvas.image.getWidth();
int height = Canvas.image.getHeight();
int[] pixels = new int[width * height];
Canvas.image.getRGB(0, 0, width, height, pixels, 0, width);
for(int i = 0; i < pixels.length; i++){
int pixel = pixels[i];
//int pixel = Canvas.image.getRGB(x, y);
int red = Colors.red(pixel);
int green = Colors.green(pixel);
int blue = Colors.blue(pixel);
red += amount;
if(red > 255){
red = 255;
}else if(red < 0){
red = 0;
}
green += amount;
if(green > 255){
green = 255;
}else if(green < 0){
green = 0;
}
blue += amount;
if(blue > 255){
blue = 255;
}else if(blue < 0){
blue = 0;
}
pixels[i] = Colors.rgba(red, green, blue);
}
//BrightnessContrastDialog.preview.setRGB(0, 0, width, height, pixels, 0, width);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, width, height, pixels, 0, width);
Preview.setImage(img);
}
}
I have a slider, which calls this function every time it moves.
Don't adjust the image until the slider stops moving. I don't know Swing, but I'm betting there is a test for evt which says whether it is moving or has stopped.
The way you have it, applyFilter may be called 100 times or more as the slider is moved.
As I understand the picture is presented for user in order to give immediate feedback of changes that are made, what you can do us display downsampled version of picture and perform the brightness change to it while slider is moving which will be fast. Once user is satisfied with the value she selected using slider you can apply the change to original image. You can add apply button or something
I would suggest that you investigate OpenCL and its Java binding, JOCL. OpenCL is a library for interacting directly with the GPU on various different graphics cards. JOCL is a Java binding library for the OpenCL API.
Fair warning, this may be much more than you want to tackle, as you will be working at a much lower level than Swing.
I am not sure but it looks like you are using a BufferedImage of type BufferedImage.TYPE_INT_ARGB. This means that the BufferedImage is using a WritableRaster that is using a DataBuffer of type DataBufferInt. In its simplest form a DataBufferInt is nothing more than a wrapper around an int[]. If you can get a hold of the BufferedImage that the Canvas is using then get its WritableRaster and from there get the DataBufferInt:
WritableRaster raster = Canvas.image.getRaster();
DataBufferInt dataBuffer = (DataBufferInt)raster.getDataBuffer();
int[] pixels = dataBuffer.getData();
Now that you have the int[] that represents the pixels you can just loop over it and change the components:
for (int i = 0, len = pixels.len; i < len; ++i) {
int pixel = pixels[i];
int red = ((pixel & 0x00FF0000) >> 16) + amount;
if (red < 0) red = 0 else if (red > 255) red = 255;
int green = ((pixel & 0x0000FF00) >> 8) + amount;
if (green < 0) green = 0 else if (green > 255) green = 255;
int blue = (pixel & 0x000000FF) + amount;
if (blue < 0) blue = 0 else if (blue > 255) blue = 255;
pixels[i] = (pixels[i] & 0xFF000000) + (red << 16) + (green << 8) + blue;
}
This means that the pixels in the BufferedImage that the Preview has are being changed in-place without having to create another int[] of new pixels and another BufferedImage.
I am not sure if this will work but many times it helps in Java to cut out the middle-man and don't create as many objects.
If this does not work then look into Java Advanced Imaging.
I am reading pixel color in a BufferedImage as follows:
.....
InputStream is = new BufferedInputStream(conn.getInputStream());
BufferedImage image = ImageIO.read(is);
int color = image.getRGB(x, y);
int red = (colour & 0x00ff0000) >> 16;
int green = (colour & 0x0000ff00) >> 8;
int blue = colour & 0x000000ff;
Now this works fine except for png's with transparency. I find that if x,y refer to a transparent pixel with no color, i still read a color, generally the same color as used elsewhere in the image.
How do I detect that the pixel is actually transparent and not colored?
Thanks
int alpha = (colour>>24) & 0xff;
The result is also a value ranging from 0 (completely transparent) to 255 (completely opaque).