Keyhole Markup Language

Adding PhotoOverlays

Earlier releases of KML allow you to include small photographs in description balloons attached to placemarks in Google Earth. Entire layers, such as Panoramio, consist of user-contributed geolocated photos. To view these photos, the user must click the placemark icon (or click the name in the List panel) to open the balloon containing the photo.

PhotoOverlays are photographs that are directly embedded in the Earth's landscape. They can be 2D rectangles, adding scenic "billboards" that expand the base aerial imagery of the Earth. PhotoOverlays can also be projected onto cylinders or spheres to create virtual panoramas that the user can "enter," explore, and inspect in detail. In addition, KML 2.2 accommodates very large PhotoOverlays, containing many megapixels of data . These images require you, as KML author, to provide a set of downsampled versions of the image so that Google Earth can efficiently load only the portion of the image that fits into the current view, and at the appropriate level of detail.

In addition to this page, be sure to read the "Topics in KML" page on Cameras, which are used by the PhotoOverlay object. If you are using a very large image for the PhotoOverlay, you will also need to create an <ImagePyramid>.

What You Can Do

The new <PhotoOverlay> element allows you to geographically locate a photograph on the Earth and to specify the placement and orientation of the Camera that views this PhotoOverlay. The PhotoOverlay can be a simple 2D rectangle, a partial or full cylinder, or a sphere (for spherical panoramas). The overlay is placed at the specified location and oriented toward the Camera.


Perhaps the most exciting aspect of this new feature is its ability to handle extremely large photographs, containing many megapixels of data, and to allow the user to efficiently zoom in and pan these large images to see fine details. This advanced feature is discussed in the section Adding Very Large Photos.

Key Concepts

The following sections discuss these key concepts that are related to PhotoOverlay:

  • Inheritance from <Feature> and <AbstractView>
  • Inheritance from <Overlay>
  • Shape
  • Field of View
  • Adjusting the View with <rotation>
  • Marking PhotoOverlays with Icons
  • Image Pyramid - advanced; see the section Adding Very Large Photos


The syntax for <PhotoOverlay> is provided here so that you can refer to it as you read about the related key concepts.

  <!-- inherited from Feature element -->   
  <name>...</name>                      <!-- string -->   
  <visibility>1</visibility>            <!-- boolean -->   
  <open>0</open>                        <!-- boolean -->
  <atom:author>...<atom:author>         <!-- xmlns:atom -->   
  <atom:link>...</atom:link>            <!-- xmlns:atom -->   
  <address>...</address>                <!-- string -->   
  <AddressDetails xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">...
</AddressDetails> <!-- string --> <phoneNumber>...</phoneNumber> <!-- string -->
<Snippet maxLines="2">...</Snippet> <!-- string --> <description>...</description> <!-- string --> <AbstractView>...</AbstractView> <!-- Camera or LookAt --> <TimePrimitive>...</TimePrimitive> <styleUrl>...</styleUrl> <!-- anyURI --> <StyleSelector>...</StyleSelector> <Region>...</Region> <ExtendedData>...</ExtendedData> <!-- inherited from Overlay element --> <color>ffffffff</color> <!-- kml:color --> <drawOrder>0</drawOrder> <!-- int --> <Icon> <href>...</href> <!-- anyURI --> ... </Icon> <!-- specific to PhotoOverlay --> <rotation>0</rotation> <!-- kml:angle180 --> <ViewVolume> <leftFov>0</leftFov> <!-- kml:angle180 --> <rightFov>0</rightFov> <!-- kml:angle180 --> <bottomFov>0</bottomFov> <!-- kml:angle90 --> <topFov>0</topFov> <!-- kml:angle90 --> <near>0</near> <!-- double --> </ViewVolume> <ImagePyramid> <tileSize>256</tileSize> <!-- int --> <maxWidth>...</maxWidth> <!-- int --> <maxHeight>...</maxHeight> <!-- int --> <gridOrigin>lowerLeft</gridOrigin> <!-- lowerLeft or upperLeft--> </ImagePyramid> <Point> <coordinates>...</coordinates> <!-- lon,lat[,alt] --> </Point> <shape>rectangle</shape> <!-- kml:shape --> </PhotoOverlay>

Inheritance from <Feature>

