Image getWidth and getHeight returning -1 inappropriately - java

Why does this:
URL url = MinecraftPlatformGame.class.getResource("images/diamondPick.png");
image = Toolkit.getDefaultToolkit().getImage(url);
int width = image.getWidth(null);
int height = image.getHeight(null);
System.out.println(width);
System.out.println(height);
Return -1 for both the width and the height
Edit: My question before I figured out the answer was actually how I was supposed to fix it.
I fixed it by doing the following:
URL url = MinecraftPlatformGame.class.getResource("images/diamondPick.png");
image = Toolkit.getDefaultToolkit().getImage(url);
MediaTracker mTracker = new MediaTracker(this);
mTracker.addImage(image,1);
try {
mTracker.waitForID(1);
} catch (InterruptedException ex) {
Logger.getLogger(MinecraftPlatformGame.class.getName()).log(Level.SEVERE, null, ex);
}
int width = image.getWidth(null);
int height = image.getHeight(null);
System.out.println(width);
System.out.println(height);
url = MinecraftPlatformGame.class.getResource("images/gui.png");
image1 = Toolkit.getDefaultToolkit().getImage(url);
mTracker.addImage(image1,2);
try {
mTracker.waitForID(2);
} catch (InterruptedException ex) {
Logger.getLogger(MinecraftPlatformGame.class.getName()).log(Level.SEVERE, null, ex);
}
width = image1.getWidth(null);
height = image1.getHeight(null);
System.out.println(width);
System.out.println(height);
Problem I have now is this doesn't seem very efficient nor does it seem like I should need so much code just for two images to be imported and given sizes. Is there a better more efficient and easier way to do this?

Per the Javadoc:
If the width is not yet known, this method returns -1 and the
specified ImageObserver object is notified later.
In response to your edit, and following Russell's comment, use ImageIO.read() instead to get a fully-loaded image.

Related

Buffer Image width and height inverted values randomly

I need to know if an image is landscape oriented or not, for that i´m getting the width and height of a BufferImage but sometimes the values appear as inverted.
This is the code I use to detect if an image is landscape:
public class ProcessImage{
private static final String IMAGE_ORIENTATION_ERROR ="001";
public static void main(String[] args) {
try {
File file = new File("C:\\myFolder\\nothing.jpg");
byte[] fileContent = Files.readAllBytes(file.toPath());
BufferedImage image = createImageFromBytes(fileContent);
validateImage(image);
System.out.println(image.getWidth());
} catch (IOException | ImageOrientationException e) {
e.printStackTrace();
}
}
private static BufferedImage createImageFromBytes(byte[] imageData) {
ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
try {
return ImageIO.read(bais);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* Here is where i validate if the image is landscape
But Values of image.getWidth() and image.getHeight() appear as inverted.*/
private static void validateImage (BufferedImage image)
throws ImageOrientationException{
//if this happens the picture is NOT landscape
if (image.getWidth() < image.getHeight()) {
throw new ImageOrientationException(IMAGE_ORIENTATION_ERROR,
"error oriented picture");
}
}
}
The problem i'm having is that for some images the values of heigth and width are inverted .
For example, for an image which has a width of 3024 and a height of 4032 , the values of width and height the BufferImage returns are width: 4032 and height:3024. But if i edit the same image in Paint (respecting the original sizes) the BufferImage returns width:3024 and height: 4032 (As it should be).
I have tested with other images with the same width and height and the BufferImage gets the rigth values
Do you have any idea of why is this happening? Is there any way to know if the image is really landscape oriented?
Here is a link with the image which has the problem: http://www.mediafire.com/file/n1a8uhy195zgesd/nothing.jpg/file
Thanks in advance!

PNG Images and InputStream in Android

I need to decode an .png image to use it as a base to create some Rects and to use the image itself as a background for my application, but the try-catch keeps throwing me a Null Pointer Exception, this is the code:
try {
InputStream is = ParamsSingleton.assetManager.open("background.png");
figure = BitmapFactory.decodeStream(is);
height = figure.getHeight();
width = figure.getWidth();
src = new Rect(0, 0, width, height);
first = new Rect();
} catch (IOException e) {
Log.d(TAG, "Image decode fail!");
}
I've tried some logs and the try-catch break right on the InputStream line and prints the 'Log.d' in catch block, I checked the file name and it is alright.
You can directly use getAssets.open method inside decodeStream .
figure = BitmapFactory.decodeStream(getAssets.open("background.png"));

Decode specific areas of image in Bitmapfactory?

I'm working with GeoTiff/PNG files too large for handling as a whole in my code.
Is there any possibility to decode specific areas (e.g. given by two x,y coordinates) of a file in bitmapfactory? Haven't found anything looking similar at http://developer.android.com/reference/android/graphics/BitmapFactory.html(Android's developer reference).
Thanks!
With kcoppock's hint I've set up the following solution.
Though I'm wondering why rect needs to be initialized by Rect(left, bottom, right, top) instead of Rect(left, top, right, bottom)...
Example call:
Bitmap myBitmap = loadBitmapRegion(context, R.drawable.heightmap,
0.08f, 0.32f, 0.13f, 0.27f);
Function:
public static Bitmap loadBitmapRegion(
Context context, int resourceID,
float regionLeft, float regionTop,
float regionRight, float regionBottom) {
// Get input stream for resource
InputStream is = context.getResources().openRawResource(resourceID);
// Set options
BitmapFactory.Options opt = new BitmapFactory.Options();
//opt.inPreferredConfig = Bitmap.Config.ARGB_8888; //standard
// Create decoder
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(is, false);
} catch (IOException e) {
e.printStackTrace();
}
// Get resource dimensions
int h = decoder.getHeight();
int w = decoder.getWidth();
// Set region to decode
Rect region = new Rect(
Math.round(regionLeft*w), Math.round(regionBottom*h),
Math.round(regionRight*w), Math.round(regionTop*h));
// Return bitmap
return decoder.decodeRegion(region, opt);
}
You should look into BitmapRegionDecoder. It seems to describe exactly the use case that you are looking for.
I don't know exactly what you mean by "Decode specific areas" but if by decoding you mean, to actually "copy" certain areas of a bitmap, what you can do is make use of canvas in order to get it as shown below:
Bitmap bmpWithArea = Bitmap.createBitmap(widthDesired, heightDesired, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpWithArea);
Rect area = new Rect(arealeft, areatop, arearight, areabottom);
Rect actualSize = new Rect(0, 0, widthDesired, heightDesired);
canvas.drawBitmap(bitmapWithAreaYouWantToGet, area, actual, paintIfAny);
//And done, starting from this line "bmpWithArea" has the bmp that you wanted, you can assign it to ImageView and use it as regular bmp...
Hope this helps...
Regards!

