View Cart

Kindle Image Zoom Tutorial, Part 2

KF8 "Panel View" Zoom

NOTE: This was a follow-up to the preceding essay, posted two weeks later on the 24th of March, 2012. After many questions and much discussion, as well as extensive testing during the intervening weeks, this more comprehensive disection and evaluation of the region zoom feature was composed. It would remain the preeminent essay on the topic until the release of a much expanded version in the published guidebook, How To Make Kindle Comics & Childrens' Books. It is presented here as an in-depth introduction to the subject.

KF8 Fixed Layout Image Zoom Tutorial

In this installment I'll show you how to zoom images in KF8 fixed layout ebooks using a few important variations on the code used to create text mag targets (discussed in the first part), as well as how to add a lightbox effect to dim the background surrounding the magnified area (as seen in the image on the right), and within the magnified region itself as a semi-transparent fill. In addition, I'll discuss the elements that allow you to include live text overlays on top of both the full screen and zoomed images.

The easiest way to explain how these features work is to go through an example step by step. Thus, it will be helpful if you have downloaded my template and can view the examples given there, as I'll be using the code for Page 3 here to describe the relevant elements and their variables.

NOTE: That early version of the KF8 template is no longer available, but the necessary code is pasted throughout the post below, and image captures are included as well to illustrate each point. In addition, the current Advanced Template contains numerous variations of these features for you to view.

The primary difference between text and image zooming is that with text the content is entirely contained within the magnified area, and in part determines how large the target container is. Conversely, with image zoom the mag region acts as a window through which you can see a portion of a larger, hidden image underneath. First we'll examine image zoom with live text overlays, and then we'll look at how to use a lightbox to create a semi-opaque fill.


1<div class="fs">
4<img src="your-image-source" alt="Description" class="image"/>
5 </div>
7 <div class="note">
8 <h1>Non-Magnified Text</h1>
9 </div>
11<div id="zoom1">
12<a class="app-amzn-magnify"
17<div class="center">
18<p>Double-Tap Here To Zoom</p>
22<div id="zoom1-magTargetParent" class="target-mag-parent">
23<div class="target-mag-lb"></div>
24<div id="zoom1-magTarget" class="target-mag">
25<p class="textzoom">Zoomed Text Overlay</p>
26<img src="your-image-source" alt="Description" />

This is the code before I inserted the lightbox fill addition, which I'll define and explain separately below. I've numbered the lines here to facilitate the following discussion: they're not part of the code, and the numbering you see in your file editor of choice will be relative to their position in the full page of code.

As you can see, there are four subdivisions within the overarching div container. I've used fs, by the way, for the fullscreen div container spanning lines 1-30 simply because this is Amazon's default in the provided samples, and it's as good as any; but you can name it whatever you like, so long as it matches its reference in the CSS. As with the text example discussed in the first part of this tutorial, this overarching container defines the overall size of the page, and holds all the content to be displayed.

DIV 1: LINES 3-5

In order for the image magnification to function you must use the img src= insertion method for your background image, as opposed to the div id method used on the Table of Contents page example in the template (and all the page layouts in Amazon's children's ebook sample) [NOTE: This is true of the new templates as well]. The CSS class "image" is set to use absolute positioning with a height and width equal to the full display size. The image will shrink to fit the screen while retaining its default aspect ratio. Using this insertion method, the user can double-tap the background image at any point that is not covered by a mag region, and use pinch-and-zoom to enlarge the full image to any size they desire. This is not possible with the div id insertion method, which locks the image within the div container.

This image should fill the entire page, although this does not necessarily have to be the entire display: the image above, for example, is how a standard 6x9 print book page displays on the Kindle Fire: the widescreen aspect ratio of the Fire's display leaves white space at the top and bottom.

The image you insert as the background must also be embedded at the highest resolution you want it to be zoomed to. So, for example, if you want the zoomed regions to be magnified by 150%, then this image needs to be 150% larger than it will appear when shrunk to fit the Kindle Fire screen. For a full screen image this would be 1536x900 pixels (1024x600 times 1.5). The pixels per inch, by the way, does not matter: 72 ppi will display the same as 300 ppi on the screen, since it's the number of pixels that determines its dimensions relative to the display size.

DIV 2: LINES 7-9

