Hello,
I'm trying to combine two images to display them via the Google Cardboard Camera app. These images encode the right panoramic view into the left panoramic view, as described on this Google page (https://developers.google.com/vr/concepts/cardboard-camera-vr-photo-format).
So far I've been able to extract the encoded Image, that is stored as binary base64-encoded value in XMP-GImage:Data and also set ExifTool's config file so that I can (theoretically) write the GImage:Data tag. For this post I will be using this image created with the Cardboard Camera app (https://drive.google.com/open?id=0B8ltHMCkesizWVVYZ3dYaGw3TTg).
My config file looks like this:
%Image::ExifTool::UserDefined::GImage = (
GROUPS => { 0 => 'XMP', 1 => 'XMP-GImage', 2 => 'Image' },
NAMESPACE => { 'GImage' => 'http://ns.google.com/photos/1.0/image/' },
WRITABLE => 'string', # (default to string-type tags)
# Example 8. XMP-xxx:NewXMPxxxTag1 (an alternate-language tag)
# - replace "NewXMPxxxTag1" with your own tag name (eg. "MyTag")
Data => { Binary => 1, },
# Example 9. XMP-xxx:NewXMPxxxTag2 (a string tag in the Author category)
Mime => { },
);
# The %Image::ExifTool::UserDefined hash defines new tags to be added
# to existing tables.
%Image::ExifTool::UserDefined = (
# new XMP namespaces (ie. XXX) must be added to the Main XMP table:
'Image::ExifTool::XMP::Main' => {
GImage => {
SubDirectory => {
TagTable => 'Image::ExifTool::UserDefined::GImage',
},
},
},
);
1; #end
To extract the encoded image from the left perspective I used .\exiftool.exe -b -XMP-GImage:Data .\MyImage.jpg > .\MyImage_right.jpg.bin (yes, I'm on Windows.) The resulting file starts with /9j/4AAQSk... and ends with MIlGgggD//Z and a new line, so two lines in total.
Then I run certutil.exe -decode .\MyImage_right.jpg.bin .\MyImage_right.jpg to get the right panorama, so far everything works great. (Except that I haven't been able to pipe ExifTool's output into any base64-decoder)
Now I would like to create these stereoscopic photospheres myself, but I haven't had much success. Just trying to rewrite the .bin into the left view results in an incorrect image. My command for this is .\exiftool.exe "-XMP-GImage:Data<=.\MyImage_right.jpg.bin" .\MyImage.jpg The resulting image is now 3.505.127 Bytes, the original only 2.232.764 Bytes. Also, the extracted .bin already is 2.541.070 Bytes (should be 952.899 Bytes, according to the -X output). In fact, when I extract the freshly written XMP-GImage:Data again it's double the size and contains a dot between each character.
Can anybody point me in the right direction? I thought using the -b option is for exactly that case.
I don't have any time right now to read this in detail, but it seems like you will have to decode the base64 data with something like this in your tag definition:
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
And remove the "Binary => 1" flag.
If you can't figure it out, post a (small) sample image and I'll try it when I get a chance (in a couple of days). Some people have trouble posting images, so an alternative is to upload it to a file sharing service somewhere.
- Phil
Thank you for your reply Phil.
I adjusted my config file just like you said and ran .\exiftool.exe -b -XMP-GImage:Data .\MyImage.vr.jpg > .\MyImage_right.vr.jpg, but it produced a jpg with a file size of 1875 KB (should be roughly half of the original image, so 2181 KB / 2) and it can't be opened by any image viewer.
For this thread I'm using this image (https://drive.google.com/file/d/0B8ltHMCkesizWVVYZ3dYaGw3TTg/view) created in the Cardboard Camera app, to download click the little arrow pointing down in the upper right corner, otherwise the metadata won't be stored correctly.
So to sum up: At first I'd like to extract the binary XMP-GImage:Data from the left perspective and just as a test rewrite it into the left perspective.
OK, everything works fine for me with the attached config file. I can read and write a valid 952899 byte JPEG image. Reading should have worked for you with the addition I suggested, but a ValueConvInv was required to be able to write the Base64 data.
% ls -l a.jpg
-rw-r--r--@ 1 phil staff 2232764 21 May 08:32 a.jpg
% exiftool -config gimage.config -b -xmp-gimage:data a.jpg > b.jpg
% ls -l b.jpg
-rw-r--r--@ 1 phil staff 952899 21 May 08:25 b.jpg
% exiftool -config gimage.config "-xmp-gimage:data<=b.jpg" a.jpg
1 image files updated
% exiftool -config gimage.config -data a.jpg
Data : (Binary data 952899 bytes, use -b option to extract)
(Since you are in Windows, you would do a "dir" instead of "ls -l" in my above commands.)
- Phil
Edit: ExifTool 10.54 will support these GImage tags (named ImageData and ImageMimeType).
Hi Phil, thank you for taking your time to troubleshoot this issue for me.
I have tried the steps you described, and while I get the same results you posted (meaning the encoded image has the same size before and after exporting it) I get different file sizes for the left perspective (before 2.232.764 Bytes, after 2.254.264 Bytes). Therefore the Google Cardboard Camera app fails to display the image and the Google Photos app (which seems to be a bit more robust) displays the left perspective for both eyes.
Where does this difference in file size come from? I have uploaded the image after extracting and re-encoding the right into the left perspective (https://drive.google.com/open?id=0B4JbwzHxeOTyNEk5dXRER0pYT1E), maybe this helps in figuring out the problem.
The difference in the file size is unrelated to a problem displaying the image (unless the app isn't parsing the XMP properly). See FAQ 13 (https://exiftool.org/faq.html#Q13).
There must be some other difference. I'll look at your uploaded file when I get a chance.
- Phil
OK, I've taken a closer look. The only notable differences are some change in ordering of the XMP properties (which shouldn't be significant), and the fact that ExifTool inserts linefeeds in the base 64 output (which is perfectly legal, but maybe the camera app can't handle standard base 64). If the linefeeds are the problem, then changing the ValueConvInv to this should fix it:
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val, 1)',
Please let me know if this does the trick.
- Phil
Unfortunately it still doesn't work. Windows tells me the new generated file is 2.233.088 Bytes, while the original is 2.232.764 Bytes. You can find the new generated file here (https://drive.google.com/open?id=0B4JbwzHxeOTyVjdNN1ZMU2l0NVk).
As I said, the file size is not significant.
I can see no significant differences in the metadata of these files. It would be useful if the Google Cardboard Camera app people could tell you why their app isn't loading the file.
- Phil
I know this is quite an old thread but I ran into the same issue. Images following the Google specification for VR images created with ExifTool can not be processed by the Android Cardboard application ("this is not a VR image"). The issue is not related to the base64 encoding but to the structure of the XML. I analyzed the files with Unix hexdump and it appears that the XMP part of images created by the Cardboard Camera app look like this (slightly formatted for readability):
http://ns.adobe.com/xap/1.0/
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description xmlns:GPano="http://ns.google.com/photos/1.0/panorama/"
xmlns:GImage="http://ns.google.com/photos/1.0/image/"
xmlns:xmpNote="http://ns.adobe.com/xmp/note/"
rdf:about=""
GPano:CroppedAreaLeftPixels="0"
GPano:CroppedAreaTopPixels="1620"
GPano:CroppedAreaImageWidthPixels="9262"
GPano:CroppedAreaImageHeightPixels="1624"
GPano:FullPanoWidthPixels="9262"
GPano:FullPanoHeightPixels="4631"
GPano:InitialViewHeadingDegrees="180"
GImage:Mime="image/jpeg"
xmpNote:HasExtendedXMP="ceb9f6c4a305955504a856dafdfe371f"/>
</rdf:RDF>
</x:xmpmeta>
If I use ExifTool to create these kind of images the XMP has a different fornat:
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about=''
xmlns:xmpNote='http://ns.adobe.com/xmp/note/'>
<xmpNote:HasExtendedXMP>6B88EFA1352935825671FB752D8D067C</xmpNote:HasExtendedXMP>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:GImage='http://ns.google.com/photos/1.0/image/'>
<GImage:Mime>image/jpeg</GImage:Mime>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:GPano='http://ns.google.com/photos/1.0/panorama/'>
<GPano:CroppedAreaImageHeightPixels>1624</GPano:CroppedAreaImageHeightPixels>
<GPano:CroppedAreaImageWidthPixels>9262</GPano:CroppedAreaImageWidthPixels>
<GPano:CroppedAreaLeftPixels>0</GPano:CroppedAreaLeftPixels>
<GPano:CroppedAreaTopPixels>1620</GPano:CroppedAreaTopPixels>
<GPano:FullPanoHeightPixels>4631</GPano:FullPanoHeightPixels>
<GPano:FullPanoWidthPixels>9262</GPano:FullPanoWidthPixels>
<GPano:InitialViewHeadingDegrees>180</GPano:InitialViewHeadingDegrees>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
Apparently ExifTool writes one rdf:Description tag per namespace. Google Cardboard is confused and seems to use quite an intolerant XML parser.
I assume the problem is on Google's side and not in ExifTool. I tried patching such a file with a hex editor and after removing the additional tags it worked with Cardboard. I posted a bug report on Google VR Developer forum but I do not expect that somebody will react or even fix this: https://plus.google.com/103723281823338770763/posts/ekD3KAgoWMU (https://plus.google.com/103723281823338770763/posts/ekD3KAgoWMU)
If somebody knows a workaround to convince ExifTool to write the compact format please post. Personally I do not need a fix I have written a small Java program using the icafe library on GitHub. This gives me more convenience anyway. I thought it might be useful to post because others may run into the same issue and ExifTool is very popular for these kind of tasks.
If this is indeed the problem then the fault is definitely in the Android Cardboard Camera app, and some other work-around must be used. Currently there is no way to get ExifTool to write XMP using the compact format.
- Phil
Quote from: Phil Harvey on August 25, 2017, 11:55:06 AM
Currently there is no way to get ExifTool to write XMP using the compact format.
I tried to use either of -api Compact = or -z, but editing the metadata with exiftool:
exiftool Lenovo.vr.jpg -XMP-GPano:CroppedAreaTopPixels="0" -o exiftool.vr.jpgbreaks compatibility with https://arvr.google.com/vr180/apps/
The same thing - "this is not a VR image"
This is fixed compatibility:
exiv2 -M"set Xmp.GPano.CroppedAreaTopPixels 0" exiftool.vr.jpgMaybe there is some parameter for exiftool -exiv2LikeXMP?
I wanted to try:
exiftool exiftool.vr.jpg "-xmp<=exiv2Like.XMP"but I can't create valid exiv2Like.XMP because of big ImageData.xmp
Could you attach the Exiv2 version of the file so I can compare the result?
- Phil
ok
The most significant difference is that there is no xpacket wrapper for the XMP in the original file. ExifTool will write XMP like this without adding a wrapper, but the Exiv2 file is wrapped.
Does this command produce a useable result?:
exiftool Lenovo.vr.jpg -xmp:all= "-all:all<xmp:all" -XMP-GPano:CroppedAreaTopPixels="0" -o exiftool.vr.jpg
This will rebuild the XMP, adding the xpacket wrapper.
- Phil
Quote from: Phil Harvey on April 16, 2021, 09:28:58 AM
useable result?:
Unfortunately no
I tried:
exiftool Lenovo.vr.jpg -xmp:all= "-all:all<xmp:all" -XMP-GPano:CroppedAreaTopPixels="0" -o exiftool.xmp
exiftool Lenovo.vr.jpg "-xmp<=exiftool.xmp" -o exiftool.vr.jpg
Warning: [minor] Entries in ExifIFD were out of sequence. Fixed. - Lenovo.vr.jpg
Error: [minor] XMP block too large for JPEG segment! (2801884 bytes) - Lenovo.vr.jpg
0 image files updated
1 files weren't updated due to errors
How to save exiftool.xmp wrapped by http://ns.adobe.com/xmp/extension/
The only other thing I can think of is to add -api compact=shorthand to the exiftool command in case the parser is brain-dead and can't deal with XMP in standard format.
Aside from this, I can't see any major differences in the XMP.
I would consider this a bug in the VR180 app, and submit a bug report to them.
- Phil
Quote from: Phil Harvey on April 16, 2021, 10:07:44 AM
bug in the VR180 app, and submit a bug report to them
They will say use exiv2 and don't bother us \8^)
Quote7. Extract XMP as a block and write to output XMP file: (same effect as above)
exiftool -xmp -b SRC.EXT > DST.xmp
As with the previous command, this command will not copy extended XMP segments in JPEG images, but in this case the -a option may be added to also extract extended XMP blocks. However, the result would be a non-standard XMP file that ExifTool could read but other utilities may not
exiftool -xmp -b -a Lenovo.vr.jpg > DST.xmpQuote10. Restore XMP as a block from an XMP sidecar file to a JPG image:
(same effect as above except that any non-writable XMP tags would be copied by this command, and the 2 kB of padding recommended by the XMP specification is not added when copying as a block)
exiftool -tagsfromfile SRC.xmp -xmp DST.jpg
or equivalently
exiftool "-xmp<=SRC.xmp" DST.jpg
y:\ins\360\VR>exiftool Lenovo.vr.jpg "-xmp<=DST.xmp" -o exiftool.vr.jpg
Warning: Invalid XMP data for XMP:XMP
Warning: [minor] Entries in ExifIFD were out of sequence. Fixed. - Lenovo.vr.jpg
1 image files copied
Unfortunately you can't treat extended XMP as a block because it exists as 2 or more parts in a JPEG image.
It would be interesting to know exactly what the app doesn't like about the XMP that ExifTool writes. It would take me a few hours to track this down, but I don't have time to spend on this right now.
- Phil
Has this problem been solved?
Or, alternatively, would it be enough to replace the section of a jpeg file included between
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP"> and
</x:xmpmeta> by my own text?