Chapter 7. Presentation

Much of what you need to know about presentations has already been covered in the preceding chapter, because a presentation is at heart a series of <draw:page> elements within the <office:presentation> element.

Note

In fact, you can create multiple pages in a drawing document. They are simply stored as separate pages, and don’t have any of the transition elements that a presentation permits.

In OpenOffice.org, there’s so much information (53K bytes worth) in the styles.xml file for even the simplest of presentations that you probably don’t want to create it from scratch. Instead, you will be better off to create an empty presentation with the background elements that you want, and then merge your own content.xml into the resulting jar file. Here are some of the names of <style:style>s that are in the styles.xml file for a plain presentation, along with their salient characteristics. These are styles for OpenOffice.org; for other applications “your mileage may vary.”

The <office:automatic-styles> is followed by <office:master-styles>. Just as described in the section called “A Drawing’s styles.xml File”, the <office:master-styles> begins with a <draw:layer-set> element.

In a presentation, the layer set is followed by a <style:handout-master> element. Its presentation:presentation-page-layout-name attribute refers to the style:presentation-page-layout whose <presentation:placeholder>s describe handouts. The <style:handout-master> starts with some <draw:frame> elements that give the <presentation:header>, <presentation:date-time>, and <presentation:footer>. These text frames are followed by one <draw:page-thumbnail> element for each thumbnail; the values of the thumbnail’s svg:x, svg:y, svg:width, and svg:height attributes are different from those of the <presentation:placeholder>, and are the ones that are actually used when displaying the thumbnail.

The next master style is a <style:master-page> element which describes the layout for the default slide type (text with outline) notes view. It contains a <draw:frame> elements for a default title, an outline area, date and time, footer, and page number (which is enclosed in a text:page-number element inside the frame’s text box). These frames are followed by a <presentation:notes> element, which contains a <draw:page-thumbnail> element for the page and then various <draw:frames> to describe the rest of the page.

Example 7.1, “Structure of a styles.xml file” shows a styles.xml file, with much non-essential information removed. Note how the names of the <style:page-master> elements are referenced in the <style:handout-master> and <style:master-page>; they are shown in boldface. Note also that the similar names of the <style:page-master> and <style:master-page> elements doesn’t make this any easier.

Example 7.1. Structure of a styles.xml file

<office:styles>
    <draw:marker draw:name="Arrow" svg:viewBox="0 0 20 30"
      svg:d="m10 0-10 30h20z"/>
    <style:default-style style:family="graphic">
        <style:paragraph-properties several properties>
            <style:tab-stops/>
        </style:paragraph-properties>
        <style:text-properties font declarations/>
    </style:default-style>
    <style:style style:name="standard"
      style:family="graphic">
        <style:graphic-properties many properties>
            <text:list-style>
                <text:list-level-style-bullet text:level="1"
                  text:bullet-char="●">
                    <style:text-properties fo:font-family="StarSymbol"
                      style:use-window-font-color="true" fo:font-size="45%"/>
                </text:list-level-style-bullet>
                <!-- and nine more bullets -->
            </text:list-style>
        </style:graphic-properties>
        <style:paragraph-properties many specifications/>
    </style:style>
    <!-- we have omitted many other default styles -->
 
    <style:presentation-page-layout style:name="AL0T26">
        <presentation:placeholder
          presentation:object="handout" svg:x="2.057cm" svg:y="1.743cm"
          svg:width="6.103cm" svg:height="-0.233cm"/>
        <presentation:placeholder
          presentation:object="handout" svg:x="10.96cm" svg:y="1.743cm"
          svg:width="6.103cm" svg:height="-0.233cm"/>
          <!-- etc -->
    </style:presentation-page-layout>
</office:styles>

