Calculating correct zoomlevel
#1
I am trying to calcualte the correct zoomlevel for an Image inside a Zoompanel.
How do I calculate the actual zoom of my Image inside the Image control - at any ZoomPanel and Image aspect ratio and size. (zoom = display-pixelwidth of 1 image pixel).

The ZoomFactor is constant while resizing a Zoompanel. The amount of pixels shown in the encapsuled Image control is often kept constant, but sometimes it increase or decrease (especially seen when having a very asymmetric ZoomPanel control). Therefore I cannot calculate the actual zoomfactor (1 pixel in the Image takes up X pixels on the display).
I use "ZoomPanel.GetZoomFactor(viewbox)" or simply the "ZoomFactor" property to get the zoomfactor (which is not updated when the ViewboxChanged event is fired unfortunately).
The ZoomPanel is inside a grid with "*" row width and column height so it resizes with window resize.

xaml:
<ab2d:ZoomPanel
Grid.Row="0"
Name="ZoomPanel" Margin="5,0,5,0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
MouseRightButtonDown="ZoomPanel_MouseRightButtonDown" MouseRightButtonUp="ZoomPanel_MouseRightButtonUp"
MouseMove="ZoomPanel_MouseMove" ViewboxChanged="ZoomPanel_ViewboxChanged"
IsViewboxLimited="True" ViewboxMinSize="0.0078125, 0.0078125" ViewboxLimits="0, 0, 1, 1"
RenderOptions.BitmapScalingMode="NearestNeighbor"
ZoomMode="Move" ZoomFactor="1" Stretch="Uniform">
<Grid>
<Image Source="{Binding BS}" Cursor="Cross" Name="ZoomImage" Panel.ZIndex="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
<Canvas Name="Overlay" Panel.ZIndex="5" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Visibility="{Binding ShowOverlay, Converter={StaticResource BooleanToVisibilityConverter}}" IsHitTestVisible="False"/>
</Grid>
</ab2d:ZoomPanel>
#2
You have more options:

1)
You can set the Stretch property to None (instead of Uniform). This will not stratch the ZoomPanel's content when the size of ZoomPanel (window) is changed. In this mode the content will be scaled only by the ZoomFactor factor.

2)
If you would also like to stretch the content of ZoomPanel when the window's size is changed, you can get the actual "zoom factor" with dividing the ActualContentBounds with ContentSize:

ActualContentBounds can be get with ZoomPanel.UsedViewboxEx.ActualContentBounds (gets the size and position of the actual content size and position after ZoomPanel scale and stretch are applied).

ContentSize can be get with calling the ZoomPanel.GetContentSize(); in your case you can also get it from image's size

So for example if your content width is 100 and your ActualContentBounds's Width is 300, this means that your image is scaled by factor 3.


PS: You can also simply observe the ActualContentBounds and other properties with adding ZoomPanelDump control to your window:

<ab2d:ZoomPanelDump VerticalAlignment="Bottom" HorizontalAlignment="Right" ZoomPanel="{Binding ElementName=ZoomPanel}" />
Andrej Benedik
#3
Thanks for the reply.

I am using option 2 and calculating zoom as follows:

double zf2 = Math.Sqrt((ZoomPanel.UsedViewboxEx.ActualContentBounds.Height * ZoomPanel.UsedViewboxEx.ActualContentBounds.Width) / (ZoomPanel.GetContentSize().Height * ZoomPanel.GetContentSize().Width));

There is however a problem with updating the values. Somehow I read an old/not updated value while zooming using the mouse wheel (using the ViewboxChanged event). I have seen the exact same previously when simply reading the ZoomPanel.ZoomFactor property instead of ZoomPanel.GetZoomFactor(Rect viewbox). The value read is only old for a very short time, when asking again after a few ms the value is updated to the correct value.

Also right after loading a bitmapsource to the Image the "ActualContentBounds.Height" returns 0. When asking again after a few milliseconds the value returned is correct. (Even though no resize or zooming has been done).

The solution for ZoomFactor was using the event args to get the rectangle "NewViewboxValue" and to call the method GetZoomFactor(), instead of the ZoomFactor property. How can I fix it here?

When getting the values after a SizeChanged event on the window the correct values seem to be read.

/Simon
#4
The cause of the "wrong" and "old" values is caused by animating the zooming.

If you would disable the animation, you would immediately get the final values of ZoomFactor and other properties.

But because the zooming is animated, the values are "old" at the start of the animation but will change to new values when the animation is finished.

As you have already found out, one way to get the new values is from the ViewboxChanged event agrs - from NewViewboxValue property.

The problem with this approach is that it is not possible to get the final value of ZoomPanel.UsedViewboxEx.ActualContentBounds.

But you can also subscribe to ViewboxAnimationCompleted event that is fired when the animation is completed and from that event you can get all the final values.
Andrej Benedik
#5
Thanks, that did the job.

Only missing item was an update when the binding property were first updated or an image with new dimensions was loaded. Here the normal calls did not work using the animation completed event.
By adding a SizeChanged event to the Image control I was able to get an event and update the zoomfactor at these instances too.
  


Forum Jump:


Users browsing this thread:
1 Guest(s)