adobe-indesignidml

Identify coordinates for a visual element in idml


I need to process Indesign Idml files, generate an image, and overlay other elements over certain elements in html.

Given an Indesign Idml file (which is a package of zipped xml) and given a visual element in that file (via a tag in the xml). Is there a way to find at what coordinates on the image that visual element falls?


Solution

  • The heirarchy of containers for an image in an IDML document is as follows:

    Document [Contains] > Spread > PageItem > PlacedImage. Pages aren't used as containers, and PageItems are stored in spread coordinates, so we can forget about the Document and Page elements. if you can find a Placed Image in Spread coordinates, and rebase those coords so 0,0 is at the top left of your screen, you can position an image as it was in the InDesign document.

    A page item (which contains an image) doesn't have geometric bounds in IDML. Its bounds are stored as an array of PathPointType objects within the PathGeometry tag, like this:

    <Properties>
                <PathGeometry>
                    <GeometryPathType PathOpen="false">
                        <PathPointArray>
                            <PathPointType Anchor="-32.04 -35.04" LeftDirection="-32.04 -35.04" RightDirection="-32.04 -35.04" />
                            <PathPointType Anchor="-32.04 35.04" LeftDirection="-32.04 35.04" RightDirection="-32.04 35.04" />
                            <PathPointType Anchor="32.04 35.04" LeftDirection="32.04 35.04" RightDirection="32.04 35.04" />
                            <PathPointType Anchor="32.04 -35.04" LeftDirection="32.04 -35.04" RightDirection="32.04 -35.04" />
                        </PathPointArray>
                    </GeometryPathType>
                </PathGeometry>
            </Properties>
    

    You can calculate the bounds yourself simply enough by getting the lowest/greatest point values, assuming the border around your page item is a rectangle. Then you need the item transform,

    ItemTransform="1 0 0 1 509.27559055100005 -123.76377952749999"
    

    ...and you need to allow for where IDML thinks 0,0 is (which is the origin of the transform).

    In the X axis, 0 will be the binding location (which is variable - in a single page document it's usually the left hand edge of the spread, but in a two page document it may be the center of the spread). This is where you will need pages. BindingLocation is expressed as an integer (0 for before the first page, 1 for between first and second, etc). You find the coords of this by adding up the ItemTransforms of the preceding pages.

    In the Y axis, for reasons best known to Adobe, 0 is the vertical center of the spread (not either the top or bottom, as you might expect).

    The IDML docs have coord examples: http://www.photoshopelementsmac.com/devnet/indesign/documentation.html including translating from one coord space to another.

    Also, within a page item (which gives the geometric bounds), a placed image has its own set of graphic bounds, which can offset it further, as well as its own ItemTransform

    So, to answer your question, you would need to unpack the IDML zip file, find the image in the XML, then do a sum something like:

    // Pseudo-code:
    // Calculate PageItem GeometricBounds First as noted above
    X: (Spread.BindingLocation) + Spread.ItemTransform.tx + PageItem.itemTransform.tx + PageItem.GeometricBounds.Left + PlacedImage.ItemTransform.tx + PlacedImage.GraphicBounds.Left
    
    Y: (Half Spread Height) + Spread.ItemTransform.ty + PageItem.itemTransform.ty + PageItem.GeometricBounds.Top+ PlacedImage.ItemTransform.ty + PlacedImage.GraphicBounds.Top
    

    Oh, one more thing: all IDML coords are in points. You'll need to divide all values by 72 divided by the PPI of your screen if you want to get results in pixels.