Bitmap Memory Error Android

I am making an Android game, but when I load my Bitmaps, I get a memory error. I know that this is caused by a very large Bitmap (it's the game background), but I don't know how I could keep from getting a "Bitmap size extends VM Budget" error. I can't rescale the Bitmap to make it smaller because I can't make the background smaller. Any suggestions?
Oh yeah, and here's the code that causes the error:
space = BitmapFactory.decodeResource(context.getResources(),
R.drawable.background);
space = Bitmap.createScaledBitmap(space,
(int) (space.getWidth() * widthRatio),
(int) (space.getHeight() * heightRatio), false);
You're going to have to sample down the image. You can't "scale" it down smaller than the screen obviously, but for small screens etc it doesn't have to be as high resolution as it is for big screens.
Long story short you have to use the inSampleSize option to downsample. It should actually be pretty easy if the image fits the screen:
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final int dimension = Math.max(display.getHeight(), display.getWidth());
final Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
InputStream bitmapStream = /* input stream for bitmap */;
BitmapFactory.decodeStream(bitmapStream, null, opt);
try
{
bitmapStream.close();
}
catch (final IOException e)
{
// ignore
}
final int imageHeight = opt.outHeight;
final int imageWidth = opt.outWidth;
int exactSampleSize = 1;
if (imageHeight > dimension || imageWidth > dimension)
{
if (imageWidth > imageHeight)
{
exactSampleSize = Math.round((float) imageHeight / (float) dimension);
}
else
{
exactSampleSize = Math.round((float) imageWidth / (float) dimension);
}
}
opt.inSampleSize = exactSampleSize; // if you find a nearest power of 2, the sampling will be more efficient... on the other hand math is hard.
opt.inJustDecodeBounds = false;
bitmapStream = /* new input stream for bitmap, make sure not to re-use the stream from above or this won't work */;
final Bitmap img = BitmapFactory.decodeStream(bitmapStream, null, opt);
/* Now go clean up your open streams... : ) */
Hope that helps.
This may help you: http://developer.android.com/training/displaying-bitmaps/index.html
From the Android Developer Website, a tutorial on how to efficiently display bitmaps + other stuff. =]
I don't understand why are you using ImageBitmap? for background. If its necessary , its okay. Otherwise please use Layout and set its background because you are using background image.
This is important. (Check Android docs. They have clearly indicated this issue.)
You can do this in following way
Drawable d = getResources().getDrawable(R.drawable.your_background);
backgroundRelativeLayout.setBackgroundDrawable(d);
In most android devices the Intent size equals 16MB. You MUST Follow these instructions Loading Large Bitmap Efficiently

