]> granicus.if.org Git - docbook-dsssl/commitdiff
Reworked support for graphic attributes; now support DocBook 4.2CR1 attributes
authorNorman Walsh <ndw@nwalsh.com>
Sun, 12 May 2002 11:21:15 +0000 (11:21 +0000)
committerNorman Walsh <ndw@nwalsh.com>
Sun, 12 May 2002 11:21:15 +0000 (11:21 +0000)
xsl/html/graphics.xsl

index 0b7acef182e79fb6cd4bb08e647cd6f813ce3f68..887fe27516f840b1e9680bb64eef262de03844c6 100644 (file)
@@ -2,9 +2,11 @@
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:xlink="http://www.w3.org/1999/xlink"
                 xmlns:stext="http://nwalsh.com/xslt/ext/com.nwalsh.saxon.TextFactory"
+                xmlns:simg="http://nwalsh.com/xslt/ext/com.nwalsh.saxon.ImageIntrinsics"
+                xmlns:ximg="xaln://com.nwalsh.xalan.ImageIntrinsics"
                 xmlns:xtext="com.nwalsh.xalan.Text"
                 xmlns:lxslt="http://xml.apache.org/xslt"
-                exclude-result-prefixes="xlink stext xtext lxslt"
+                exclude-result-prefixes="xlink stext xtext lxslt simg ximg"
                 extension-element-prefixes="stext xtext"
                 version='1.0'>
 
@@ -21,8 +23,9 @@
 
      ******************************************************************** -->
 
-<lxslt:component prefix="xtext"
-                 elements="insertfile"/>
+<lxslt:component prefix="xtext" elements="insertfile"/>
+
+<lxslt:component prefix="ximg" functions="new getWidth getDepth"/>
 
 <!-- ==================================================================== -->
 <!-- Graphic format tests for the HTML backend -->
 
 <!-- ==================================================================== -->
 
+<xsl:param name="nominal.image.width" select="6 * $pixels.per.inch"/>
+<xsl:param name="nominal.image.depth" select="4 * $pixels.per.inch"/>
+<xsl:param name="make.graphic.viewport" select="1"/>
+
 <xsl:template name="process.image">
   <!-- When this template is called, the current node should be  -->
   <!-- a graphic, inlinegraphic, imagedata, or videodata. All    -->
   <xsl:param name="alt"/>
   <xsl:param name="longdesc"/>
 
