Reputation: 13083
I have images stored in the database as Base64 encoded strings. I want to read this string, decode it into an array of bytes and display it. So far so good.
Now I also want to display additional information about this image. I really care when this image was taken / created.
I have tried several approaches. When an image exists in the file system, there is no problem. However, when I read encoded string, decode it into bytes, a problem appears.
I used metadata-extractor library.
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.9.0</version>
</dependency>
public void processData(String data) {
if (data == null || data.isEmpty()) {
return;
}
byte[] base64Decoded = DatatypeConverter.parseBase64Binary(data);
read(base64Decoded );
//displayImage();
//displayImageInfo();
}
public void read(byte [] data) {
try {
InputStream inputStream = new ByteArrayInputStream(data);
BufferedImage image = ImageIO.read(inputStream);
retrieveImageInfo();
Metadata metadata = ImageMetadataReader.readMetadata(inputStream);
retrieveAdditiaonlInfo2(metadata);
} catch (Exception e) {
//throw new RuntimeException("Failed to read the image from bytes.", e);
}
}
private void retrieveImageInfo() {
imageWidth = (long) image.getWidth();
imageHeight = (long) image.getHeight();
imageSize = (long) data.length;
}
private void retrieveAdditiaonlInfo2(Metadata metadata) {
for (Directory directory : metadata.getDirectories()) {
for (Tag tag : directory.getTags()) {
System.out.format("[%s] - %s = %s", directory.getName(), tag.getTagName(), tag.getDescription());
System.out.println();
}
if (directory.hasErrors()) {
for (String error : directory.getErrors()) {
System.err.format("ERROR: %s", error);
System.err.println();
}
}
}
}
This works well for images that were read from files. But for our database it does not work. It says,
Caused by: java.io.IOException: Stream ended before file's magic number could be determined. at com.drew.imaging.FileTypeDetector.detectFileType(FileTypeDetector.java:97)
Upvotes: 2
Views: 3982
Reputation: 11
along with converting it to BufferedInputStream, I also had to pass bytes length as second arg to get rid of that error.
byte[] imageBytes = downloadImageFromUrl(imageUrl);
Metadata metadata = ImageMetadataReader.readMetadata(new BufferedInputStream(new ByteArrayInputStream(imageBytes)), imageBytes.length)
Upvotes: 0
Reputation: 13083
After a research and debug I found this. BufferedInputStream is the necessety!
File imageFile = new File(filename);
Path path = imageFile.toPath();
byte[] data = Files.readAllBytes(path);
String str = DatatypeConverter.printBase64Binary(data);
//Store encoded data.
//Retrieve encoded string from the database.
byte [] data2 = DatatypeConverter.parseBase64Binary(str);
InputStream inputStream = new ByteArrayInputStream(data2);
BufferedInputStream bis = new BufferedInputStream(inputStream);
Metadata metadata = ImageMetadataReader.readMetadata(bis);
So it worked!
One thing, not all the images contain metadata (I need date-time taken). Here are two examples of metadata.
[JPEG] - Compression Type = Baseline
[JPEG] - Data Precision = 8 bits
[JPEG] - Image Height = 758 pixels
[JPEG] - Image Width = 1024 pixels
[JPEG] - Number of Components = 3
[JPEG] - Component 1 = Y component: Quantization table 0, Sampling factors 2 horiz/2 vert
[JPEG] - Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
[JPEG] - Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
[JFIF] - Version = 1.1
[JFIF] - Resolution Units = none
[JFIF] - X Resolution = 1 dot
[JFIF] - Y Resolution = 1 dot
[JFIF] - Thumbnail Width Pixels = 0
[JFIF] - Thumbnail Height Pixels = 0
[JPEG] - Compression Type = Baseline
[JPEG] - Data Precision = 8 bits
[JPEG] - Image Height = 3104 pixels
[JPEG] - Image Width = 4192 pixels
[JPEG] - Number of Components = 3
[JPEG] - Component 1 = Y component: Quantization table 0, Sampling factors 2 horiz/1 vert
[JPEG] - Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
[JPEG] - Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
[Exif IFD0] - Software = Flyme
[Exif IFD0] - Orientation = Top, left side (Horizontal / normal)
[Exif IFD0] - Unknown tag (0x0224) = 1
[Exif IFD0] - Unknown tag (0x0225) =
[Exif IFD0] - Date/Time = 2016:04:13 10:20:08
[Exif IFD0] - Model = m1 note
[Exif IFD0] - Unknown tag (0x0222) = 0
[Exif IFD0] - Unknown tag (0x0223) = 0
[Exif IFD0] - Unknown tag (0x0220) = 0
[Exif IFD0] - Unknown tag (0x0221) = 0
[Exif IFD0] - Y Resolution = 72 dots per inch
[Exif IFD0] - X Resolution = 72 dots per inch
[Exif IFD0] - YCbCr Positioning = Datum point
[Exif IFD0] - Resolution Unit = Inch
[Exif IFD0] - Image Description =
[Exif IFD0] - Make = Meizu
[GPS] - GPS Img Direction = 49 degrees
[GPS] - GPS Img Direction Ref = Magnetic direction
[Exif SubIFD] - Date/Time Digitized = 2016:04:13 10:20:08
[Exif SubIFD] - Color Space = sRGB
[Exif SubIFD] - Date/Time Original = 2016:04:13 10:20:08
[Exif SubIFD] - FlashPix Version = 1.00
[Exif SubIFD] - Metering Mode = Center weighted average
[Exif SubIFD] - Exposure Bias Value = 0 EV
[Exif SubIFD] - Exif Image Height = 3104 pixels
[Exif SubIFD] - Exif Version = 2.20
[Exif SubIFD] - Exif Image Width = 4192 pixels
[Exif SubIFD] - Focal Length = 3.8 mm
[Exif SubIFD] - Digital Zoom Ratio = 1
[Exif SubIFD] - White Balance = (Other)
[Exif SubIFD] - Scene Capture Type = Standard
[Exif SubIFD] - Flash = Flash did not fire
[Exif SubIFD] - White Balance Mode = Auto white balance
[Exif SubIFD] - Exposure Mode = Auto exposure
[Exif SubIFD] - Exposure Time = 79999/1000000 sec
[Exif SubIFD] - ISO Speed Ratings = 810
[Exif SubIFD] - Components Configuration = YCbCr
[Exif SubIFD] - F-Number = f/2.2
[Exif SubIFD] - Exposure Program = Unknown (0)
[Interoperability] - Interoperability Index = Recommended Exif Interoperability Rules (ExifR98)
[Interoperability] - Interoperability Version = 1.00
[Exif Thumbnail] - Orientation = Top, left side (Horizontal / normal)
[Exif Thumbnail] - Compression = JPEG (old-style)
[Exif Thumbnail] - Thumbnail Offset = 962 bytes
[Exif Thumbnail] - YCbCr Positioning = Datum point
[Exif Thumbnail] - Thumbnail Length = 0 bytes
[Exif Thumbnail] - Y Resolution = 72 dots per inch
[Exif Thumbnail] - Resolution Unit = Inch
[Exif Thumbnail] - X Resolution = 72 dots per inch
Upvotes: 3