Cardboard Camera VR Photo Format

A VR photo is a stereoscopic panorama with sound. Cardboard Camera stores elements of a VR photo as metadata in a JPEG file. The container image acts as the left eye image, while the right eye and an (optional) audio file are stored as base64-encoded binary blobs in the image’s metadata. This allows the photo to be backwards-compatible with ordinary image viewers, which recognize the container (left eye) image and display it as a 2D panoramic photo. Metadata is stored using Adobe’s XMP standard, and is further described in their specification.

Metadata Tags

GPano

GPano is used to describe the imaging model of the photo, and stored in the standard section of XMP. Using GPano ensures backwards compatibility with the PhotoSphere metadata standard.

Name Type Required Default value
(viewer assumed)
Property description Action required if image is modified
GPano:UsePanoramaViewer Boolean No True Whether to show this image in a photo sphere viewer rather than as a normal flat image. This may be specified based on user preferences or by the stitching software. The application displaying or ingesting the image may choose to ignore this. scale/crop:
No change. An application may decide to switch this to False if the field of view falls below a certain value.
GPano:CaptureSoftware String No n/a If capture was done using an application on a mobile device, such as an Android phone, the name of the application that was used (such as “Photo Sphere”). This should be left blank if source images were captured manually, such as by using a DSLR on a tripod. n/a
GPano:StitchingSoftware String No n/a The software that was used to create the final photo sphere. This may sometimes be the same value as that of  GPano:CaptureSoftware. n/a
GPano:ProjectionType Open Choice of Text Yes

equirectangular

Projection type used in the image file. Google products currently support the value equirectangular. scale/crop: No change.
GPano:PoseHeadingDegrees Real No, but is required for display on Google Maps n/a Compass heading, measured in degrees, for the center the image. Value must be >= 0 and < 360. scale/crop: No change.
GPano:PosePitchDegrees Real No 0 Pitch, measured in degrees, for the center in the image. Value must be >= -90 and <= 90. scale/crop: No change.
GPano:PoseRollDegrees Real No 0 Roll, measured in degrees, of the image where level with the horizon is 0. Value must be > -180 and <= 180. scale/crop: No change.
GPano:InitialViewHeadingDegrees Integer No 0 The heading angle of the initial view in degrees. scale/crop: No change.
GPano:InitialViewPitchDegrees Integer No 0 The pitch angle of the initial view in degrees. scale/crop: No change.
GPano:InitialViewRollDegrees Integer No 0 The roll angle of the initial view in degrees. scale/crop: No change.
GPano:InitialHorizontalFOVDegrees Real No n/a The initial horizontal field of view that the viewer should display (in degrees). This is similar to a zoom level. n/a
GPano:FirstPhotoDate Date No n/a Date and time for the first image created in the photo sphere. scale/crop: No change.
GPano:LastPhotoDate Date No n/a Date and time for the last image created in the photo sphere. scale/crop: No change.
GPano:SourcePhotosCount Integer No n/a Number of source images used to create the photo sphere. scale/crop: No change.
GPano:ExposureLockUsed Boolean No n/a When individual source photographs were captured, whether or not the camera’s exposure setting was locked. n/a
GPano:CroppedAreaImageWidthPixels Integer Yes n/a Original width in pixels of the image (equal to the actual image’s width for unedited images). scale/crop: This property needs to be updated to reflect the new size of the image.
GPano:CroppedAreaImageHeightPixels Integer Yes n/a Original height in pixels of the image (equal to the actual image’s height for unedited images). scale/crop: This property needs to be updated to reflect the new size of the image.
GPano:FullPanoWidthPixels Integer Yes n/a Original full width from which the image was cropped. If only a partial photo sphere was captured, this specifies the width of what the full photo sphere would have been. crop: No change.
scale: This properly needs to be scaled accordingly.
GPano:FullPanoHeightPixels Integer Yes n/a Original full height from which the image was cropped. If only a partial photo sphere was captured, this specifies the height of what the full photo sphere would have been. crop: No change.
scale: This properly needs to be scaled accordingly.
GPano:CroppedAreaLeftPixels Integer Yes n/a Column where the left edge of the image was cropped from the full sized photo sphere. crop: If the left crop of the image is changed, this value must be updated.
scale: This properly needs to be scaled accordingly.
GPano:CroppedAreaTopPixels Integer Yes n/a Row where the top edge of the image was cropped from the full sized photo sphere. crop: If the top crop of the image is changed, this value must be updated.
scale: This properly needs to be scaled accordingly.
GPano:InitialCameraDolly Real No 0 This optional parameter moves the virtual camera position along the line of sight, away from the center of the photo sphere. A rear surface position is represented by the value -1.0, while a front surface position is represented by 1.0. For normal viewing, this parameter should be set to 0. n/a

GAudio

The audio MIME type is written in the standard section, and the base64-encoded data in the extended section. Storing the MIME type in the standard section allows image readers to quickly determine whether the photo contains audio or not.

Name Type Required Default value
(viewer assumed)
Property description Action required if image is modified
Mime String Yes N/A The MIME type for the base64 string containing the audio content , e.g., "audio/mp4" or "audio/mpeg3". Scale/crop: No change.
Data String Yes N/A The base64-encoded audio data. No change.

GImage

Similar to GAudio, the MIME type of the right eye image resides in the standard section, with the base64-encoded data in the extended section.

Name Type Required Default value
(viewer assumed)
Property description Action required if image is modified
Mime String Yes N/A The MIME type for the base64 string containing the image content, e.g., "image/jpeg" or "image/png". Scale/crop: No change.
Data String Yes N/A The base64-encoded image. Scale/crop: The data needs to be decoded into an image, then scaled/cropped, then re-encoded again.

File Extension

Cardboard Camera currently writes VR photos to a file with the extension .vr.jpg. This extension does not affect the file metadata contents, but it makes it easier to distinguish them from conventional photos. Otherwise, this distinction would require parsing the header of each file, which slows down performance.

Example

Below is an example of the photo format as it would appear in a JPEG file. The XMP metadata of an actual VR photo is viewable by opening it in a text editor.

Standard section

<x:xmpmeta xmlns:x="adobe:ns:meta/" xmptk="Adobe XMP">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description
       xmlns:GImage="http://ns.google.com/photos/1.0/image/"
       xmlns:GPano="http://ns.google.com/photos/1.0/panorama/"
       xmlns:GAudio="http://ns.google.com/photos/1.0/audio/"
       xmlns:xmpNote="http://ns.adobe.com/xmp/note/"
       GImage:Mime="image/jpeg"
       GPano:CroppedAreaLeftPixels="7530"
       GPano:CroppedAreaTopPixels="1809"
       GPano:CroppedAreaImageWidthPixels="1046"
       GPano:CroppedAreaImageHeightPixels="1746"
       GPano:FullPanoWidthPixels="10740"
       GPano:FullPanoHeightPixels="5370"
       GPano:InitialViewHeadingDegrees="269"
       GAudio:Mime="audio/mp4"
       xmpNote:HasExtendedXMP="fe3edd169aebc146ca7aceb5cd15294d" />
  </rdf:RDF>
</x:xmpmeta>

Extended section

<x:xmpmeta xmlns:x="adobe:ns:meta/" xmptk="Adobe XMP">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description
        xmlns:GImage="http://ns.google.com/photos/1.0/image/"
        xmlns:GAudio="http://ns.google.com/photos/1.0/audio/"
        GImage:Data="Base64EncodedImageData"
        GAudio:Data="Base64EncodedAudioData" />
  </rdf:RDF>
</x:xmpmeta>