+  <!-- The HTML img element only supports the notion of content-area
+       scaling; it doesn't support the distinction between a
+       content-area and a viewport-area, so we have to make some
+       compromises.
+
+       1. If only the content-area is specified, everything is fine.
+          (If you ask for a three inch image, that's what you'll get.)
+
+       2. If only the viewport-area is provided:
+          - If scalefit=1, treat it as both the content-area and
+            the viewport-area. (If you ask for an image in a five inch
+            area, we'll make the image five inches to fill that area.)
+          - If scalefit=0, ignore the viewport-area specification.
+
+          Note: this is not quite the right semantic and has the additional
+          problem that it can result in anamorphic scaling, which scalefit
+          should never cause.
+
+       3. If both the content-area and the viewport-area is specified
+          on a graphic element, ignore the viewport-area.
+          (If you ask for a three inch image in a five inch area, we'll assume
+           it's better to give you a three inch image in an unspecified area
+           than a five inch image in a five inch area.
+
+       Relative units also cause problems. As a general rule, the stylesheets
+       are operating too early and too loosely coupled with the rendering engine
+       to know things like the current font size or the actual dimensions of
+       an image. Therefore:
+
+       1. We use a fixed size for pixels, $pixels.per.inch
+
+       2. We use a fixed size for "em"s, $points.per.em
+
+       Percentages are problematic. In the following discussion, we speak
+       of width and contentwidth, but the same issues apply to depth and
+       contentdepth
+
+       1. A width of 50% means "half of the available space for the image."
+          That's fine. But note that in HTML, this is a dynamic property and
+          the image size will vary if the browser window is resized.
+
+       2. A contentwidth of 50% means "half of the actual image width". But
+          the stylesheets have no way to assess the image's actual size. Treating
+          this as a width of 50% is one possibility, but it produces behavior
+          (dynamic scaling) that seems entirely out of character with the
+          meaning.
+
+          Instead, the stylesheets define a $nominal.image.width
+          and convert percentages to actual values based on that nominal size.
+
+       Scale can be problematic. Scale applies to the contentwidth, so
+       a scale of 50 when a contentwidth is not specified is analagous to a
+       width of 50%. (If a contentwidth is specified, the scaling factor can
+       be applied to that value and no problem exists.)
+
+       If scale is specified but contentwidth is not supplied, the
+       nominal.image.width is used to calculate a base size
+       for scaling.
+
+       Warning: as a consequence of these decisions, unless the aspect ratio
+       of your image happens to be exactly the same as (nominal width / nominal height),
+       specifying contentwidth="50%" and contentdepth="50%" is NOT going to
+       scale the way you expect (or really, the way it should).
+
+       Don't do that. In fact, a percentage value is not recommended for content
+       size at all. Use scale instead.
+
+       Finally, align and valign are troublesome. Horizontal alignment is now
+       supported by wrapping the image in a <div align="{@align}"> (in block
+       contexts!). I can't think of anything (practical) to do about vertical
+       alignment.
+  -->
+
+  <xsl:variable name="scalefit">
+    <xsl:choose>
+      <xsl:when test="@contentwidth or @contentdepth">0</xsl:when>
+      <xsl:when test="@scale">0</xsl:when>
+      <xsl:when test="@scalefit"><xsl:value-of select="@scalefit"/></xsl:when>
+      <xsl:when test="@width or @depth">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="scale">
+    <xsl:choose>
+      <xsl:when test="@contentwidth or @contentdepth">1.0</xsl:when>
+      <xsl:when test="@scale">
+        <xsl:value-of select="@scale div 100.0"/>
+      </xsl:when>
+      <xsl:otherwise>1.0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
   <xsl:variable name="filename">
     <xsl:choose>
       <xsl:when test="local-name(.) = 'graphic'
     </xsl:choose>
   </xsl:variable>
 
-  <xsl:variable name="width">
+  <xsl:variable name="intrinsicwidth">
     <xsl:choose>
-      <xsl:when test="@scale"><xsl:value-of select="@scale"/>%</xsl:when>
-      <xsl:when test="@width">
-        <xsl:variable name="w-magnitude">
-          <xsl:call-template name="length-magnitude">
-            <xsl:with-param name="length" select="@width"/>
-          </xsl:call-template>
-        </xsl:variable>
-        <xsl:variable name="w-units">
+      <xsl:when test="function-available('simg:getWidth')">
+        <xsl:value-of select="simg:getWidth(simg:new($filename), $nominal.image.width)"/>
+      </xsl:when>
+      <xsl:when test="function-available('ximg:getWidth')">
+        <xsl:value-of select="ximg:getWidth(ximg:new($filename), $nominal.image.width)"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$nominal.image.width"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="intrinsicdepth">
+    <xsl:choose>
+      <xsl:when test="function-available('simg:getDepth')">
+        <xsl:value-of select="simg:getDepth(simg:new($filename), $nominal.image.depth)"/>
+      </xsl:when>
+      <xsl:when test="function-available('ximg:getDepth')">
+        <xsl:value-of select="ximg:getDepth(ximg:new($filename), $nominal.image.width)"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$nominal.image.depth"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="contentwidth">
+    <xsl:choose>
+      <xsl:when test="@contentwidth">
+        <xsl:variable name="units">
           <xsl:call-template name="length-units">
-            <xsl:with-param name="length" select="@width"/>
-            <xsl:with-param name="default.units" select="'px'"/>
+            <xsl:with-param name="length" select="@contentwidth"/>
           </xsl:call-template>
         </xsl:variable>
 
         <xsl:choose>
-          <xsl:when test="$w-units = '%'">
-            <xsl:value-of select="@width"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'cm'">
-            <xsl:value-of select="round(($w-magnitude div 2.54) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'mm'">
-            <xsl:value-of select="round(($w-magnitude div 25.4) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'in'">
-            <xsl:value-of select="round($w-magnitude * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'pt'">
-            <xsl:value-of select="round(($w-magnitude div 72) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'pc'">
-            <xsl:value-of select="round(($w-magnitude div 6) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'px'">
-            <xsl:value-of select="$w-magnitude"/>
-          </xsl:when>
-          <xsl:when test="$w-units = 'em'">
-            <xsl:message>
-              <xsl:text>Relative units (ems) are not supported on widths.  </xsl:text>
-              <xsl:text>Using 12pt/em.</xsl:text>
-            </xsl:message>
-            <xsl:value-of select="round((($w-magnitude * 12) div 72) * $pixels.per.inch)"/>
+          <xsl:when test="$units = '%'">
+            <xsl:variable name="cmagnitude">
+              <xsl:call-template name="length-magnitude">
+                <xsl:with-param name="length" select="@contentwidth"/>
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:value-of select="$intrinsicwidth * $cmagnitude div 100.0"/>
+            <xsl:text>px</xsl:text>
           </xsl:when>
           <xsl:otherwise>
-            <xsl:message>
-              <xsl:text>Unrecognized unit given for width: </xsl:text>
-              <xsl:value-of select="$w-units"/>
-              <xsl:text>. Treating as px.</xsl:text>
-              <xsl:value-of select="$w-magnitude"/>
-            </xsl:message>
+            <xsl:call-template name="length-spec">
+              <xsl:with-param name="length" select="@contentwidth"/>
+            </xsl:call-template>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
-      <xsl:otherwise></xsl:otherwise>
+      <xsl:otherwise>
+        <xsl:value-of select="$intrinsicwidth"/>
+        <xsl:text>px</xsl:text>
+      </xsl:otherwise>
     </xsl:choose>
   </xsl:variable>
 
-  <xsl:variable name="height">
+  <xsl:variable name="scaled.contentwidth">
+    <xsl:if test="$contentwidth != ''">
+      <xsl:variable name="cwidth.in.points">
+        <xsl:call-template name="length-in-points">
+          <xsl:with-param name="length" select="$contentwidth"/>
+          <xsl:with-param name="pixels.per.inch" select="$pixels.per.inch"/>
+          <xsl:with-param name="em.size" select="$points.per.em"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:value-of select="$cwidth.in.points div 72.0 * $pixels.per.inch * $scale"/>
+    </xsl:if>
+  </xsl:variable>
+
+  <xsl:variable name="width-units">
+    <xsl:if test="@width">
+      <xsl:call-template name="length-units">
+        <xsl:with-param name="length" select="@width"/>
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:variable>
+
+  <xsl:variable name="width">
+    <xsl:if test="@width">
+      <xsl:choose>
+        <xsl:when test="$width-units = '%'">
+          <xsl:value-of select="@width"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="length-spec">
+            <xsl:with-param name="length" select="@width"/>
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:variable>
+
+  <xsl:variable name="html.width">
     <xsl:choose>
-      <xsl:when test="@scale"></xsl:when>
-      <xsl:when test="@depth">
-        <xsl:variable name="d-magnitude">
-          <xsl:call-template name="length-magnitude">
-            <xsl:with-param name="length" select="@depth"/>
+      <xsl:when test="$width-units = '%'">
+        <xsl:value-of select="$width"/>
+      </xsl:when>
+      <xsl:when test="@width and @width != ''">
+        <xsl:variable name="width.in.points">
+          <xsl:call-template name="length-in-points">
+            <xsl:with-param name="length" select="$width"/>
+            <xsl:with-param name="pixels.per.inch" select="$pixels.per.inch"/>
+            <xsl:with-param name="em.size" select="$points.per.em"/>
           </xsl:call-template>
         </xsl:variable>
-        <xsl:variable name="d-units">
+        <xsl:value-of select="$width.in.points div 72.0 * $pixels.per.inch"/>
+      </xsl:when>
+      <xsl:otherwise></xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="contentdepth">
+    <xsl:choose>
+      <xsl:when test="@contentdepth">
+        <xsl:variable name="units">
           <xsl:call-template name="length-units">
-            <xsl:with-param name="length" select="@depth"/>
-            <xsl:with-param name="default.units" select="'px'"/>
+            <xsl:with-param name="length" select="@contentdepth"/>
           </xsl:call-template>
         </xsl:variable>
 
         <xsl:choose>
-          <xsl:when test="$d-units = '%'">
-            <xsl:value-of select="@depth"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'cm'">
-            <xsl:value-of select="round(($d-magnitude div 2.54) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'mm'">
-            <xsl:value-of select="round(($d-magnitude div 25.4) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'in'">
-            <xsl:value-of select="round($d-magnitude * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'pt'">
-            <xsl:value-of select="round(($d-magnitude div 72) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'pc'">
-            <xsl:value-of select="round(($d-magnitude div 6) * $pixels.per.inch)"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'px'">
-            <xsl:value-of select="$d-magnitude"/>
-          </xsl:when>
-          <xsl:when test="$d-units = 'em'">
-            <xsl:message>
-              <xsl:text>Relative units (ems) are not supported on depths.  </xsl:text>
-              <xsl:text>Using 12pt/em.</xsl:text>
-            </xsl:message>
-            <xsl:value-of select="round((($d-magnitude * 12) div 72) * $pixels.per.inch)"/>
+          <xsl:when test="$units = '%'">
+            <xsl:variable name="cmagnitude">
+              <xsl:call-template name="length-magnitude">
+                <xsl:with-param name="length" select="@contentdepth"/>
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:value-of select="$intrinsicdepth * $cmagnitude div 100.0"/>
+            <xsl:text>px</xsl:text>
           </xsl:when>
           <xsl:otherwise>
-            <xsl:message>
-              <xsl:text>Unrecognized unit given for depth: </xsl:text>
-              <xsl:value-of select="$d-units"/>
-              <xsl:text>. Treating as px.</xsl:text>
-              <xsl:value-of select="$d-magnitude"/>
-            </xsl:message>
+            <xsl:call-template name="length-spec">
+              <xsl:with-param name="length" select="@contentdepth"/>
+            </xsl:call-template>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
-      <xsl:otherwise></xsl:otherwise>
+      <xsl:otherwise>
+        <xsl:value-of select="$intrinsicdepth"/>
+        <xsl:text>px</xsl:text>
+      </xsl:otherwise>
     </xsl:choose>
   </xsl:variable>
 
-  <xsl:variable name="align">
-    <xsl:value-of select="@align"/>
+  <xsl:variable name="scaled.contentdepth">
+    <xsl:if test="$contentdepth != ''">
+      <xsl:variable name="cdepth.in.points">
+        <xsl:call-template name="length-in-points">
+          <xsl:with-param name="length" select="$contentdepth"/>
+          <xsl:with-param name="pixels.per.inch" select="$pixels.per.inch"/>
+          <xsl:with-param name="em.size" select="$points.per.em"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:value-of select="$cdepth.in.points div 72.0 * $pixels.per.inch * $scale"/>
+    </xsl:if>
   </xsl:variable>
 
-  <xsl:element name="{$tag}">
-    <xsl:attribute name="src">
-      <xsl:value-of select="$filename"/>
-    </xsl:attribute>
-    <xsl:if test="$align != ''">
-      <xsl:attribute name="align">
-        <xsl:value-of select="$align"/>
-      </xsl:attribute>
-    </xsl:if>
-    <xsl:if test="$height != ''">
-      <xsl:attribute name="height">
-        <xsl:value-of select="$height"/>
-      </xsl:attribute>
-    </xsl:if>
-    <xsl:if test="$width != ''">
-      <xsl:attribute name="width">
-        <xsl:value-of select="$width"/>
-      </xsl:attribute>
+  <xsl:variable name="depth-units">
+    <xsl:if test="@depth">
+      <xsl:call-template name="length-units">
+        <xsl:with-param name="length" select="@depth"/>
+      </xsl:call-template>
     </xsl:if>
-    <xsl:if test="$alt != ''">
-      <xsl:attribute name="alt">
-        <xsl:value-of select="$alt"/>
-      </xsl:attribute>
+  </xsl:variable>
+
+  <xsl:variable name="depth">
+    <xsl:if test="@depth">
+      <xsl:choose>
+        <xsl:when test="$depth-units = '%'">
+          <xsl:value-of select="@depth"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="length-spec">
+            <xsl:with-param name="length" select="@depth"/>
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
     </xsl:if>
-    <xsl:if test="$longdesc != ''">
-      <xsl:attribute name="longdesc">
-        <xsl:value-of select="$longdesc"/>
+  </xsl:variable>
+
+  <xsl:variable name="html.depth">
+    <xsl:choose>
+      <xsl:when test="$depth-units = '%'">
+        <xsl:value-of select="$depth"/>
+      </xsl:when>
+      <xsl:when test="@depth and @depth != ''">
+        <xsl:variable name="depth.in.points">
+          <xsl:call-template name="length-in-points">
+            <xsl:with-param name="length" select="$depth"/>
+            <xsl:with-param name="pixels.per.inch" select="$pixels.per.inch"/>
+            <xsl:with-param name="em.size" select="$points.per.em"/>
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:value-of select="$depth.in.points div 72.0 * $pixels.per.inch"/>
+      </xsl:when>
+      <xsl:otherwise></xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="viewport">
+    <xsl:choose>
+      <xsl:when test="inlinegraphic
+                      | ancestor::inlinemediaobject
+                      | ancestor::inlineequation">0</xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$make.graphic.viewport"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+<!--
+  <xsl:message>=====================================
+scale: <xsl:value-of select="$scale"/>, <xsl:value-of select="$scalefit"/>
+@contentwidth <xsl:value-of select="@contentwidth"/>
+$contentwidth <xsl:value-of select="$contentwidth"/>
+scaled.contentwidth: <xsl:value-of select="$scaled.contentwidth"/>
+@width: <xsl:value-of select="@width"/>
+width: <xsl:value-of select="$width"/>
+html.width: <xsl:value-of select="$html.width"/>
+@contentdepth <xsl:value-of select="@contentdepth"/>
+$contentdepth <xsl:value-of select="$contentdepth"/>
+scaled.contentdepth: <xsl:value-of select="$scaled.contentdepth"/>
+@depth: <xsl:value-of select="@depth"/>
+depth: <xsl:value-of select="$depth"/>
+html.depth: <xsl:value-of select="$html.depth"/>
+align: <xsl:value-of select="@align"/>
+valign: <xsl:value-of select="@valign"/></xsl:message>
+-->
+
+  <xsl:variable name="img">
+    <xsl:element name="{$tag}">
+      <xsl:attribute name="src">
+        <xsl:value-of select="$filename"/>
       </xsl:attribute>
-    </xsl:if>
-  </xsl:element>
+
+      <xsl:choose>
+        <xsl:when test="@contentwidth or @contentdepth">
+          <!-- ignore @width/@depth, @scale, and @scalefit if specified -->
+          <xsl:if test="@contentwidth">
+            <xsl:attribute name="width">
+              <xsl:value-of select="$scaled.contentwidth"/>
+            </xsl:attribute>
+          </xsl:if>
+          <xsl:if test="@contentdepth">
+            <xsl:attribute name="height">
+              <xsl:value-of select="$scaled.contentdepth"/>
+            </xsl:attribute>
+          </xsl:if>
+        </xsl:when>
+
+        <xsl:when test="$scale != 1.0">
+          <!-- scaling is always uniform, so we only have to specify one dimension -->
+          <!-- ignore @scalefit if specified -->
+          <xsl:attribute name="width">
+            <xsl:value-of select="$scaled.contentwidth"/>
+          </xsl:attribute>
+        </xsl:when>
+
+        <xsl:when test="$scalefit != 0">
+          <xsl:choose>
+            <xsl:when test="contains($html.width, '%')">
+              <xsl:choose>
+                <xsl:when test="$viewport != 0">
+                  <!-- The *viewport* will be scaled, so use 100% here! -->
+                  <xsl:attribute name="width">
+                    <xsl:value-of select="'100%'"/>
+                  </xsl:attribute>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:attribute name="width">
+                    <xsl:value-of select="$html.width"/>
+                  </xsl:attribute>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="contains($html.depth, '%')">
+              <!-- HTML doesn't deal with this case very well...do nothing -->
+            </xsl:when>
+
+            <xsl:when test="$scaled.contentwidth != '' and $html.width != ''
+                            and $scaled.contentdepth != '' and $html.depth != ''">
+              <!-- scalefit should not be anamorphic; figure out which direction -->
+              <!-- has the limiting scale factor and scale in that direction -->
+              <xsl:choose>
+                <xsl:when test="$html.width div $scaled.contentwidth &gt;
+                                $html.depth div $scaled.contentdepth">
+                  <xsl:attribute name="height">
+                    <xsl:value-of select="$html.depth"/>
+                  </xsl:attribute>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:attribute name="width">
+                    <xsl:value-of select="$html.width"/>
+                  </xsl:attribute>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="$scaled.contentwidth != '' and $html.width != ''">
+              <xsl:attribute name="width">
+                <xsl:value-of select="$html.width"/>
+              </xsl:attribute>
+            </xsl:when>
+
+            <xsl:when test="$scaled.contentdepth != '' and $html.depth != ''">
+              <xsl:attribute name="width">
+                <xsl:value-of select="$html.width"/>
+              </xsl:attribute>
+            </xsl:when>
+          </xsl:choose>
+        </xsl:when>
+      </xsl:choose>
+
+      <xsl:if test="$alt != ''">
+        <xsl:attribute name="alt">
+          <xsl:value-of select="$alt"/>
+        </xsl:attribute>
+      </xsl:if>
+
+      <xsl:if test="$longdesc != ''">
+        <xsl:attribute name="longdesc">
+          <xsl:value-of select="$longdesc"/>
+        </xsl:attribute>
+      </xsl:if>
+
+      <xsl:if test="@align and $viewport = 0">
+        <xsl:attribute name="align">
+          <xsl:value-of select="@align"/>
+        </xsl:attribute>
+      </xsl:if>
+    </xsl:element>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="$viewport != 0">
+      <table border="0" summary="manufactured viewport for HTML img"
+             cellspacing="0" cellpadding="0">
+        <xsl:if test="$html.width != ''">
+          <xsl:attribute name="width">
+            <xsl:value-of select="$html.width"/>
+          </xsl:attribute>
+        </xsl:if>
+        <tr>
+          <xsl:if test="$html.depth != '' and $depth-units != '%'">
+            <!-- don't do this for percentages because browsers get confused -->
+            <xsl:attribute name="height">
+              <xsl:value-of select="$html.depth"/>
+            </xsl:attribute>
+          </xsl:if>
+          <td>
+            <xsl:variable name="bgcolor">
+              <xsl:call-template name="dbhtml-attribute">
+                <xsl:with-param name="pis"
+                                select="../processing-instruction('dbhtml')"/>
+                <xsl:with-param name="attribute" select="'background-color'"/>
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:if test="$bgcolor != ''">
+              <xsl:attribute name="bgcolor">
+                <xsl:value-of select="$bgcolor"/>
+              </xsl:attribute>
+            </xsl:if>
+            <xsl:if test="@align">
+              <xsl:attribute name="align">
+                <xsl:value-of select="@align"/>
+              </xsl:attribute>
+            </xsl:if>
+            <xsl:if test="@valign">
+              <xsl:attribute name="valign">
+                <xsl:value-of select="@valign"/>
+              </xsl:attribute>
+            </xsl:if>
+            <xsl:copy-of select="$img"/>
+          </td>
+        </tr>
+      </table>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy-of select="$img"/>
+    </xsl:otherwise>
+  </xsl:choose>
 </xsl:template>
 
 <!-- ==================================================================== -->