getSize(), getWidth(), getHeight() returns -1 - java

I have an Image img that, when trying to use any of above mentioned get methods, returns -1. Why is this? And what is an ImageObserver object?

According to the documentation for Image, these methods return a -1 if the size, width, or height (respectively) are not yet known.
Also, ImageObserver is simply an interface that provides methods to get notifications about the information of an Image object that is being constructed.

You can use the MediaTrack to get your image's width & height like that :
// ...
Image img;
// ...
// ... loading the image using IO or Toolkit ot something
MediaTracker MTrack = new MediaTracker(this); // in my case, 'this' is a JFrame
MTrack.addImage(img,1);
try
{
MTrack.waitForID(1);
}
catch(InterruptedException e)
{
e.getMessage();
}
int width = img.getWidth(null);
int height = img.getHeight(null);
double ratio = (double)width/(double)height;
// ....
// ....

According to the Java docs, it seems that if you call getHeight() etc. on an Image while it's still in the construction phase, such that the height is not really "known", -1 is returned and the ImageObserver provided is notified.
ImageObserver is an interface that provides a way for you to have a callback method that is called when the image is updated in some way. ImageObserver is implemented by java.awt.Component, so if you extend that in the containing class you could override imageUpdated() and store the image height when the function is called asynchronously (if Image.getHeight returns -1).

In GraphTest, override imageUpdate:
#Override
public void imageUpdate(Image img, int flags,
int x, int y, int width, int height) {
if ((flags & (WIDTH|HEIGHT)) == (WIDTH|HEIGHT)) {
// width and height have meaningful values, do your resize here
}
super.imageUpdate(img, flags, x, y, width, height);
}

The problem is the time needed to load the Image.
As long as the image is not loaded you get the -1. When the image is finally loaded, it fires the ImageObserver. The obeserver, in your case the Background instance - g.drawImage(bkg, 0, 0, this); - will force a repaint of the Background causing the now loaded image to be painted.
You can also use the java.awt.MediaTracker to track the status of your Image.
[]]

Related

Scaled "straight line" image jumps out of line

a have a problem with scaling images up. I have a png file that looks like this:
raw png
The image is 8px * 8px and has some red straight lines on it.
But when i draw this image with java and scale it up this happens: java image
And as you can barly see, the line is not exactly straight. It is always one pixel off and makes this kind of wavy shape. If the image gets drawn somewhere else on the frame the "waves" are somewhere else. The image is rotated 90° but I tested it without rotation and it was still there. Apart from this I do need rotated images.
Is there any way to fix this? I enabled text-antialiasing in the same Graphics2D object. Is there also some sort of anitaliasing for this?
Code
private void loadImage(String path, int field, int imageNumber) {
BufferedImage image;
image = new Resource().readImg(path);
images[field][imageNumber][0] = image;
images[field][imageNumber][1] = rotateClockwise90(image);
images[field][imageNumber][2] = rotateClockwise90(rotateClockwise90(image));
images[field][imageNumber][3] = rotateClockwise90(rotateClockwise90(rotateClockwise90(image)));
}
private BufferedImage rotateClockwise90(BufferedImage src) {
int width = src.getWidth();
int height = src.getHeight();
BufferedImage dest = new BufferedImage(height, width, src.getType());
Graphics2D graphics2D = dest.createGraphics();
graphics2D.translate((height - width) / 2, (height - width) / 2);
graphics2D.rotate(Math.PI / 2, height / 2, width / 2);
graphics2D.drawRenderedImage(src, null);
return dest;
}
When the program starts I load the image I rotate it in all 4 directions, so I don't have to do this over and over again while the program is running.
public BufferedImage getTile(int type, int part, int rotation) {
return images[type][part][rotation];
}
And then all I have to do is calling this get method and draw the image:
g2d.drawImage(tiles.getShipTile(type, part, rotation), x, y, null);
I actually found a way to avoid these weird pixels but this method makes the image a little bit blurry.
Instead of using
g2d.drawImage(img, x, y, width, height, null);
you can simply use
g2d.drawImage(img.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING), x, y, null);
which does basically the same thing but wehn I scale it up it uses this smooth making key.
I tried this and noticed that its not verry comfortable because it lags a lot.
So I just scale it up in the beginning when I also rotate the images.
As I said this method is a bit blurry but if there are no other ways avoiding this problem I have to get use of this. You almost can't see the blur, so this would be an option for me.

Trying to add Image onto JFrame