<office:automatic-styles>
    <!-- page master for handouts -->
    <style:page-layout style:name="PM0">
        <style:page-layout-properties
            fo:margin-top="0cm" fo:margin-bottom="0cm"
            fo:margin-left="0cm" fo:margin-right="0cm"
            fo:page-width="27.94cm" fo:page-height="21.59cm" style:print-orientation="landscape"/>
    </style:page-layout>

    <!-- page master for ordinary pages -->
    <style:page-layout style:name="PM1">
        <style:page-layout-properties
            fo:margin-top="0cm" fo:margin-bottom="0cm"
            fo:margin-left="0cm" fo:margin-right="0cm"
            fo:page-width="28cm" fo:page-height="21cm" style:print-orientation="landscape"/>
    </style:page-layout>

    <!-- page master for notes -->
    <style:page-layout style:name="PM2">
        <style:page-layout-properties
            fo:margin-top="0cm" fo:margin-bottom="0cm"
            fo:margin-left="0cm" fo:margin-right="0cm"
            fo:page-width="21.59cm" fo:page-height="27.94cm"
            style:print-orientation="portrait"/>
    </style:page-layout>

    <!-- style for the default page -->
    <style:style style:name="dp1" style:family="drawing-page">
        <style:drawing-page-properties
            draw:background-size="border"
            draw:fill="none"/>
    </style:style>
</office:automatic-styles>
 
<office:master-styles>
    <draw:layer-set>
        <draw:layer draw:name="layout"/>
        <draw:layer draw:name="background"/>
        <draw:layer draw:name="backgroundobjects"/>
        <draw:layer draw:name="controls"/>
        <draw:layer draw:name="measurelines"/>
    </draw:layer-set>

    <style:handout-master
      presentation:presentation-page-layout-name="AL0T26"
      style:page-layout-name="PM0" draw:style-name="dp2">
        <draw:frame draw:style-name="gr1" draw:text-style-name="P1"
          draw:layer="backgroundobjects"
          svg:width="12.124cm" svg:height="1.078cm"
          svg:x="0cm" svg:y="0cm" presentation:class="header">
            <draw:text-box>
                <text:p text:style-name="P1">
                    <presentation:header/>
                </text:p>
            </draw:text-box>
        </draw:frame>
        <!-- frames for date/time and footer follow -->
        <draw:page-thumbnail
            draw:layer="backgroundobjects"
            svg:width="5.586cm" svg:height="4.189cm"
            svg:x="2.794cm" svg:y="4.327cm" draw:page-number="1"/>
        <draw:page-thumbnail draw:layer="backgroundobjects"
            svg:width="5.586cm" svg:height="4.189cm"
            svg:x="11.176cm" svg:y="4.327cm"/>
    </style:handout-master>

    <style:master-page style:name="Default" style:page-layout-name="PM1"
      draw:style-name="dp1">
        <draw:frame presentation:style-name="Default-title"
          draw:layer="backgroundobjects"
          svg:width="25.199cm" svg:height="3.506cm"
          svg:x="1.4cm" svg:y="0.837cm"
          presentation:class="title" presentation:placeholder="true">
            <draw:text-box/>
        </draw:frame>

        <presentation:notes style:page-layout-name="PM2">
            <draw:page-thumbnail presentation:style-name="Default-title"
              draw:layer="backgroundobjects"
              svg:width="13.968cm" svg:height="10.476cm"
              svg:x="3.81cm" svg:y="2.123cm"
              presentation:class="page"/>
            <draw:frame presentation:style-name="Default-notes"
              draw:layer="backgroundobjects"
              svg:width="17.271cm" svg:height="12.572cm"
              svg:x="2.159cm" svg:y="13.271cm"
              presentation:class="notes" presentation:placeholder="true">
                    <draw:text-box/>
            </draw:frame>
            <!-- frame for header and date/time, footer, and page
                 number follow -->
        </presentation:notes>
    </style:master-page>
</office:master-styles>

In the content.xml file’s <office:presentation> element you will find a series of <draw:page> elements, each of which has a draw:name attribute in the form pagen. The draw:master-page-name and draw:style-name attributes refer to the master page and style for the slide. These will normally be the same for all slides. The presentation:presentation-page-layout-name attribute points to the default layout from the styles.xml file.

The <draw:page> element contains child elements for each of the objects on the slide. These can be

These elements have the following attributes in common: draw:layer is set to layout. If there is a presentation:class attribute, it tells what kind of item this is: title, outline, subtitle, or notes. The item’s location and size is given by svg:x, svg:y, svg:width, and svg:height attributes. The element will also have a draw:style-name attribute that refers to a style in the <office:automatic-styles> section of the file.

