I have a problem with a Vector of BufferedImage objects. I'm trying to add BufferedImage objects into the Vector but the Vector is always empty. The ImageIo.read(input1) seems not working but I don't understand why.
Here's a part of my code :
private void drawPixel(int index,String name) throws IOException {
File input1 = new File("pince.png");
BufferedImage img = ImageIO.read(input1);
Graphics g = this.imagePoints.getGraphics();
imagePixelLabelBuffered.add(img);
input1.delete();
changeColorPixelLabel(imagePixelLabelBuffered.get(labelClassesCount-1),labelClassesCount-1);
File output = new File("pince.png");
//ImageIO.write(imagePixelLabelBuffered.get(labelClassesCount-1), "PNG", output);
int x = (index % this.width);
int y = (index / this.width);
g.drawImage(imagePixelLabelBuffered.get(labelClassesCount-1),x-20, y-31,100,100, null);
repaint();
}
My guess is that file "pince.png" is not in the current directory. I would recommend you to put your images in the classpath, and load them via Class.getResource() or getResourceAsStream().
You add the BufferedImage to the vector using imagePixelLabelBuffered.add(img) and you never modify the variable img, so your problem is not with the vector or the BufferedImage.
I do think your problem is in the line changeColorPixelLabel(imagePixelLabelBuffered.get(labelClassesCount-1),labelClassesCount-1) and more particularly with labelClassesCount-1. This variable is never updated, and it is simply useless. You can use the following line:
changeColorPixelLabel(img, imagePixelLabelBuffered.size()-1);
In Java, a List has a method size that returns the number of elements in the list.
Moreover, you never modify the variable img, so it's still a pointer on the BufferedImage you add to the Vector.
If you don't do parallelized (multi-threaded) operations, use an ArrayList instead of a Vector. A Vector is an ArrayList with synchronized operations, which is slower.
Same thing with the line g.drawImage(imagePixelLabelBuffered.get(labelClassesCount-1),x-20, y-31,100,100, null), you can use the variable img.
[EDIT] Here is a link for BufferedImage cloning.
Related
I am trying to retrieve an jpg image as a BufferedImage then decompose it into a 3D array [RED][GREEN][BLUE] and then turn it back into a BufferedImage and store it under a different file-name. All looks fine to me BUT, when I am trying to reload the 3D array using the new file created I get different values for RGB although the new image looks fine to the naked eye. I did the following.
BufferedImage bi = ImageIO.read(new File("old.jpg"));
int[][][] one = getArray(bi);
save("kite.jpg", one);
BufferedImage bi2 = ImageIO.read(new File("new.jpg"));
int[][][] two = getArray(bi2);
private void save(String destination, int[][][] in) {
try {
BufferedImage out = new BufferedImage(in.length, in[0].length, BufferedImage.TYPE_3BYTE_BGR);
for (int x=0; x<out.getWidth(); x++) {
for (int y = 0; y < out.getHeight(); y++) {
out.setRGB(x, y, new Color(in[x][y][0], in[x][y][1], in[x][y][2]).getRGB());
}
}
File f = new File("name");
ImageIO.write(out, "JPEG", f);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
so in the example above the values that arrays one and two are holding are different.
I am guessing there is something to do with the different types of retrieving and restoring images? I am trying to figure out what is going on all day but with no luck. Any help appreciated.
Pretty simple:
JPEG is a commonly used method of lossy compression for digital images
(from wikipedia).
Each time the image is compressed, the image is altered to reduce file-size. In fact repeating the steps of decompression and compression for several hundred times alters the image to the point where the entire image turns into a plain gray area in most cases. There are a few compressions that work lossless, but most operation-modes will alter the image.
I've been spending the last hours trying to solve the stack trace below. With major research on here SO and also through Google, I understand the exception can mean several things:
the program can't find the requested images with the provided path;
the images are being rendered after the width and the height are generated, reason why it equals 0...
Am I missing something? I can't figure out how to solve this...
Stack
Exception in thread "main" java.lang.IllegalArgumentException: Width
(-1) and height (-1) cannot be <= 0 at
java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016)
at java.awt.image.BufferedImage.(BufferedImage.java:331) at
tp6.Interface.toBufferedImage(Interface.java:157) at
tp6.Interface.(Interface.java:36) at
tp6.Interface.main(Interface.java:171)
tp6.Interface.toBufferedImage(Interface.java:157):
public BufferedImage toBufferedImage(Image image) {
if( image instanceof BufferedImage ) {
return( (BufferedImage)image );
} else {
image = new ImageIcon(image).getImage();
BufferedImage bufferedImage = new BufferedImage(
image.getWidth(null),
image.getHeight(null),
BufferedImage.TYPE_INT_RGB );
Graphics g = bufferedImage.createGraphics();
g.drawImage(image,0,0,null);
g.dispose();
return( bufferedImage );
}
}
tp6.Interface.(Interface.java:36)
//IMAGE JPANEL
Image map=new ImageIcon("images/main.gif").getImage();
Image digi=new ImageIcon("images/digits.gif").getImage();
BufferedImage mapmodifiable= toBufferedImage(map);
BufferedImage digits= toBufferedImage(digi);
tp6.Interface.main(Interface.java:171)
public static void main(String[] args)
{
Window windowintro = new Window( 440, 400, 1);
//INTERFACE GRAPHIC
Interface graphic=new Interface();
graphic.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
}
The reason for the exception has already been explained, Image methods getWidth(null) and getHeight(null) both return -1 when the image dimensions are not (yet) known. This is implemented so, because the old Image API in Java is asynchronous and loads image resources off the current thread. As you write, it could also happen because the image is not found.
However, as you want to use your images as BufferedImages (presumably because you want to modify them at some stage), it's better and easier to just load them using the more recent synchronous ImageIO API. In most cases, the code will be clearer and easier to understand, and more importantly; you'll get error messages right away if the image can't be found/loaded.
So, instead of:
Image map = new ImageIcon("images/main.gif").getImage();
BufferedImage mapmodifiable = toBufferedImage(map);
You can simply do:
BufferedImage mapmodifiable = ImageIO.read(new File("images/main.gif"));
PS: It is possible to convert an Image to a BufferedImage like you do in your toBufferedImage method, and using ImageIcon.getImage(..) should ensure the image was preloaded (ImageIcon internally uses a MediaTracker for preloading). However, as I say above, the old Image API is not very good at error feedback, so most likely the problem is that your image isn't found.
I was having this problem too. I solved it by adding one line of code. In your in the first line of your toBufferedImage() method you can put
while(image.getWidth() == -1);
This line will just keep looping until there is a value in getWidth() besides -1.
I found this question concerning your problem. Maybe you are using an asynchronous way to load the images. This mean the image may not be loaded yet, when you are calling getWidth(null) or getHeight(null). Since the image may not be loaded at this time, the width and height may not be known yet. This is the reason why -1 is returned.
Maybe you will get the right result if you add some delay with Thread.sleep(1000). I did not investigate it but it is definitively not a good solution. You may sleep not long enough on some systems. On other systems you may sleep unnecessary long. And since I do not know the specification very well, it may even be a valid implementation of Java if Thread.sleep blocks the process from reading the image (Does someone know it?).
I would see two ways which could be used to solve the problem:
First solution
One solution would be to load the image with blocking IO. Just like descripted in the answers of the linked question.
Second solution
Another solution would be to use an ImageObserver:
int width = getWidth(new ImageObserver() {
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
// TODO use the width when the image is loaded and the size is known
}
});
if (width != -1) {
// TODO use the width, it is already known
}
i have 2D array to keep color component value :
p[pixel_value][red]
p[pixel_value][green]
p[pixel_value][blue]
i just dont know how to use them to make an image.
i read about setRGB, what i understand is i should mix all of them to become a RGBArray. then how to make it?
is it any better way to make an image without setRGB ? i need some explanation.
The method setRGB() can be used to set the color of a pixel of an already existing image. You can open an already existing image and set all the pixels of it, using the values stored in your 2D array.
You can do it like this:
BufferedImage img = ImageIO.read(new File("image which you want to change the pixels"));
for(int width=0; width < img.getWidth(); width++)
{
for(int height=0; height < img.getHeight(); height++)
{
Color temp = new Color(p[pixel_value][red], p[pixel_value][green], p[pixel_value][blue]);
img.setRGB(width, height, temp.getRGB());
}
}
ImageIO.write(img, "jpg", new File("where you want to store this new image"));
Like this, you can iterate over all the pixels and set their color accordingly.
NOTE: By doing this, you will lose your original image. This is just a way which I know.
What you need is a BufferedImage. Create a BufferedImage of type TYPE_3BYTE_BGR, if RGB is what you want, with a specified width and height.
QuickFact:
The BufferedImage subclass describes an Image with an accessible
buffer of image data.
Then, call the getRaster() method to get a WritableRaster
QuickFact:
This class extends Raster to provide pixel writing capabilities.
Then, use the setPixel(int x, int y, double[] dArray) method to set the pixels.
Update:
If all you want is to read an image, use the ImageIO.read(File f) method. It will allow you to read an image file in just one method call.
Somewhat SSCCE:
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
}
You want to manually set RGB values?
You need to know that since an int is 32bit it contains all 4 rgb values (1 for the transparency).
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
^Alpha ^red ^green ^blue
You can accomplish using 4 int values by the use of binary arithmetic:
int rgb = (red << 16) && () (green << 8) & (blue);
bufferedImage.setRGB(x, y, rgb);
IN the above you can add Alpha as well if needed. You just "push" the binary codes into the right places.
This is a question, wether I am using the right way or not. And by the right way, I mean, is there a more memory-efficient way to do this?
I use 1 image source:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = ImageIO.read(getClass().getResource(imgurl));
I draw the image in a paint() method. But sometimes I need to set the brightness:
public void setBrightness(float brightness)
{
RescaleOp rescaleOp = new RescaleOp(brightness, 15, null);
rescaleOp.filter(loadedimage, image);
}
So I read the same image, two times. One to have a 'final' BufferedImage (it's not really final... But I cannot use final in this context, because it needs to be used outside the constructor (which you can't see here, but it is)) which is used as template, and one to edit and draw.
More information: Before trying this way, I did this:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = loadedimage;
But when I edit the image, it edits the loadedimage as well. Pretty much because they're the same object.
So... Is there another way to set the brightness of this image, WITHOUT loading the same image two times?
The following would copy an image.
public static BufferedImage copy(BufferedImage img) {
Hashtable<?,?> properties = new Hashtable<>();
for (String propertyName : img.getPropertyNames()) {
properties.put(propertyName, img.getProperty(propertyName));
}
return new BufferedImage(img.getColorModel(),
img.copyData(null),
img.isAlphaPremultiplied(), properties);
}
The same thing can be achieved slower but simplier by creating an empty image, drawing in the createGraphics of it (not to forget dispose). If you need a Graphics2D to process the image, that might be an option too.
I am trying to use the underlying DataBufferByte of a BufferedImage of type TYPE_3BYTE_BGR to set pixel values as quick as possible.
Perhaps I am not understanding, but when I do the following...
byte[] imgBytes = ((DataBufferByte) img.getData().getDataBuffer()).getData();
... it seems as though I am getting a copy of the byte[] and not a reference. For example, if I run...
System.out.println(System.identityHashCode(imgBytes));
System.out.println(System.identityHashCode((DataBufferByte) img.getData().getDataBuffer()).getData());
... I get two clearly different object hashes. If I'm not mistaken, this indicates that I am not getting a reference to the underlying byte[] but rather a copy. If this is the case, how am I supposed to edit the DataBufferByte directly???
Or perhaps I am just setting the pixels wrong... When I set pixels in the imgBytes it doesn't seem to do anything to the BufferedImage. Once I get the byte[], I set each pixel value like so:
imgBytes[intOffset] = byteBlue;
imgBytes[intOffset+1] = byteGreen;
imgBytes[intOffset+2] = byteRed;
To me, this all seems fine. I can read pixels just fine this way so it seems I should be able to write them the same way!
I had the same problem. You may not use getData() but use getRaster() which gives you an array you can use to write to.
I once played around with pixel manipulations for Images in Java. Instead of directly answering your question I will offer an alternative solution to your problem. You can do the following to create an array of pixels to manipulate:
final int width = 800;
final int height = 600;
final int[] pixels = new int[width * height]; // 0xAARRGGBB
MemoryImageSource source = new MemoryImageSource(width, height, pixels, 0, width);
source.setAnimated(true);
source.setFullBufferUpdates(true);
Image image = Toolkit.getDefaultToolkit().createImage(source);
image.setAccelerationPriority(1f);
Then to draw the image, you can simply call the drawImage method from the Graphics class.
There are a few other ways to achieve what you are looking for, but this method was the simplest to me.
Here is how it's implemented in JDK7. You may have an error somewhere else if the stuff doesn't work for you.
public byte[] getData() {
theTrackable.setUntrackable();
return data;
}