Hello I'm trying to add an Image that I have on my desktop to my JFrame that I have created i have imported all the necessary functions and the correct variables the only trouble i have is with Image observer I set my x and y values for my image but it causes an error in my drawImage component and it asks for an Image observer which i don't know what it is and if i auto fill something my Image doesn't appear on my JFrame. If one of you can look at my code or answer what an Image observer does i would be greatly appreciated
public class Window2 extends JPanel {
// Image Import
ImageIcon i = new ImageIcon("C: / Class Pokemon Game/ src / GameTitle (1).psd");
Image title = i.getImage();
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.RED);
g.fillRect(0, 40, 5000, 20);
g.**drawImage**(title, 500, 500);
}
}
the error is
add argument to match 'drawImage(Image, int, int, ImageObserver)'
ImageObserver is an interface that has methods for handling notification of state of image loading. It can use this for redisplay as needed. JFrame and Applet both implement ImageObserver interface.
To keep users informed regarding the loading of an image
ImageObserver interface – Enables the monitoring of the loading process so that
users can be informed and the image can be used asap once it is loaded.
Loading an image asynchronously – how to know when the image is ready.
An image is ready – getImage() method returns, long before anything is
known about the image.
imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
Note: java.awt.Component implements ImageObserver, all the subclasses do as
well!
g.drawImage(imge, 0,0, this) -- this refers to the ImageObserver instance.
imageUpdate() – Called by the ImageObserver whenever necessary. You do not call
it explicitly!
If the image is complete, returns false.
If the image is not complete and needs to be updated, returns true.
ImageObserver.ALLBITS = 32
Various constants are combined to form the infoflags argument, which indicates
whether all information is available or not.
You can skip using an ImageObserver by putting it as null
for example (Using Graphics2D)
g2.drawImage(Image texture, x, y, width, height, null);

How to solve java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot be <= 0?

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
}

How to center GIF in Live Wallpaper

I am making a live wallpaper with a gif image that is put in the raw directory, how can I put the gif in the center of the screen, no matter what device I am using?? I understand why my code right now puts it in the left, because display.getWidth-display.getWidth =0, and same with height, hence (0,0) is in the top left. But what is center?! I cannot seem to figure it out for the life of me. This class is extending WallpaperService.
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
mScaleX = width / (1.5f*mNyan.width());
mScaleY = height / (1.5f*mNyan.height());
Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
mWidth = (display.getWidth()-display.getWidth());
mHeight = (display.getHeight()-display.getHeight());
nyan();
}
and this is the end where I draw the canvas...
void nyanNyan(Canvas canvas) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
mNyan.setTime(mWhen);
mNyan.draw(canvas, mWidth,mHeight);
canvas.restore();
}
Can anyone help!?! I'm stuck, and I can't move past this. I also tried, without any luck:
void nyanNyan(Canvas canvas) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
mNyan.setTime(mWhen);
mNyan.draw(canvas, mCenterX - mNyan.width() , mCenterY - mNyan.height());
}
As I do not fully understand your code (e.g. where vars like mCenterX are coming from or how they are defined) I can not gurantee the code to run properly without further adjustments.
Assuming that you have access to nyan's width and height (I'll call it nyan.getWidth()) and the canvas' dimensions, then your last mNyan.draw() call should probably look like this:
mNyan.draw(
canvas,
( canvas.getWidth() - nyan.getWidth() ) / 2,
( canvas.getHeight() - nyan.getHeight() ) / 2
);

Java fillRect() Inconsistencies

Suspicious fillRect() Speed
Okay so let me get this straight. Java fills rectangles by iterating through an array and changing the rgb values to a designated color. If all it does is change the color then why is Texturepaint so expensive if all it is doing is changing the integer in the array? Does changing the integer in between take time to register?
Fast fillRect() operation using setPaint(new Color());
setPaint(new Color(0,0,0));
fillRect(0,0,frame.getWidth(),frame.getHeight());
// Around 100+ fps repainting with timer set to zero milliseconds.
Slow fillRect() operation using setPaint(new TexturePaint());
setPaint(new TexturePaint(image, rectangle));
fillRect(0,0,frame.getWidth(),frame.getHeight());
// Around 20+ fps repainting with timer set to zero milliseconds.
As you can see from its sourcecode, Graphics delegates this functionality to subclasses.
My implementation seems to use SunGraphics2d, which again delegates it to a PixelFillPipe, which there are many implementations of. The OGLRenderer delegates this functionality to the Graphics card if possible, using OpenGL. The X11Renderer uses native X calls, like this:
native void XFillRect(long pXSData, long xgc,
int x, int y, int w, int h);
public void fillRect(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
SunToolkit.awtLock();
try {
long xgc = validate(sg2d);
XFillRect(sg2d.surfaceData.getNativeOps(), xgc,
x+sg2d.transX, y+sg2d.transY, width, height);
} finally {
SunToolkit.awtUnlock();
}
}
XRRenderer uses this code:
public synchronized void fillRect(SunGraphics2D sg2d,
int x, int y, int width, int height) {
SunToolkit.awtLock();
try {
validateSurface(sg2d);
XRSurfaceData xrsd = (XRSurfaceData) sg2d.surfaceData;
x += sg2d.transform.getTranslateX();
y += sg2d.transform.getTranslateY();
tileManager.addRect(x, y, width, height);
tileManager.fillMask(xrsd);
} finally {
SunToolkit.awtUnlock();
}
}
I showed you this code, because it is more than setting colors in an array. Your mileage will vary per platform and JRE.
As I don't know which renderer/fillpipe you use, I can only recommend to look at your very own code, it's not that hard.

Categories

Resources