This div element contains any text you don't want to include in the magnified region. Here it's a simple header, but you can of course include whatever elements you like, either in a single div, or in multiple containers as needed (or none at all). Since we're using absolute positioning, these containers can overlap one another without affecting the positioning of those above or below, so long as the Tap Targets are on top (i.e. added last in the HTML code). This text can also be live if you follow my instructions given in the earlier post.

The div class references the CSS positioning data for the container, which is aligned to its top and left edges, with the width parameter used to define the right margin. So, for example, a left position of 10% combined with a width of 80% creates an equivalent right margin of 10%. A left position of 0% with a width value of 100% leaves no right margin at all, and fills the screen from edge to edge exactly. The height of the text container is determined by the content itself.

DIV 3: LINES 11-20

So now we get to the crux of the matter. This div container creates the Tap Target Zone: the area within which a double-tap activates the zoom of that region. The size and position of the Target Zone is defined by the div class values provided in the CSS:

#zoom1 {
top: 30%;
left: 15%;
height: 45%;
width: 70%;

Here the top edge of the tap zone begins 30% down from the top, 15% in from the left, extends downward a further 45% of the display height, and 70% of its width - leaving 15% on the right and 25% on the bottom not covered by the tap zone. As I mentioned in my prior post on live text, one of the benefits of activating live text by deleting the book-type metadata entry is that it causes the Tap Target Zone to appear as a gray box when touched, allowing you to see exactly where the target boundaries are. Even if you do not intend to use live text in your final product (although I can't imagine why), it will help you to position your target element here.

Within this div container is the JSON object already discussed in the first part of this tutorial. The only differences here are that the SourceId is not used (for reasons to be given shortly), and the targetId references a magTargetParent rather than the magTarget itself. We'll get to the specifics of that in a minute, but essentially this creates a link that points to the magnified element defined in the next section.

You may also notice that the CSS contains a set of values for the anchor tag (div.fs a). These define the JSON hyperlink as a block (or "Tap Target Zone") covering 100% of the div container that holds it, in both height and width, so that double-tapping anywhere within this region activates the link.

Live Text in a Kindle Fixed Layout


Normally (as far as Amazon's description is concerned, at any rate), the JSON object is all you would include in this container. However, you can include some live text here as well if you like by embedding a second div container within the first. Here I've included some instructions for the reader so they know that the region can be magnified. You might use this to add live text to a dialogue balloon in a graphic novel, for example, instead of including it in the image itself (which is not an optimal solution, for reasons I've discussed at length in other posts).

As before, the div class here references the CSS positioning data for the text container, while the content itself is formatted using header/paragraph tags as usual. This text can be as simple or complex as you like, using any HTML/CSS elements supported by KF8 (see the end section of the Kindle Publishing Guidelines or the KF8 web page for a list of accepted tags and their variables).

Bear in mind, however, that this text will not actually be magnified. Unlike the standard "children" ebook method of zooming text, which allows you to magnify the default text by using the SourceId tag, here we have to fudge the rules a little to make this work, as you'll see in the next section. Additionally, this text will not disappear as it does in the standard text zoom method unless you enclose it within the anchor tags, which I haven't done here simply for the sake of clarity in keeping the two components of this section separate (and, of course, since you'll be covering it up with an enlarged image region, it won't matter anyway).

DIV 4: LINES 22-28

Our final container holds the data that defines the magnified region itself, and here is where things get a little tricky. The div id value must equal the targetId from the JSON object, as this is the target that link is referencing. The class value defines the "parent" element, which is simply a container to enclose a number of distinct constituent elements. The parent is required here in order to create the lightbox effect, since the lightbox needs an opacity value that applies only to it, and not the zoomed content itself. If you don't intend to use a lightbox you can use a standard magTarget here and do away with the parent altogether.

You will notice that the only values applied to the target-mag-parent element in the stylesheet are a width and height of 100%, and a display value of none. The former simply makes the parent large enough to contain everything you put inside it and no larger, and the latter keeps it invisible until it's activated. Also, if you delete the lightbox element as mentioned in the previous paragraph, be sure to include the display: none entity in the magTarget CSS so that the magnified element is not visible until activated. Otherwise, it will appear by default, and disappear when double-tapped (which, by the way, might be good to know if you want something hidden underneath a larger image to appear, as might be useful in children's books).

This parent div container holds two individual sub-containers, the first being our lightbox element and the second one containing the magnified content itself.

Zoomed Image in a Lightbox

Line 23 inserts the lightbox, which is defined in the CSS by the target-mag-lb values. Like the parent element itself, the target-mag-lb values define the lightbox as covering 100% of the width and height of its content. But since the only content in the lightbox is a background fill color without any defined size parameters of its own, the lightbox defaults to the overall dimensions of the display screen, thus filling the entire page with color. The color used in Amazon's examples is a dark shade of gray, which I've retained as it seems a natural choice for dimming out an image, but of course you can use any color that you like. The opacity value determines how much this fill obscures the background image.

Now at last we come to the magnified content itself. This is held within the second sub-container, whose id value defines its size and position:

#zoom1-magTarget {
top: 21%;
left: 0%;
height: 62%;
width: 100%;

And whose class defines some values for its content: {
position: absolute;
overflow: hidden;
border: 5px solid #000000;

We'll get to size and position in a minute, as this is a rather tangled affair, but first let's dispense with some other factors. The target-mag values here are only part of the picture, as there are several sub-components entered separately. However, these provide some overall values that define how the magTarget functions...

First, it will use absolute positioning to make it easier to place exactly where we want it. The overflow value keeps the portions of the image not visible within the window hidden. And finally, we'll add a nice little border around the whole to make it stand out better. You can also use the border-radius tag to round the edges if you like, or any other decorative frills you care to add, so long as they're supported. This, incidentally, is how you might create circular magTargets for use as callout boxes or dialogue balloons: by adding a high border-radius value and a white background fill under centered text, your magnified target would look like a dialogue bubble, albeit without the pointed indicator.

In this example I've added a bit of text to overlay atop the magnified image, and this requires a bit of explanation. Since we can't use the SourceId tag to magnify the actual text on the page (since that source does not include the magnified image we also want), we must enter the alternate text here. Consequently, this can be the exact same text or something altogether different, as it is here.

p.textzoom {
font-size: 150%;
margin: 20%;
top: 18%;
z-index: 1;

I've used a separate paragraph class to define the values of the magnified text that vary from the default text, foremost of which is that it be 150% larger. The next two lines position the text where I want it in the magnified target, and the final one is what allows the text to be overlaid on top of the image rather than being forced below. Since the default z-index value is "0" any larger number will place that element higher in the vertical stack. Bear in mind that the positioning information here is relative to the magTarget boundaries, because my default paragraph has a relative position value. This actually makes it easier to position elements within the enlarged region, since it's easier to visualize their position with regard to their immediate surroundings.

Finally we come to the image itself, which is added as before using the img src= insertion method, minus the class tag. Here we're referencing the same image as the one above, but this isn't strictly necessary. You could, in fact, use this to create images that change when double-tapped, such as a facial expression or an opened door. In that case you might create an image of the same size but with different content that the double-tap or swipe would trigger. You might, in fact, have a series of events all strung together, each one triggered by sequential swipes. But I'm letting my imagination get away from me... let's get back to the matter at hand.

In the stylesheet there are a number of additional entries for the element, but with the img entity appended. The first of these defines the actual image resolution: img {
position: absolute;
height: 1536px;
width: 900px;

These are the actual dimensions of the image you've included in your file, and this entry tells the device that the image contained within the target-mag is 1536x900 pixels in size. The following entries provide values for that image various magnifications by appending a zoom factor: img.zoom100 {
position: absolute;
height: 1024px;
width: 600px;
} img.zoom150 {
position: absolute;
height: 1536px;
width: 900px;

The first of these defines the default display size, and will be the size of your page rather than the screen size; that is, as discussed earlier, whatever size your page is when fitted to the Kindle Fire screen, which may or may not be the full display resolution if the aspect ratio doesn't match. Here I'm using an image that is formatted to fit the Fire display precisely.

The second entry defines the size of that image magnified by 150%, which in this example is our default zoom factor. However, you can include as many variations on this as you wish, but to do so you will also need to include a class tag to your img src= entry in the HTML, as such:

<img class="zoom150" src="...

In this way you can magnify various panels at different zoom levels, providing your image is embedded at the size that magnification factor requires. If you only use one zoom factor throughout your book you can leave this class tag out.

One more thing should be mentioned. While the Kindle Publishing Guidelines expressly state that there are four standard zoom factors, you can in fact use any magnification level you choose. The zoom### tag is just a reference that tells the device to display the image at that size, rather than shrinking it to fit the display. But I've used other magnification factors and they work just fine. The number given after zoom doesn't even have to be the actual zoom factor used (although using another number would likely prove confusing); it's the values entered for the height and width that matter.

So now that we have our content added we need to work out how to size and position it...

Magnified Text with an Image Fill


Determining the size and placement of the magTarget window can be a matter of considerable frustration, but a little simple math can go a long way toward alleviating these headaches. Let's say that your image is like the one in the picture shown above, and you want your first magTarget to appear in the upper left corner at 150% of the display size. First you must determine how large the panel to be enlarged is, and the easiest way to do this is to open your full-page image in a graphics program such as Photoshop or GIMP. Using the rulers set to show percent, you first measure the width and height of the section to be magnified, and then multiply those dimensions by the amount of magnification to achieve your window size.

So, for example, an image section 42% wide by 35% high in the original intended to be viewed at 150% when zoomed would require a magTarget 63% by 52.5% in size. These values are entered in the stylesheet in the #name-magTarget entry (where name is the specific tag reference for that entity). Using percentages, by the way, removes the necessity of calculating pixels to percents, and "future proofs" the layout against changes in display resolution by using relative values rather than absolute ones, theoretically requiring only the change of the absolute height/width display values and replacing the actual images with higher resolution ones. I haven't been quite as consistent as I should in using percents instead of pixels myself, however.

Bear in mind, of course, that the amount of magnification determines the maximum size of an image section that can be zoomed. Thus, for an image you want to zoom by 200%, 50% x 50% is the largest section of a full page image you can isolate within a window, which in that case would be a window 100%x100% in size, covering the entire display with the enlarged section of the image. At 150%, a width and height of 66.6% would achieve the same result.

Positioning the window on the page works much the same way, although in most cases, given the larger size of the magnified region, you'll want to align it to one or more of the edges, such as left: 0% in the example given above. The width: 100% value fills the screen horizontally, while the top: 21% and height: 62% values place the image near the middle of the page vertically, with a 17% margin remaining on the bottom.

Of course, if isn't quite as simple as that once you move away from the upper left-hand corner. Since the full size image is much larger than the display screen, much of it will fall beyond the edges, beyond the reach of the window. Thus, we need another entry in the stylesheet:

#zoom1-magTarget img {
top: -77%;
left: -25%;

The image by default is positioned in the upper left-hand corner, with the overflow going off the right and bottom of the screen. Therefore, in order to view those sections of the enlarged image we need to move it up and left until the section we want to view is visible within the window. Now, if you thought you had a headache before, you're in for a real treat now.

The crucial factor here is that all values are in percentages of the magTarget size, not the actual image size, nor the display size (unless, of course, your window size is the same as the display). Thus, you need to work out how far you need to move the image, and convert that to percentages of the window you've created to view the magnified panel.

For example, let's say you have an image that is 1200 pixels wide by 2048 pixels high: that is, exactly four times the size of the Kindle Fire screen, with a window size the same width as the display (600px), but only half its height (512px), aligned to the bottom of the screen. This might be a common configuration to view a panel in the lower-right corner, for example, zoomed to fill the bottom portion of the screen.

Since the actual image by default is placed flush against the top and left of the screen, you'll need to move the image 600 pixels to the left and 1024 pixels up from its default position in order to view the lower-right quarter in a window at the bottom of the screen. Your values would therefore be left: -100% and top:-200%. That is to say, you need to move the image 100% of the width of the magTarget size (600px), and twice its height (512px x2 =1024px). It's easiest if you always place your window flush against at least one edge of the display, and preferably a corner, leaving the other two sides for adjusting the window size to fit the given panel.

Of course, it's rarely that easy, since you also need to take the window position into account, as well as any margins surrounding it if it's centered or only flush against one edge. And, of course, you've defined your magTarget window using percents not pixels, so there's a little math involved there, too. But using this same formula you can work out fairly quickly just how far you need to move the image to get it roughly where you need it. A little tweaking once it's more or less in place will ultimately get it where you want it.

Live Text with a Semi-Transparent Fill


As promised in my last post, I'm adding this addendum describing the modifications required to include a transparent background fill for your mag targets that leaves the text fully opaque. You'll need to create your default content using a parent element as we did in the example above. This allows us to include two separate div containers in the magTarget that enclose the lightbox and the text within separate entities so that they can be formatted individually.

Here's my HTML for the added content on Page 3 of the template:

<div id="zoom2">
<a class="app-amzn-magnify" data-app-amzn-magnify=
'{"targetId":"zoom2-magTargetParent", "ordinal":5}'>
<p class="note2">Default Content Here</p>

<div id="zoom2-magTargetParent" class="target-mag2-parent">
<div class="target-mag2-lb"></div>
<div id="zoom2-magTarget" class="target-mag2">
<p>Magnified Text</p>

When inserting your default content in the main div container be sure to enclose it within the anchor tag for the JSON object so that the default text will disappear when the magnified region appears. Otherwise you'll see the default content through the transparent fill. But anything contained within the JSON link will disappear. You can format this content however you like, and can, in fact, add anything you like within the anchors and it will disappear when the link is activated. However, if you use only an image or a fill (with no text), be sure to add a height value for the root container ("zoom2"), so that the TapTarget retains an active area with which to interact. Also, be sure you add the following to your CSS:

div.fs a {
display: block;
width: 100%;
height: 100%;

This will tell the JSON object to fill the space you've just provided with an active link.

For the target content you'll format the parent element the same as before, with a height and width of 100% and a display value of none to make it hidden by default. Within this you want to create a div element for your lightbox, and another for your magnified content. It's easier to fill the background after you know how large the magTarget will be, so let's format that content first:

#zoom2-magTarget {
top: 75%;
left: 0%;
display: block;
} {
position: absolute;
display: none;
font-size: 150%;
padding: 15px;
border: 5px solid #000000;
background-color: none;

First, use the div id values to size and position your magnified region. Here I've positioned it three quarters of the way down the screen and aligned it to the left edge. I haven't defined a width or height, as these will be determined by the magnified text, which in this case will fill the full width of the screen and create a box tall enough to fit it all. You can, of course, define a width less than that of the display, as I did in the first magTarget example on this page.

The class tag values are where you format the appearance of the magTarget. Unlike the image zoom example, here is where you define the zoom factor for the text content, which in this case has a magnification value of 150%. Adding a percent here allows you to multiply the default formatting by a consistent factor, rather than trying to calculate the larger pixel value. The other important change here is to set the background-color to none (or just leave it out). This creates a fully transparent container with just the content visible.

Magnified Text with a White Fill

Now that you have your magnified region active and visible you can format the lightbox to fill it in. Of course, you want the fill to be inside the magnified region rather than outside it, so you'll need to change the size and position values to match the text container. Your top and left position values will be the same as the text container itself, so just copy those. The width you've also either set or left unspecified as I have, in which case it equals 100%. But the height is a little trickier, since the text itself determines that value. You'll just have to use some educated guesswork to get it close and adjust until you get it right. {
top: 75%;
left: 0%;
height: 18.5%;
width: 100%;
background-color: #FFFFFF;
opacity: .3;

The fill itself is provided by the background-color value - here set to white - and an opacity that determines how transparent or opaque that color is, in a value ranging from 0 to 1, where 0 is invisible and 1 is completely opaque (0.5 being equivalent to 50%, and so on). You can enter the color value as a hexadecimal code as I have here, or as RGB, or simply by using names for basic colors, such as black and white. White seems the logical choice, as it appears to lighten and desaturate the underlying full page image, making the text easier to read by standing out in higher contrast against the lightened backdrop.

Here, by the way, you don't need to use a z-index to stack the text on top of the color fill as you did with the magnified image, since the background-color element is placed at the bottom by default (being a background element, after all).

That's about all I can tell you for right now, although I'm sure there much more to it than that, and more than you can do. Just use your imagination and the possibilities are likely endless.


Join Me
On Google+

View My Vids
On YouTube

envelopeSubscribe To
My Newsletter