Warning

The layout of a page is controlled by the style.xml’s <style:presentation-page-layout> elements as described in the section called “Page Layouts in styles.xml”. If you set the location and size attributes for a particular element in the content.xml file, they will not take effect unless you also set the presentation:user-transformed to true.

If a slide doesn’t have content yet (it shows up as “Click for title/text/chart” in OpenOffice.org), that means that the element has its presentation:placeholder attribute set to true.

The <draw:frame> for text boxes has additional presentation:style-name and draw:text-style-name attributes. The children of the <draw:text-box> element will normally be <text:p> elements for titles and <text:list> elements for outlines. (Of course, if you add anything other than the defaults, such as an ordered list, that will also go into the <draw:text-box>. Example 7.2, “Text Boxes for a Page with Title and Two Outlines” shows the text boxes for a page with a title and a left and right outline, each containing one item.

Clip art is represented by a <draw:image> element, with attributes exactly as described in the section called “Body Information for Images in Text”. Embedded spreadsheets and charts are represented by a <draw:object> element. Images and objects have these attributes in common:

  • xlink:href, whose value is a local URL
  • xlink:type, always set to simple
  • xlink:show, always set to embed, and
  • xlink:actuate, always set to onLoad

Example 7.3, “Clip Art and Spreadsheet in a Presentation” shows the XML for clip art and an embedded spreadsheet.

Finally, each slide can have notes which are represented by a <presentation:notes> element with two children. The <draw:page-thumbnail> child element gives the size and position of the slide thumbnail, and has a presentation:class of page. The draw:page-number attribute tells which slide should be thumbnailed. The following <draw:frame> element’s child <draw:text-box> contains (naturally enough) the notes for the slide, and has a presentation:class of notes. Example 7.4, “Presentation Notes” shows the relevant XML.

It is also possible to use elements borrowed from the Synchronized Multimedia Integration Language (SMIL) specification to animate text on a slide. These elements come after the text and before the notes. A full discussion of SMIL is well beyond the scope of this book, so we will just show Example 7.5, “Simple SMIL animation”, which is the XML for an animation that has text fly in from the left:

1 The children of the anim:par element are all animated in parallel; the children of the anim:seq element are animated in sequence.
2 The smil:fill has nothing to do with filling areas with colors; it tells the animation engine how to fill the time after part of the animation is done. The value of hold means to hold the animated object at its ending position rather than remove it.
3 If you are building a presentation programmatically, you do not need to include these attributes. The presentation will display properly, but the application will not be aware that any animation has been associated with the slide when you edit it.
4 The first part of the animation simply makes the object appear.
5 The anim:animate elements move the x coordinate in increasing values while leaving y unchanged. The smil:keyTimes give the “breakpoints” for the animation as floating point numbers, where 0 is the beginning of the duration and 1 is the end.

Transitions from one slide to the next are controlled by attributes in the style:style that is associated with a slide (it will have a style:family="drawing-page" attribute).

The <style:style> element will contain a <style:drawing-page-properties> element that sets the presentation:transition-speed, smil:type and smil:subtype attributes. The speed may be one of slow, medium, or fast. There are lots of transition types and subtypes, fully summarized in the SMIL recommendation at http://www.w3.org/TR/SMIL/. Here is a table of just a few of the possibilities:

To include a sound with a slide transition, you insert a <presentation:sound> element in the slide’s controlling <style:style>. The <presentation:sound> has an xlink:href whose value is the path to the sound file. Other attributes should be set as xlink:type="simple", xlink:show="new", and xlink:actuate="onRequest".

If you wish to have a draw:frame respond to a mouse click, add code like this between the opening and closing tags of the object:

The presentation:action attribute can have a value of none (the default), previous-page, next-page, first-page, last-page, hide (hides the object), fade-out (fade out this object), or stop (exits the slideshow). These values require no additional information.

The presentation:action values of show (display a specific slide), execute (run a program), and sound require extra information. Running a macro in response to a mouse click is done in an entirely different manner altogether, and, since we have not covered scripting in this book, we will not discuss that option. Example 7.6, “XML for Presentation Actions Requiring Extra Information” shows the XML for showing slides, running programs, and playing sounds in response to a mouse click. In this example, all the actions are connected with text boxes. The position and size attributes for the frames are not shown. In the code for playing a sound, note that the <presentation:sound> element becomes a child of the <presentation:event-listener> element.

In this case study, we will use Perl to create (literally) a slide show from a series of photographs such as one might take on vacation.[12] The input file is a simple text file consisting of alternating file names and descriptions:

dscn0134_a.jpg
Rubies at Smithsonian Institution
dscn0157_a.jpg
Mt. Rushmore
dscn0181_a.jpg
Devil's Tower National Monument
dscn0210_a.jpg
Buffalo at Yellowstone
dscn0242_a.jpg
Old Faithful
dscn0274_a.jpg
Grand Teton
dscn0329_a.jpg
Baby Llama

Our slide show will place the description at the top of the page and the picture beneath it. We will have “Next” and “Back” buttons at the bottom of each slide, with the exception of the first and last slides, which won’t let you fall off the edge of the earth. We will also have transitions for the slides; they will move onto the screen from the left.

The program starts off with variable declarations, and grabs two arguments from the command line: the file name containing the picture list, and an output file name. [You will find the pictures, the picture list (file piclist.txt), and the program (file make_slideshow.pl) in directory ch07 in the downloadable example files.]


#!/usr/bin/perl
use strict;
use warnings;

use Archive::Zip;
use File::Spec;

my  $file_name;         # file name to insert in slide show
my  $description;       # description of the slide
my  ($width, $height);  # height and width of a picture
my  $left_edge;         # where left edge of picture begins

my  $archive;           # zip archive
my  $content_filename;  # name of content file
my  $styles_filename;   # name of styles file
my  @piclist;           # stores picture file names and descriptions

my  $i;                 # ubiquitous loop counter
my  $slide_number;      # current slide number

#
#   This program requires two arguments: the picture list
#   and the output file name.

if (scalar @ARGV != 2)
{
    print "Usage: $0 picturelist outputFilename\n";
    exit;
}

Because we don’t know how many pictures there are a priori, and we need to do something special on the last picture, we will have to read all the picture names and descriptions into an array for future use:

#   Read the picture file names and their descriptions
#   into an array.
#
open INFILE, "<$ARGV[0]" or die("Cannot find file $ARGV[0]");
while (<INFILE>)
{
    chomp;
    next if (m/^\s*$/); # skip blank lines
    push @piclist, $_;
}
close INFILE;

The code continues by setting up a new .ZIP archive and adding the subdirectory for the images. We call File::Spec->tmpdir() to provide a temporary directory for storing the META-INF/manifest.xml, styles.xml, and content.xml that we will be creating. To make the program easier to read, we separate the creation of the manifest and style files into separate subroutines. The styles file has constant contents, so we will leave it for last.

#
#   Create a .ZIP archive
#
$archive = Archive::Zip->new( );

#
#   Add a directory for the images
#
$archive->addDirectory( "Pictures" );

#
#   create a temporary file for the manifest,
#   create the META-INF/manifest.xml file, and
#   add it to the archive
#
$manifest_filename = File::Spec->catfile(File::Spec->tmpdir(),
    "manifest.xml");
open MANIFESTFILE, ">$manifest_filename" or
    die("Cannot open $manifest_filename");

create_manifest_file( );

close MANIFESTFILE;
$archive->addFile( $manifest_filename , "META-INF/manifest.xml" );

#   create a temporary file for styles,
#   create the styles.xml file, and
#   add it to the archive.
#
$styles_filename = File::Spec->catfile(File::Spec->tmpdir(), "styles.xml");
open STYLESFILE, ">$styles_filename" or
    die("Cannot open $styles_filename");

create_styles_file( );

close STYLESFILE;
$archive->addFile( $styles_filename , "styles.xml" );

The manifest file’s contents depend upon the pictures, so here’s the code for creating the manifest file:

sub create_manifest_file
{
    print MANIFESTFILE << "MANIFEST";
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE manifest:manifest
    PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
<manifest:manifest
    xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
    <manifest:file-entry
        manifest:media-type="application/vnd.oasis.opendocument.presentation"
        manifest:full-path="/"/>
    <manifest:file-entry manifest:media-type="text/xml"
        manifest:full-path="content.xml"/>
    <manifest:file-entry manifest:media-type="text/xml"
        manifest:full-path="styles.xml"/>
    <manifest:file-entry manifest:media-type="text/xml"
        manifest:full-path="meta.xml"/>
    <manifest:file-entry manifest:media-type=""
        manifest:full-path="Pictures/"/>
MANIFEST
    for ($i=0; $i < @piclist; $i += 2)
    {
        print MANIFESTFILE
            qq!<manifest:file-entry manifest:media-type="image/jpeg"!,
            qq! manifest:full-path="Pictures/$piclist[$i]"/>\n!;
    }
    print MANIFESTFILE "</manifest:manifest>\n";
}

We now create the main part of the content file.

#   create a temporary file for content
#
$content_filename = File::Spec->catfile(File::Spec->tmpdir(),
    "content.xml");
open CONTENTFILE, ">$content_filename" or
    die("Cannot open $content_filename");


insert_header(); 1

for ($i=0; $i < @piclist; $i += 2)
{
    $slide_number = ($i / 2) + 1;
    ($file_name, $description) = @piclist[$i,$i+1];
    
    ($width, $height) = get_jpg_dimensions($file_name);
    
    # Presume that pictures are 72 dpi; convert width & height
    # to centimeters.

    $width = ($width / 72) * 2.54;
    $height = ($height / 72) * 2.54;
    $left_edge = (27.94-$width) / 2; 2
    
    $archive->addFile( $file_name, "Pictures/$file_name");
    print CONTENTFILE << "ONE_PAGE";
<draw:page draw:name="page$slide_number"
 draw:master-page-name="PM1" draw:style-name="dp7"
 presentation:presentation-page-layout-name="slidepage">
    <draw:frame draw:layer="layout" presentation:class="title"
        presentation:style-name="standard"
        svg:x="4.5cm" svg:y="2.25cm"
        svg:width="20cm" svg:height="2cm">
        <draw:text-box>
            <text:p text:style-name="P1">$description</text:p>
        </draw:text-box>
    </draw:frame>
    <draw:frame draw:layer="layout"
      svg:width="${width}cm" svg:height="${height}cm"
      svg:x="${left_edge}cm" svg:y="4cm">
        <draw:image
            xlink:href="Pictures/$file_name"
            xlink:type="simple" xlink:show="embed"
            xlink:actuate="onLoad"/>
    </draw:frame>
ONE_PAGE
    if ($slide_number != 1)
    {
        insert_back_button();
    }
    if ($slide_number != int(@piclist/2))
    {
        insert_next_button();
    }
    print CONTENTFILE "</draw:page>\n";

}

insert_footer();  3

close CONTENTFILE;

$archive->addFile( $content_filename , "content.xml" );
$archive->overwriteAs( $ARGV[1] );

unlink $styles_filename; 4
unlink $content_filename;
unlink $manifest_filename;

1 This subroutine provides the boilerplate for the root element, namespaces, and <office:automatic-styles> for the content file.
2 The $left_edge variable lets us center the picture horizontally on the slide.
3 This subroutine provides the boilerplate for the closing tags in the content section.
4 This deletes the temporary files once the OpenDocument file is complete.

The code to insert the next and back buttons shows the use of interaction:

sub insert_back_button
{
    print CONTENTFILE << "BACK_BUTTON";
<draw:rect draw:layer="layout" draw:text-style-name="centered"
 svg:x="2.2cm" svg:y="18.3cm"
 svg:width="2cm" svg:height="1cm"
 draw:style-name="buttonborderstyle">
    <office:event-listeners>
        <presentation:event-listener script:event-name="dom:click"
         presentation:action="previous-page"/>
    </office:event-listeners>   
    <text:p text:style-name="P1">
        <text:span text:style-name="buttontext">Back</text:span>
    </text:p>
</draw:rect>
BACK_BUTTON
}

sub insert_next_button
{
    print CONTENTFILE << "NEXT_BUTTON";
<draw:rect draw:layer="layout"
 svg:x="24cm" svg:y="18.3cm"
 svg:width="2cm" svg:height="1cm"
 draw:style-name="buttonborderstyle">
    <office:event-listeners>
        <presentation:event-listener script:event-name="dom:click"
         presentation:action="next-page"/>
    </office:event-listeners>   
    <text:p text:style-name="P1">
        <text:span text:style-name="buttontext">Next</text:span>
    </text:p>
</draw:rect>
NEXT_BUTTON
}

Here’s the code that inserts the heading material into the content.xml file. Note the presentation:transition-style in the <style:style> named dp1.

sub insert_header
{
    print CONTENTFILE <<"HEADER";
<?xml version="1.0" encoding="UTF-8"?>
<office:document-content
    xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
    xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
    xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
    xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
    xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
    xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
    xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
    xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
    xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
    xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
    xmlns:dom="http://www.w3.org/2001/xml-events"
    office:version="1.0">
 <office:scripts/>
 <office:automatic-styles>
    <style:style style:name="dp1" style:family="drawing-page">
        <style:properties
         presentation:transition-speed="medium"
         presentation:background-visible="true"
         presentation:background-objects-visible="true"
         smil:type="barWipe"
         smil:subtype="leftToRight"/>
    </style:style>
    <style:style style:name="P1" style:family="paragraph">
        <style:paragraph-properties fo:text-align="center"/>
        <style:text-properties fo:font-size="18pt"/>
    </style:style>
    <style:style style:name="buttonborderstyle" style:family="graphic">
        <style:graphic-properties
            draw:stroke="solid"
            svg:stroke-width="0.05cm"
            svg:stroke-color="#cccccc"
            draw:fill="solid" draw:fill-color="#ffffcc"/>
    </style:style>
    <style:style style:name="buttontext" style:family="text">
        <style:text-properties
            fo:font-family="Helvetica"
            style:font-family-generic="swiss"
            fo:font-size="10pt"/>
    </style:style>
 </office:automatic-styles>
 <office:body>
    <office:presentation>
HEADER
}

sub insert_footer
{
    print CONTENTFILE <<"FOOTER";
    </office:presentation>
 </office:body>
</office:document-content>
FOOTER
}

Finally, we have the code to create the information in the styles.xml file. It is pure boilerplate, adapted from an existing presentation file, with lots of unnecessary information removed.

sub create_styles_file
{
    print STYLESFILE << "STYLES";
<office:document-styles
 xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
 xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
 xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
 xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
 xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
 xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
 xmlns:dom="http://www.w3.org/2001/xml-events"
 office:version="1.0">

<office:styles>
    <style:presentation-page-layout style:name="slidepage">
        <presentation:placeholder presentation:object="title"
          svg:x="4.5cm" svg:y="2.25cm"
          svg:width="20cm" svg:height="2cm"/>
        <presentation:placeholder presentation:object="graphic"
          svg:x="2cm" svg:y="5.5cm"
          svg:width="20cm" svg:height="13cm"/>
    </style:presentation-page-layout>
</office:styles>

<office:automatic-styles>
    <style:page-master style:name="PM1">
        <style:properties
         fo:margin-top="1cm" fo:margin-bottom="1cm"
         fo:margin-left="1cm" fo:margin-right="1cm"
         fo:page-width="27.94cm" fo:page-height="21.59cm"
         style:print-orientation="landscape"/>
    </style:page-master>
</office:automatic-styles>

<office:master-styles>
    <draw:layer-set>
        <draw:layer draw:name="layout"/>
        <draw:layer draw:name="background"/>
        <draw:layer draw:name="backgroundobjects"/>
        <draw:layer draw:name="controls"/>
        <draw:layer draw:name="measurelines"/>
    </draw:layer-set>

    <style:master-page style:name="Default" style:page-master-name="PM1"
     draw:style-name="dp1">
    </style:master-page>
</office:master-styles>

</office:document-styles>
STYLES
}

We are omitting the get_jpg_dimensions code that gets the width and height of a JPEG; it is not relevant to creating the OpenDocument file. If you are interested in seeing it, just download it from the book's Web site.



[12] Thanks to my brother Steve, who provided photos from his vacation for the sample files.


Copyright (c) 2005 O’Reilly & Associates, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".