How can I retrieve the dimensions of an image (typically jpeg, png, jpg and gif), in the local filesystem with Java?
You can use java's image class to get image attributes. Here is the sample -
BufferedImage img = ImageIO.read(new File("imageFilePath"));
int height = img.getHeight();
int width = img.getWidth();
how about this: getting image metadata
Related
I am storing an Image in the filesystem like:
FileImageOutputStream fos = new FileImageOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
And all images are stored correctly in the filesystem. (Also with correct aspect ratio with width and height!)
However, later, I am loading my image like:
File imgFile ...
FileImageInputStream stream = new FileImageInputStream(imgFile);
BufferedImage srcImage = ImageIO.read(stream);
And I want to get the width and height for my images like:
int actualHeight = srcImage.getHeight();
int actualWidth = srcImage.getWidth();
This works totally fine for images in landscape format.
However, for images in upfront format, the width and height is always swapped, so that the width is the height of the orginial image. So, e.g. I have an image that is 200x500 (width x height) and the two integers above are actualHeight = 200 and actualWidth = 500.
Am I missing something?
Most likely, your images are Exif images ("Exif-in-JPEG") from a digital camera/phone. For such images, the pixel data is often stored in the "natural" orientation of the sensor, which is always the same (usually landscape). For portrait images, the orientation is only stored in the Exif metadata, and the ImageIO JPEG plugin doesn't take this orientation into account.
Some cameras, like my Canon DSLR, has an option to do in-camera rotation to match the orientation, but this feature is typically disabled by default. This is obviously only a possible fix if you control the input images.
To fix this in the Java side, you hava some options. You already mentioned using Thumbnailator:
BufferedImage srcImage = Thumbnails.of(new FileInputStream(imgFile))
.scale(1)
.asBufferedImage();
Another option is to use EXIFUtilities from TwelveMonkeys (I'm the author of that library):
IIOImage image = EXIFUtilities.readWithOrientation(imgFile);
BufferedImage srcImage = (BufferedImage) image.getRenderedImage();
Or, if you don't need the other metadata for anything:
BufferedImage srcImage = (BufferedImage) EXIFUtilities.readWithOrientation(imgFile)
.getRenderedImage();
how do I get the resolution of an image.
BufferedImage theBufferedImage = ImageIO.read(new File("/tmp/foo.jpg"));
int width = theBufferedImage.getWidth();
int height = theBufferedImage.getHeight();
int resolution = ???
Regards,
saromba
You can't get DPI or any other such information out of BufferedImage, you'll have to examine the original JPEG file for it. It's just a raster image without any metadata. If you're writing a BufferedImage to a file, you can set the DPI. But BufferedImage itself has no concept of DPI, it's just pixels.
i need to write a program which takes an image, resizes and rotates it and then saves it out. The first 2 point are done, but now I have a problem. Every time I convert a grayscale image it becomes a monochrome image.
I load the target image with the following command:
BufferedImage sourceimg = ImageIO.read(input);
And after I scaled and rotated it I save it out with the following command:
BufferedImage newimg = new BufferedImage(sourceimg.getHeight(), sourceimg.getWidth(), sourceimg.getType());
op.filter(sourceimg, newimg);
sourceimg = newimg;
ImageIO.write(sourceimg, "png", outputFile);
This works fine for every image except grayscale images. I have already tried a workaround by setting the type of every image to ARGB but there has to be another way. Is there a way to get the IndexColorModel of an given image?
The problem ist now solved, i just had to change:
BufferedImage newimg = new BufferedImage(sourceimg.getHeight(), sourceimg.getWidth(), sourceimg.getType());
to:
BufferedImage newimg = new BufferedImage(sourceimg.getWidth(), sourceimg.getHeight(), BufferedImage.TYPE_INT_ARGB);
There are other solutions, especially if you like to keep the original image type (ie. keep palette of IndexColorModel images etc.).
In fact, the easiest is to just do (assuming op is a standard BufferedImageOp):
BufferedImage newimg = op.filter(sourceimg, null);
Here a new, compatible image will be created for you, and will be of correct size to keep the result of the operation.
Another option, which will preserve the image type and color model, is slightly more verbose:
ColorModel sourceCM = sourceimg.getColorModel(); // Will be the IndexColorModel in your case
// I'm assuming you are deliberately switching width/height to rotate 90 deg
WritableRaster raster = sourceCM.createCompatibleWritableRaster(sourceimg.getHeight(), sourceimg.getWidth());
BufferedImage newimg = new BufferedImage(sourceCM, raster, sourceCM.isAlphaPremultiplied(), null);
op.filter(sourceimg, newimg);
I'm trying to write 16 bit grayscale imagedata to a png using BufferedImage.TYPE_USHORT_GRAY. Normally I write to an image like so:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
then:
image.setRGB(x,y,Color.getRGB);
to set the pixels, and finally:
ImageIO.write(image, "png", new File(path + ".png"));
to write to a png image.
But now I have this as image:
BufferedImage imageGray = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
How do I go about saving pixels to that format? Using setRGB() with a 16 bit integer doesn't seem to work, when I open the saved png file I see a lot of banding happening.
I tried saving a simple gradient from 0 to 65535 and then using the setRGB() on the grayscale image, and checked the results in Photoshop. I can see the image consists of smaller gradients every 256 rows. I'm guessing either setRGB() or imageIO doesn't work as I would like it to.
Are there workarounds for this? Does imageIO even support the BufferedImage.TYPE_USHORT_GRAY format? Or can it only save 8 bit data? And if it can save 16bit data, how would I go about saving pixel data, preferably in a way like setRGB() works (so for a certain x,y coordinate)?
As pst already commented below my question:
Try using the Raster directly?
Accessing the Raster directly solved the problem :
BufferedImage bi = BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY)
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Short s = shortData[x][y]
bi.getRaster().setDataElements(x, y, Short[] {s})
}
}
From BufferedImage you can read
public static final int TYPE_USHORT_GRAY
Represents an unsigned short grayscale image, non-indexed). This image has a ComponentColorModel with a CS_GRAY ColorSpace.
So try instantiating your own ColorSpace with the CS_GRAY type (ColorSpace.getInstance(ColorSpace.CS_GRAY) should do it I suppose). This object has a method called fromRGB which you should be able to use...
You probably need to widen the signed 16bit shorts to ints and remove the sign:
int ushort = (int)(shortData[x][y]) & 0xFFFF;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
short[] dataArray = ((DataBufferUShort)image.getRaster().getDataBuffer()).getData();
dataArray[y*width+x] = color;
ImageIO.write(image, "png", new File(path + ".png"));
how can i manipulate pixel values of a loaded image then save portion of that image into a new image(1 image per word).i found several example regarding saving or loading image but i cant understand how can i save image portion???i am trying to do it with java
I didn't tried it for myself. But studying this and that page leads me to this code:
BufferedImage im = ImageIO.read(new File("in.jpg"));
// now manipulate image
...
// now get only a part of it
Raster raster = im.getData(new Rectangle(xOffset, yOffset, width, height));
BufferedImage im2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
im2.setData(raster);
ImageIO.write(im2, "jpg", new File("out.jpg"));