Because <PhotoOverlay> is derived from <Feature>, it can contain one of the two elements derived from <AbstractView>—either <Camera> or <LookAt>. The Camera (or LookAt) specifies a viewpoint and a viewing direction (also referred to as a view vector). The PhotoOverlay is positioned in relation to the viewpoint. Specifically, the plane of a 2D rectangular image is orthogonal (at right angles to) the view vector. The normal of this plane—that is, its front, which is the part with the photo—is oriented toward the viewpoint.

Inheritance from <Overlay>

The URL for the PhotoOverlay image is specified in the <Icon> tag, which is inherited from <Overlay>. The <Icon> tag must contain an <href> element that specifies the image file to use for the PhotoOverlay. In the case of a gigapixel-scale image, the <href> is a special URL that indexes into a pyramid of images of varying resolutions (see Adding Very Large Photos).


The PhotoOverlay is projected onto a shape. The value for <shape> can be one of the following:

  • rectangle - for ordinary photos
  • cylinder - for panoramas (either partial or full cylinders)
  • sphere - for spherical panoramas

Field of View

Once you have positioned the camera in space and oriented it, you need to define how much of the current scene is visible. Specifying the field of view is analogous to specifying the lens opening in a physical camera. A small field of view, like a telephoto lens, focuses on a small part of the scene. A large field of view, like a wide-angle lens, focuses on a large part of the scene.

The field of view for a PhotoOverlay is defined by four planes, each of which is specified by an angle relative to the view vector. These four planes define the top, bottom, left, and right sides of the field of view, which has the shape of a truncated pyramid, as shown here:

view volume for a camera

The following diagrams show the <rightFov> and <leftFov> angles ("Side View") and the <topFov> and <bottomFov> angles ("Top View") of this pyramid:


A typical real-world camera has a symmetric field of view in both directions, in which case

bottomFov = -topFov 


leftFov = -rightFov

Typical values are the following:


The <shape> containing the PhotoOverlay is placed at <near>, which is the distance in meters from the viewpoint (or camera position). The four planes of the field of view intersect the shape. Any part of the shape that is inside the field of view is visible. Any part of the shape that falls outside the field of view is said to be "clipped," and is not shown.

Field of View for a Rectangle

For a rectangle, <topFov> must be less than 90°, and <bottomFov> must be greater than -90°. If either of these limits is exceeded, the field of view plane would not intersect the image at all. The <bottomFov> and <leftFov> elements are usually negative values.

Field of View for a Cylinder

For a cylindrical image, the axis of the cylinder matches the up vector (Y axis) for the view. The radius of the cylinder is equal to <near>.

For a cylinder, the ranges for the field of view are as follows:

-90 < bottomFov < topFov < 90
-180 < leftFov < rightFov < 180 

Field of View for a Sphere

A spherical image is centered at the origin of the camera (viewpoint). The radius of the sphere is equal to <near>. For a sphere, the ranges for the field of view are as follows:

-90 < bottomFov < topFov < 90
-180 < leftFov < rightFov < 180 

Adjusting the View with <rotation>

Use the <rotation> element as a child of <PhotoOverlay> to adjust how the photo is placed inside the field of view. This element is useful if your photo has been rotated and deviates slightly from a desired horizontal view.

Marking PhotoOverlays with Icons

<PhotoOverlay> includes a <Point> element that behaves in the same manner as <Point> when it is used inside a <Placemark> element—that is, it causes Google Earth to draw an icon to mark the position of the PhotoOverlay. The icon drawn is specified by the <styleUrl> and <StyleSelector> fields, just as it is for <Placemark>.

Adding Very Large Photos

For very large images, you'll need to construct an image pyramid, which is a hierarchical set of images, each of which is an increasingly lower resolution version of the original image. Each image in the pyramid is subdivided into tiles, so that only the portions in view need to be loaded. Google Earth calculates the current viewpoint and loads the tiles that are appropriate to the user's distance from the image. As the viewpoint moves closer to the PhotoOverlay, Google Earth loads higher resolution tiles. Since all the pixels in the original image can't be viewed on the screen at once, this preprocessing allows Google Earth to achieve maximum performance because it loads only the portions of the image that are in view, and only the pixel details that can be discerned by the user at the current viewpoint.

If you image is very large, you should create an image pyramid for it and modify the <href> in the <Icon> element to include specifications for which tiles to load. The following sections describe how to create the image pyramid and how to specify the <href> for a gigapixel image.

The <ImagePyramid> Element

