I've to make a parallel image processing script in java, the idea is to divide the images into tiles of any size, process them, and reassemble the final image.
For now i've created a function:
public static BufferedImage readImg (String path, int startx, int starty, int w, int h)
that returns the region of an image as BufferedImage, then i'll process it and i want to place that region in the correct position of the final image.
So i've tried to make a function writeImg that uses replacePixels method to write just in the correct position without loading the whole image into memory:
public static void writeImg (String path, int startx, int starty, BufferedImage image){
File output = new File(path);
ImageOutputStream ios = null;
try {
ios = ImageIO.createImageOutputStream(output);
} catch (IOException e){
e.printStackTrace();
}
Iterator iter = ImageIO.getImageWritersByFormatName("JPEG");
ImageWriter writer = (ImageWriter)iter.next();
writer.setOutput(ios);
try{
if(writer.canReplacePixels(0)){
System.out.println("True");
}else{
System.out.println("False");
}
}catch (IOException e) {
e.printStackTrace();
}
ImageWriteParam param = writer.getDefaultWriteParam();
Point destinationOffset = new Point(startx,starty);
param.setDestinationOffset(destinationOffset);
try {
writer.replacePixels(image, param);
} catch (IOException e) {
e.printStackTrace();
}
}
The problem is that canReplacePixels is always set as false, and i've no idea what should i use to do that.
The images can be very big so it's impossible to load the whole image in memory as it will cause a OutOfMemory exception.
As long as you are fine with an 24 bit PNG file as output I have a working solution for you (under GPL license):
The class PngXxlWriter allows to write PNG files "line by line". That means that you can write an image of 10000x10000 (width * height) pixels in lines of e.g. 256 pixels (10000 * 256).
Usually this reduces the memory usage down to a level which is practically.
All required classes can be found here:
PngXxlWriter is the main class. By calling its method writeTileLine you can add a new line to the output image.
https://sourceforge.net/p/mobac/code/HEAD/tree/trunk/MOBAC/src/main/java/mobac/utilities/imageio/
Related
I try to draw an image from a bufferedImage into a PDF using PDFBox but fails, and I get black images and Acrobat Reader warns whith errors like "Out of memory" (but PDF is display).
I use a bufferedImage because I need to draw a JavaFX Image object (with came from call to Funciones.crearImagenDesdeTexto(), is a function which converts a text into an Image) into PDF. Rest of images works well without using bufferedimage.
PDPixelMap img = null;
BufferedImage bi;
try {
//If item has id, I try to get image with that id (image it's shows OK on PDF)
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + item.getId() + ".png")));
}
catch (Exception e) {
//If item has not id or fails load image, I create image on the fly (which contains item name. This not work on PDF, shows black images)
bi = new BufferedImage(alto, ancho, BufferedImage.TYPE_INT_ARGB);
bi.createGraphics().drawImage(SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(item.getNombre()), null), ancho, alto, null);
img = new PDPixelMap(documento, bi);
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
NOTE: crearImagenDesdeTexto() returns a JavaFX Image Object that is create on the fly (I try this function in other parts of the program and works well, function is take from other stackOverflow response).
Your code is confusing, you have three "new PDJpeg" and one of them is in a catch (which should just handle the error). And what does "read()" do? Does it pass a stream or a BufferedImage? If it is a stream, then it is wrong, because PDJpeg is for JPEGs, not for PNG.
The second one
img = new PDJpeg(documento, (getClass().getResourceAsStream("/com/img/" + Byte.toString(item.getId()) + ".png")));
is definitively wrong for the same reason: PDJPeg is not for PNG files / streams.
If you want to create an image from a PNG file / stream, use PDPixelMap.
It is possible to create a PDJpeg object from a BufferedImage, but this is recommended only if the image wasn't encoded before. Because if you would read a BufferedImage from a JPEG, and then use PDJPeg for this, you'll have a slight loss of quality as the image is decoded and encoded again (JPEG is a "lossy" compression format).
If my advice doesn't help, please upload the JPEG file and the PDF somewhere.
Also make sure that you're using the latest version, which is 1.8.7.
Update after comments:
the parameters to createGraphics.drawImage() should be 0, 0 and not width, height. The two parameters are a location, not a size.
Finally, I find a solution (thanks also to Tilman Hausherr):
private void dibujarImagen(Item i, int x, int y, int alto, int ancho) throws IOException {
PDPixelMap img = null;
try {
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + i.getId() + ".png")));
}
catch (IllegalArgumentException e) {
img = new PDPixelMap(documento, SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(i.getNombre()),null));
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
}
I've been searching for some solutions from the internet yet I still haven't found an answer to my problem.
I've been working or doing a program that would get an image file from my PC then will be edited using Java Graphics to add some text/object/etc. After that, Java ImageIO will save the newly modified image.
So far, I was able to do it nicely but I got a problem about the size of the image. The original image and the modified image didn't have the same size.
The original is a 2x3inches-image while the modified one which supposedly have 2x3inches too sadly got 8x14inches. So, it has gone BIGGER than the original one.
What is the solution/code that would give me an output of 2x3inches-image which will still have a 'nice quality'?
UPDATE:
So, here's the code I used.
public Picture(String filename) {
try {
File file = new File("originalpic.jpg");
image = ImageIO.read(file);
width = image.getWidth();
}
catch (IOException e) {
throw new RuntimeException("Could not open file: " + filename);
}
}
private void write(int id) {
try {
ImageIO.write(image, "jpg", new File("newpic.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
2nd UPDATE:
I now know what's the problem of the new image. As I check it from Photoshop, It has a different image resolution compared to the original one. The original has a 300 pixels/inch while the new image has a 72 pixels/inch resolution.
How will I be able to change the resolution using Java?
To set the image resolution (of the JFIF segment), you can probably use the IIOMetatada for JPEG.
Something along the lines of:
public class MetadataTest {
public static void main(String[] args) throws IOException {
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
writer.setOutput(ImageIO.createImageOutputStream(new File("foo.jpg")));
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
IIOMetadataNode jfif = (IIOMetadataNode) root.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("resUnits", "1");
jfif.setAttribute("Xdensity", "300");
jfif.setAttribute("Ydensity", "300");
metadata.mergeTree(metadata.getNativeMetadataFormatName(), root);
writer.write(null, new IIOImage(image, null, metadata), param);
}
}
Note: this code should not be used verbatim, but adding iteration, error handling, stream closing etc, clutters the example too much.
See JPEG Image Metadata DTD for documentation on the metadata format, and what options you can control.
I am trying to write a grey scale image to an TIFF file using Sanselan. Obviously would like the save the data to be 8 bit grey scale file but somehow I always end up with a 24 bit colour file.
I have searched for file formats in general and ExifTagConstants.EXIF_TAG_PIXEL_FORMAT in particular but was unable to find anything helpful.
I also considered colour profiles but there seem to be none for grey scale images. But then they all have wacky names — I might just have overlooked the right one.
Or do I have to use a different library?
Here the code I use (without business logic and experimental stuff:
Test_Only_Sanselan:
try
{
final Map <String, Object> parameter = new HashMap <>();
parameter.put(org.apache.sanselan.SanselanConstants.PARAM_KEY_COMPRESSION,
org.apache.sanselan.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_UNCOMPRESSED);
final java.io.OutputStream output = new java.io.FileOutputStream("Test-1.tiff");
org.apache.sanselan.Sanselan.writeImage(image, output,
org.apache.sanselan.ImageFormat.IMAGE_FORMAT_TIFF, parameter);
output.close();
}
catch (final IOException exception)
{
LdfImage.log.info("! Could not create tiff image.", exception);
}
catch (final org.apache.sanselan.ImageWriteException exception)
{
LdfImage.log.info("! Could not create tiff image.", exception);
}
I wonder if I need to add a special parameter. But I have not found a useful parameter yet.
The following is a test of the Java 7 image writer which creates a correct grey scale image. But as PNG and not TIFF:
Test_Only_Java_7:
try
{
final java.util.Iterator imageWriters = javax.imageio.ImageIO.getImageWritersByMIMEType ("image/png");
final javax.imageio.ImageWriter imageWriter = (javax.imageio.ImageWriter) imageWriters.next();
final java.io.File file = new java.io.File("Test-2.png");
final javax.imageio.stream.ImageOutputStream output = javax.imageio.ImageIO.createImageOutputStream(file);
imageWriter.setOutput(output);
imageWriter.write(image);
}
catch (final IOException exception)
{
LdfImage.log.info("! Could not create tiff image.", exception);
}
Is there a TIFF pug-in for imageio?
I'm not familiar with Sanselan but I see there is a ImageInfo.COLOR_TYPE_GRAYSCALE constant, I'm guessing it could be used in the params parameter map given to writeImage.
I didn't find the javadoc for Sanselan, their link is broken, would you have one more up-to-date?
If you want to use JAI you can get your inspiration here:
void get8bitImage(byte[] data, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
byte[] rasterData = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
System.arraycopy(pixels, 0, rasterData, 0, pixels.length); // A LOT faster than 'setData()'
}
void main(String[] argv) {
TIFFEncodeParam ep = new TIFFEncodeParam();
FileOutputStream out = new FileOutputStream("c:\\test.tiff");
BufferedImage img = get8bitImage(myData);
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out, ep);
encoder.encode(img);
}
Be sure that the BufferedImage has BufferedImage.TYPE_BYTE_GRAY as imageType.
Is there a Java library for rotating JPEG files in increments of 90 degrees, without incurring image degradation?
I found this: http://mediachest.sourceforge.net/mediautil/
API: http://mediachest.sourceforge.net/mediautil/javadocs/mediautil/image/jpeg/LLJTran.html
Building on Henry's answer, here's an example of how to use MediaUtil to perform lossless JPEG rotation based on the EXIF data:
try {
// Read image EXIF data
LLJTran llj = new LLJTran(imageFile);
llj.read(LLJTran.READ_INFO, true);
AbstractImageInfo<?> imageInfo = llj.getImageInfo();
if (!(imageInfo instanceof Exif))
throw new Exception("Image has no EXIF data");
// Determine the orientation
Exif exif = (Exif) imageInfo;
int orientation = 1;
Entry orientationTag = exif.getTagValue(Exif.ORIENTATION, true);
if (orientationTag != null)
orientation = (Integer) orientationTag.getValue(0);
// Determine required transform operation
int operation = 0;
if (orientation > 0
&& orientation < Exif.opToCorrectOrientation.length)
operation = Exif.opToCorrectOrientation[orientation];
if (operation == 0)
throw new Exception("Image orientation is already correct");
OutputStream output = null;
try {
// Transform image
llj.read(LLJTran.READ_ALL, true);
llj.transform(operation, LLJTran.OPT_DEFAULTS
| LLJTran.OPT_XFORM_ORIENTATION);
// Overwrite original file
output = new BufferedOutputStream(new FileOutputStream(imageFile));
llj.save(output, LLJTran.OPT_WRITE_ALL);
} finally {
IOUtils.closeQuietly(output);
llj.freeMemory();
}
} catch (Exception e) {
// Unable to rotate image based on EXIF data
...
}
Regarding the issue of EXIF data not necessarily being handled correctly, since EXIF data is irrelevant in many situations, here's example code demonstrating only the LLJTran lossless JPEG rotation feature (with thanks to user113215):
final File SrcJPEG = new File("my-input.jpg");
final File DestJPEG = new File("my-output.jpg");
final FileInputStream In = new FileInputStream(SrcJPEG);
try {
final LLJTran LLJT = new LLJTran(In);
LLJT.read(LLJTran.READ_ALL, true);
LLJT.transform(LLJTran.ROT_90);
final FileOutputStream Out = new FileOutputStream(DestJPEG);
try {
LLJT.save(Out, LLJTran.OPT_WRITE_ALL);
} finally {
Out.close();
}
} finally {
In.close();
}
If you make the input and output File objects refer to the same file, you can run this over and over again, and observe that the image does not degrade, no matter how many iterations it is put through.
For Android specifically, I found this fork:
https://github.com/juanitobananas/AndroidMediaUtil
Benefits over upstream:
Gradle/Android Studio project
Compatible with jitpack.io
It might even be usable on normal Java, as the code does not import any Android-specific package (I haven't tried though).
You don't need an external library for this kind of thing, it's all built into SE. The easiest being the rotate() function of the Graphics2D object.
For example:
Image rotatedImage = new BufferedImage(imageToRotate.getHeight(null), imageToRotate.getWidth(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
g2d.rotate(Math.toRadians(90.0));
g2d.drawImage(imageToRotate, 0, -rotatedImage.getWidth(null), null);
g2d.dispose();
no loss!
Or, if you want to be extra careful, just use BufferedImage.getRGB(x,y), and translate it pixel by pixel on to the new image.
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);
}