How to get image height and width using java?

Is there any other way besides using ImageIO.read to get image height and width?
Because I encounter an issue that locks up the thread.
at com.sun.medialib.codec.jpeg.Decoder.njpeg_decode(Native Method)
at com.sun.medialib.codec.jpeg.Decoder.decode(Decoder.java:87)
at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader.decode(CLibJPEGImageReader.java:73)
- locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)
at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.getImage(CLibImageReader.java:320)
- locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)
at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.read(CLibImageReader.java:384)
- locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)
at javax.imageio.ImageIO.read(ImageIO.java:1400)
at javax.imageio.ImageIO.read(ImageIO.java:1322)
This error only occurs on a Sun app server and therefore I suspect that it is a Sun bug.
Here is something very simple and handy.
BufferedImage bimg = ImageIO.read(new File(filename));
int width = bimg.getWidth();
int height = bimg.getHeight();
This is a rewrite of the great post by #Kay, which throws IOException and provides an early exit:
/**
* Gets image dimensions for given file
* #param imgFile image file
* #return dimensions of image
* #throws IOException if the file is not a known image
*/
public static Dimension getImageDimension(File imgFile) throws IOException {
int pos = imgFile.getName().lastIndexOf(".");
if (pos == -1)
throw new IOException("No extension for file: " + imgFile.getAbsolutePath());
String suffix = imgFile.getName().substring(pos + 1);
Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
while(iter.hasNext()) {
ImageReader reader = iter.next();
try {
ImageInputStream stream = new FileImageInputStream(imgFile);
reader.setInput(stream);
int width = reader.getWidth(reader.getMinIndex());
int height = reader.getHeight(reader.getMinIndex());
return new Dimension(width, height);
} catch (IOException e) {
log.warn("Error reading: " + imgFile.getAbsolutePath(), e);
} finally {
reader.dispose();
}
}
throw new IOException("Not a known image file: " + imgFile.getAbsolutePath());
}
I guess my rep is not high enough for my input to be considered worthy as a reply.
I tried to test performance using some of the various approaches listed. It's hard to make a rigorous test as many factors affect the result. I prepared two folders, one with 330 jpg files and another one with 330 png files. The average file size was 4Mb in both cases. Then I called getDimension for each file. Each implementation of getDimension method and each image type was tested separately (separate run). Here is the execution times that I got (first number for jpg, second number for png):
1(Apurv) - 101454ms, 84611ms
2(joinJpegs) - 471ms, N/A
3(Andrew Taylor) - 707ms, 68ms
4(Karussell, ImageIcon) - 106655ms, 100898ms
5(user350756) - 2649ms, 68ms
It's obvious that some methods load the whole file in order to get dimensions while others get by just reading some header information from the image. I think these numbers may be useful when application performance is critical.
Thank you everyone for the contribution to this thread - very helpful.
I have found another way to read an image size (more generic).
You can use ImageIO class in cooperation with ImageReaders.
Here is the sample code:
private Dimension getImageDim(final String path) {
Dimension result = null;
String suffix = this.getFileSuffix(path);
Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
if (iter.hasNext()) {
ImageReader reader = iter.next();
try {
ImageInputStream stream = new FileImageInputStream(new File(path));
reader.setInput(stream);
int width = reader.getWidth(reader.getMinIndex());
int height = reader.getHeight(reader.getMinIndex());
result = new Dimension(width, height);
} catch (IOException e) {
log(e.getMessage());
} finally {
reader.dispose();
}
} else {
log("No reader found for given format: " + suffix));
}
return result;
}
Note that getFileSuffix is method that returns extension of path without "." so e.g.: png, jpg etc.
Example implementation is:
private String getFileSuffix(final String path) {
String result = null;
if (path != null) {
result = "";
if (path.lastIndexOf('.') != -1) {
result = path.substring(path.lastIndexOf('.'));
if (result.startsWith(".")) {
result = result.substring(1);
}
}
}
return result;
}
This solution is very quick as only image size is read from the file and not the whole image. I tested it and there is no comparison to ImageIO.read performance. I hope someone will find this useful.
You can load jpeg binary data as a file and parse the jpeg headers yourself. The one you are looking for is the 0xFFC0 or Start of Frame header:
Start of frame marker (FFC0)
* the first two bytes, the length, after the marker indicate the number of bytes, including the two length bytes, that this header contains
* P -- one byte: sample precision in bits (usually 8, for baseline JPEG)
* Y -- two bytes
* X -- two bytes
* Nf -- one byte: the number of components in the image
o 3 for color baseline JPEG images
o 1 for grayscale baseline JPEG images
* Nf times:
o Component ID -- one byte
o H and V sampling factors -- one byte: H is first four bits and V is second four bits
o Quantization table number-- one byte
The H and V sampling factors dictate the final size of the component they are associated with. For instance, the color space defaults to YCbCr and the H and V sampling factors for each component, Y, Cb, and Cr, default to 2, 1, and 1, respectively (2 for both H and V of the Y component, etc.) in the Jpeg-6a library by the Independent Jpeg Group. While this does mean that the Y component will be twice the size of the other two components--giving it a higher resolution, the lower resolution components are quartered in size during compression in order to achieve this difference. Thus, the Cb and Cr components must be quadrupled in size during decompression.
For more info about the headers check out wikipedia's jpeg entry or I got the above info here.
I used a method similar to the code below which I got from this post at the sun forums:
import java.awt.Dimension;
import java.io.*;
public class JPEGDim {
public static Dimension getJPEGDimension(File f) throws IOException {
FileInputStream fis = new FileInputStream(f);
// check for SOI marker
if (fis.read() != 255 || fis.read() != 216)
throw new RuntimeException("SOI (Start Of Image) marker 0xff 0xd8 missing");
Dimension d = null;
while (fis.read() == 255) {
int marker = fis.read();
int len = fis.read() << 8 | fis.read();
if (marker == 192) {
fis.skip(1);
int height = fis.read() << 8 | fis.read();
int width = fis.read() << 8 | fis.read();
d = new Dimension(width, height);
break;
}
fis.skip(len - 2);
}
fis.close();
return d;
}
public static void main(String[] args) throws IOException {
System.out.println(getJPEGDimension(new File(args[0])));
}
}
Simple way:
BufferedImage readImage = null;
try {
readImage = ImageIO.read(new File(your path);
int h = readImage.getHeight();
int w = readImage.getWidth();
} catch (Exception e) {
readImage = null;
}
Having struggled with ImageIO a lot in the past years, I think Andrew Taylor's solution is by far the best compromise (fast: not using ImageIO#read, and versatile). Thanks man!!
But I was a little frustrated to be compelled to use a local file (File/String), especially in cases where you want to check image sizes coming from, say, a multipart/form-data request where you usually retrieve InputPart/InputStream's. So I quickly made a variant that accepts File, InputStream and RandomAccessFile, based on the ability of ImageIO#createImageInputStream to do so.
Of course, such a method with Object input, may only remain private and you shall create as many polymorphic methods as needed, calling this one. You can also accept Path with Path#toFile() and URL with URL#openStream() prior to passing to this method:
private static Dimension getImageDimensions(Object input) throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) { // accepts File, InputStream, RandomAccessFile
if(stream != null) {
IIORegistry iioRegistry = IIORegistry.getDefaultInstance();
Iterator<ImageReaderSpi> iter = iioRegistry.getServiceProviders(ImageReaderSpi.class, true);
while (iter.hasNext()) {
ImageReaderSpi readerSpi = iter.next();
if (readerSpi.canDecodeInput(stream)) {
ImageReader reader = readerSpi.createReaderInstance();
try {
reader.setInput(stream);
int width = reader.getWidth(reader.getMinIndex());
int height = reader.getHeight(reader.getMinIndex());
return new Dimension(width, height);
} finally {
reader.dispose();
}
}
}
throw new IllegalArgumentException("Can't find decoder for this image");
} else {
throw new IllegalArgumentException("Can't open stream for this image");
}
}
}
You could use the Toolkit, no need for ImageIO
Image image = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath());
int width = image.getWidth(null);
int height = image.getHeight(null);
If you don't want to handle the loading of the image do
ImageIcon imageIcon = new ImageIcon(file.getAbsolutePath());
int height = imageIcon.getIconHeight();
int width = imageIcon.getIconWidth();
Problem with ImageIO.read is that it is really slow. All you need to do is to read image header to get the size. ImageIO.getImageReader is perfect candidate.
Here is the Groovy example, but the same thing applies to Java
def stream = ImageIO.createImageInputStream(newByteArrayInputStream(inputStream))
def formatReader = ImageIO.getImageWritersByFormatName(format).next()
def reader = ImageIO.getImageReader(formatReader)
reader.setInput(stream, true)
println "width:reader.getWidth(0) -> height: reader.getHeight(0)"
The performance was the same as using SimpleImageInfo java library.
https://github.com/cbeust/personal/blob/master/src/main/java/com/beust/SimpleImageInfo.java
You can get width and height of image with BufferedImage object using java.
public void setWidthAndHeightImage(FileUploadEvent event) {
byte[] imageTest = event.getFile().getContents();
baiStream = new ByteArrayInputStream(imageTest);
BufferedImage bi = ImageIO.read(baiStream);
//get width and height of image
int imageWidth = bi.getWidth();
int imageHeight = bi.getHeight();
}
To get a Buffered Image with ImageIO.read is a very heavy method, as it's creating a complete uncompressed copy of the image in memory. For png's you may also use pngj and the code:
if (png)
PngReader pngr = new PngReader(file);
width = pngr.imgInfo.cols;
height = pngr.imgInfo.rows;
pngr.close();
}
public static Optional<Dimension> getImageDimensions(Path imageFile) {
Optional<String> suffixOpt = getExtension(imageFile);
Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffixOpt.orElse(""));
while (iter.hasNext()) {
ImageReader reader = iter.next();
try (ImageInputStream stream = new FileImageInputStream(imageFile.toFile())) {
reader.setInput(stream);
return Optional.of(new Dimension(reader.getWidth(reader.getMinIndex()),
reader.getHeight(reader.getMinIndex())));
} catch (IOException e) {
log.warn("Error reading: " + imageFile, e); //or however you want to handle the exception
} finally {
reader.dispose();
}
}
return Optional.empty();
}
public static Optional<String> getExtension(Path file) {
int pos = file.getFileName().toString().lastIndexOf(".");
if (pos == -1) {
return Optional.empty();
}
return Optional.of(file.getFileName().toString().substring(pos + 1));
}
Revised the method by #Andrew Taylor to use Optionals.
Also uses the Java's NIO Path to make the transition to Path.getExt easier in Java 21 (the second method can be removed and getExtension(imageFile) can be replaced with imageFile.getExtension()).
Also uses the try-with-resources design from Java.
One could instead use an external library in place of the second method if that's preferable.
Using a Spliterator could be another way, though in the end the code became more verbose as little is gained by converting from an Iterator.
So unfortunately, after trying all the answers from above, I did not get them to work after tireless times of trying. So I decided to do the real hack myself and I go this to work for me. I trust it would work perfectly for you too.
I am using this simple method to get the width of an image generated by the app and yet to be upload later for verification :
Pls. take note : you would have to enable permissions in manifest for access storage.
/I made it static and put in my Global class so I can reference or access it from just one source and if there is any modification, it would all have to be done at just one place. Just maintaining a DRY concept in java. (anyway) :)/
public static int getImageWidthOrHeight(String imgFilePath) {
Log.d("img path : "+imgFilePath);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imgFilePath, o);
int width_tmp = o.outWidth, height_tmp = o.outHeight;
Log.d("Image width : ", Integer.toString(width_tmp) );
//you can decide to rather return height_tmp to get the height.
return width_tmp;
}
To get size of emf file without EMF Image Reader you can use code:
Dimension getImageDimForEmf(final String path) throws IOException {
ImageInputStream inputStream = new FileImageInputStream(new File(path));
inputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
// Skip magic number and file size
inputStream.skipBytes(6*4);
int left = inputStream.readInt();
int top = inputStream.readInt();
int right = inputStream.readInt();
int bottom = inputStream.readInt();
// Skip other headers
inputStream.skipBytes(30);
int deviceSizeInPixelX = inputStream.readInt();
int deviceSizeInPixelY = inputStream.readInt();
int deviceSizeInMlmX = inputStream.readInt();
int deviceSizeInMlmY = inputStream.readInt();
int widthInPixel = (int) Math.round(0.5 + ((right - left + 1.0) * deviceSizeInPixelX / deviceSizeInMlmX) / 100.0);
int heightInPixel = (int) Math.round(0.5 + ((bottom-top + 1.0) * deviceSizeInPixelY / deviceSizeInMlmY) / 100.0);
inputStream.close();
return new Dimension(widthInPixel, heightInPixel);
}

Categories

Resources