The <ImagePyramid> element has the following syntax:

  <tileSize>256</tileSize>              <!-- int -->
  <maxWidth>...</maxWidth>              <!-- int -->
  <maxHeight>...</maxHeight>            <!-- int -->
  <gridOrigin>lowerLeft</gridOrigin>    <!-- lowerLeft or upperLeft -->

The pixel size of the original image is specified in the <maxWidth> and <maxHeight> elements. The width and height can be any size and do not need to be a power of 2. You can fill out the remaining pixels with blank pixels, as described in Adding Fill to the Image.

Tiles must be square, and the <tileSize> must be a power of 2. A tile size of 256 (the default) or 512 is recommended.

Creating the Image Pyramid

These instructions assume your image pixel measurement is a power of 2. (If your image pixel measurement is not a power of 2, you'll first need to add fill, as described in Adding Fill to the Image.) Then follow these steps to create an image pyramid:

  1. Starting with the original, full-size image, divide it into tile-sized pieces—for example, into blocks of 256 * 256 pixels each.
  2. Shrink the image by a factor of 2.
  3. Divide this new image into tile-sized squares.
  4. Repeat steps 2 and 3 until the resulting image fits inside the tile size (for example, 256 * 256 pixels).

Adding Fill to the Image

If the last tile in a row is not square, you'll need to add transparent fill pixels to make the tile square. Place the image so that the (0,0) tile is at the origin. (For example, if the origin is at the lower left, place the image in the lower left of the tile grid.) The row and columns that might need fill would then be at the right and top of the image. For best filtering, replicate the last row (or column) at the edge of the image. Then add fill (for example, black) to the remaining pixels in the tiles of the row (or column).


As an example, consider an image whose dimensions are 3600 * 2700 pixels (roughly 10 megapixels). Here are the steps to create an image pyramid for this image:

  1. Using a tile size of 256 pixels, you can subdivide the original image into a grid of 16 * 16 pixels. (This image ends up as level 4 in the final pyramid.)
  2. Fill in the pixels to "square up" the partially filled tiles (as described in Adding Fill to the Image) in the last column (to the right) and the last row (at the top, assuming <gridOrigin> is lowerLeft).
  3. Scale down the image by a factor of 2.
  4. Subdivide this image into 256-pixel tiles. The image at this level consists of a grid of 8 * 8 tiles (level 3).
  5. Scale the level 3 image down by a factor of 2.
  6. Subdivide into tiles. The image at this level consists of a grid of 4 * 4 tiles (level 2).
  7. Scale the level 2 image down by a factor of 2.
  8. Subdivide into tiles. The image at this level consists of a grid of 2 * 2 tiles (level 1).
  9. Scale the level 1 image down by a factor of 2.
  10. The resulting image is 256 * 256 pixels, so this is the last level of the image pyramid (level 0).

The image pyramid for a 4096 * 4096 image has 5 levels, as shown in the following table:

Number of Tiles
Size of Image (pixels)
256 * 256
4 (2 * 2 grid)
512 * 512
16 (4 * 4 grid)
1024 * 1024
64 (8 * 8 grid)
2048 * 2048
256 (16 * 16 grid)
4096 * 4096

Level n thus has 2n tiles in each direction.

The following illustrations show Levels 0, 1, and 2 of a sample image pyramid.

"" ""

Numbering the Tiles

The tiles in each level are numbered so that Google Earth can fetch only the specific tiles that are appropriate for the current viewpoint. Each tile is identified by three values:

  • x value - row position in the grid
  • y value - column position in the grid
  • level - level in the image pyramid, with 0 being the highest level

By default, the origin (0,0) is at the lower left of the grid. If your image has an origin in the upper left, specify topLeft for the <gridOrigin>.

The following figure illustrates numbering of the tiles at level 2 of the 10-megapixel image, with the origin in the lower left:

Specifying the URL of a Very Large Image

For gigapixel images, the <href> specification in the <Icon> element includes special entities to specify the level, x, and y values of the tiles Google Earth needs to fetch. For example, the URL for the image might be specified as follows:$[level]/row_$[x]_column_[$y].jpg 

To request the tile in row 2, column 1, at level 3, Google Earth would fetch the following URL:


If your image is fully opaque, use the JPEG format. If part of the image is opaque and part is transparent, you can mix PNG and JPEG tiles. Use the PNG format only for tiles that have transparency values. If you need to mix formats, omit the file extension from the <href> specification of the image file and include the file extension in the filename for each tile.

Back to top

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.