Problems with Coordinate Systems in Word

I wrote a previous post asking about replacing text boxes with images. But now I want to resize the images based on user input. But some of my images are becoming extremely small and not the right size. I’m using points to determing the size of the picture. My first question is: How do you determine that a text box is top-level? I noticed that when this is set to true, the picture replacement works, but when it is false I get a flattened image and the size for the height and width of the text box is not in points, but in a coordinate system. So Second question is, how do I map to that coordinate system?

A top level shape is the one whose parent is a Paragraph node. Shape.IsTopLevel is the property that can determine that.

Coordinates of top level shapes are in points and specified using Shape.Width, Shape.Height. Shape.Left, Shape.Top, Shape.RelativeHorizontalPosition, Shape.RelativeVerticalPosition, Shape.HorizontalAlignment, Shape.VerticalAlignment and Shape.WrapType properties.

Shapes can be grouped in Microsoft Word documents. Shapes can be in a group shape. The group shape could be just a group shape, a diagram or drawing canvas.

Coordinates of shapes inside a group a specified using coorindate system of that group. The size of the coordinate system and its origin are specified using ShapeBase.CoordSize and ShapeBase.CoordOrigin properties.

For example, if you set ShapeBase.CoordSize to 1000, 1000 and then add a child shape whose Left and Top properties are 500, 500, then the top left corner of the child shape will be in the middle of the group shape. This type of coordinate system is used because you can resize the group shape and all the child shapes will be scaled automatically - they don't need their coordinates changes.

Microsoft Word employs this model internally (you can see that if you save a document in WordML), it corresponds to VML.

There is also ShapeBase.LocalToParent method that converts local coordinates into parent coordinates.

Sorry we don't have a great deal of documentation and code examples for drawing objects yet, but they are coming soon.

Full support for drawing objects is just great because existing textboxes, shapes, images, ole objects etc are not lost and always converted properly by Aspose.Words. We also paid attention to developing a nice public API for shapes, just the documentation is a bit lagging behind.

I can understand now why it isn’t working, but the Local toParent function is not going to help me out. As far as I can tell, the Localtoparent keeps the same system but takes it to a larger scale. I need to be able to take the group coordinate system and translate that to the word points. Or even vice versa. Do you know of a formula or function that can do this?

Please provide a sample document with a short task description. I will try to work something out for you. Maybe some improvements in API will be necessary.

Here is the code I have been using to replace textboxes with images and change their height and width is it’s less than the text box size. The problem I have occurs only when I try to resize an image when it is in the drawing canvas. I want to stick with using points rather than the coordinate system because a user looking in word for the size of the textbox cannot see the coordinate values for the drawing canvas. That’s why I’m looking for a math equation or a function to translate the coordinates for me.

Dim doc As New Aspose.Words.Document(“c:\Temp\Test.doc”)
Dim shapes As Aspose.Words.NodeCollection
Dim image As Aspose.Words.Drawing.Shape
Dim shape As Aspose.Words.Drawing.Shape

shapes = doc.GetChildNodes(Aspose.Words.NodeType.Shape, True)

Dim i As Integer
For i = 0 To shapes.Count - 1

shape = shapes(i)

If (shape.ShapeType = ShapeType.TextBox) Then


If shape.Range.Text.Trim() = “test” Then

image = New Shape(doc, ShapeType.Image)
image.ImageData.SetImage(“c:\Temp\logo.jpg”)
image.Left = shape.Left
image.Top = shape.Top

'this is here to demonstrate that you need a point and I’m not trying to convert a point.
Dim pt As PointF = New PointF(shape.Width, shape.Height)
Label3.Text = shape.LocalToParent(pt).ToString

'assuming the value isn’t a string or negative, change the size of the image using points
If shape.Width >= txtwidth.Text Then
image.Width = Double.Parse(txtwidth.Text)
Else
image.Width = shape.Width
End If

If shape.Height >= txtheight.Text Then
image.Height = txtheight.Text
Else
image.Height = shape.Height
End If

image.RelativeHorizontalPosition = shape.RelativeHorizontalPosition
image.RelativeVerticalPosition = shape.RelativeVerticalPosition
image.HorizontalAlignment = shape.HorizontalAlignment
image.VerticalAlignment = shape.VerticalAlignment
image.WrapType = shape.WrapType
image.WrapSide = shape.WrapSide


shape.ParentNode.InsertAfter(image, shape)
shape.Remove()

End If
End If

Next

doc.Save(“c:\temp\testimage.doc”)

It's a new API even for us!

There is

ShapeBase.BoundsInPoints that you can get. You cannot set it though.

To convert local to points one simply needs to iterate over all shape parents. I will probably expose this in the public API in next version, but here is how its done:

///

/// Converts a value that is in the coordinate space of the parent shape into a value in points.

/// Suitable for converting , etc of this shape into points.

///

internal PointF ParentToPoints(PointF value)

{

ShapeBase parent = ParentNode as ShapeBase;

while (parent != null)

{

value = parent.LocalToParent(value);

parent = parent.ParentNode as ShapeBase;

}

return value;

}

///

/// Gets the location and size of the containing block of the shape in points, relative to the anchor of the topmost shape.

///

public RectangleF BoundsInPoints

{

get

{

// Technically speaking, bounds of the shape are coordinates in the parent's coordinate space.

PointF topLeft = ParentToPoints(new PointF((float)Left, (float)Top));

PointF bottomRight = ParentToPoints(new PointF((float)Right, (float)Bottom));

return new RectangleF(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);

}

}

Is it possible to convert points into local?

I guess in your case it is simple math.

You know original text box size in local and in points - you can figure out a ratio.

Then when setting the image size, just multiply the size in points by that ratio.

It will work for both top level shapes whose size is in points (the ratio will be 1) and child shapes that are in local coords.

double pointToLocalRatio= textBox.Width / textBox.BoundsInPoints.Width;

image.Width = newWidthInPoints * pointToLocalRatio;

Thank you for your help!