WPF MediaElement Playback Orientation - wpf

I have some mp4s (captured on an android, some in portrait, some in landscape)
When I use them as the source of a MediaElement tag, they always play in landscape mode. I've been googling this like crazy and haven't found anything at all about the orientation of video in a MediaElement, so hopefully I missed something basic.
Here's my xaml:
<Canvas x:Name="videoCanvas" Height="Auto" Width="641" Margin="10,0,11,0" HorizontalAlignment="Center" >
<ContentControl Content="{Binding Media}" Width="{Binding ActualWidth, ElementName=videoCanvas}" Height="{Binding ActualHeight, ElementName=videoCanvas}" />
</Canvas>
and the code-behind:
media = new MediaElement();
media.LoadedBehavior = MediaState.Manual;
media.Loaded += Media_Loaded;
media.MediaOpened += Media_MediaOpened;
media.Source = new Uri(#"c:\videos\portrait.mp4");
media.HorizontalAlignment = HorizontalAlignment.Center;
media.VerticalAlignment = VerticalAlignment.Center;
The NaturalVideoHeight/Width in Media_MediaOpened is the same for both videos so I don't think I can use that to rotate the MediaElement.

There is a way I solved this problem in my case. You need to use nugget Microsoft-WindowsAPICodePack-Core and Microsoft-WindowsAPICodePack-Shell:
ShellFile shell = ShellFile.FromFilePath(this.VideoFile);
ShellProperty<ulong?> fs = shell.Properties.System.Size;
// workaround to find out if video in portrait or landscape
BitmapSource bs = shell.Thumbnail.BitmapSource;
double bsWidth = bs.Width;
double bsHeight = bs.Height;
videoOrientation = bsWidth > bsHeight ? VideoOrientation.LANDSCAPE : VideoOrientation.PORTRAIT;
ShellProperty<uint?> fw = shell.Properties.System.Video.FrameWidth;
ShellProperty<uint?> fh = shell.Properties.System.Video.FrameHeight;
From the code, we see that video has a thumnail representation, it is the image that you see when exploring videos in Windows Explorer.
With "fw" and "fh" you can set the aspectRatio and set the properties Width and Height od MediaElement properly.
Hope it helps somebody.

Related

WPF Transform Rectangle in Canvas to Selection in Image

I have a rectangle on a canvas that the user can resize, move and so on to make a selection.
I also have an image the size of the screen behind the canvas (basically a screenshot).
I'd like to translate the selection (the rectangle) in the canvas to a 1:1 selection in the image (I want the image directly behind the rectangle) given I have the rectangle's Canvas.Top, Canvas.Left, Width, Height.
<Grid Name="MainGrid" SnapsToDevicePixels="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image x:Name="MainImage" Stretch="None" RenderOptions.BitmapScalingMode="HighQuality"/>
<Border Background="Black" Opacity="0.4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Canvas Name="MainCanvas" Width="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}}" Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}}" Background="Transparent">
<ContentControl Name="SelectionRect" />
</ContentControl>
</Canvas>
</Grid>
I tried doing this: (MainImage is the image under the canvas)
Rect rect = new Rect(Canvas.GetLeft(SelectionRect), Canvas.GetTop(SelectionRect), SelectionRect.Width, SelectionRect.Height);
Rect from_rect = SelectionRect.TransformToVisual(this).TransformBounds(rect);
BitmapSource cropped_bitmap = new CroppedBitmap(MainImage.Source as BitmapSource,
new Int32Rect((int)from_rect.X, (int)from_rect.Y, (int)from_rect.Width, (int)from_rect.Height));
SelectionRectImageSource = cropped_bitmap;
But the image I get (SelectionRectImageSource) is a moved aside version of the actual pixels behind the selection rectangle.
So basically, I don't understand how these transformations work and how I should use them if at all.
Example:
Thanks a lot!
Dolev.
Looks like you need to correct for the DPI difference between the image (usually 72dpi) and the presentation source (usually 96dpi). Additionally, your first Rect should not be offset by Canvas.Left and Canvas.Top; TransformToVisual will take care of the relative offset for you.
var source = (BitmapSource)MainImage.Source;
var selectionRect = new Rect(SelectionRect.RenderSize);
var sourceRect = SelectionRect.TransformToVisual(MainImage)
.TransformBounds(selectionRect);
var xMultiplier = source.PixelWidth / MainImage.ActualWidth;
var yMultiplier = source.PixelHeight / MainImage.ActualHeight;
sourceRect.Scale(xMultiplier, yMultiplier);
var croppedBitmap = new CroppedBitmap(
source,
new Int32Rect(
(int)sourceRect.X,
(int)sourceRect.Y,
(int)sourceRect.Width,
(int)sourceRect.Height));
SelectionRectImageSource= croppedBitmap;
Depending on where this code resides, you may also need to transform the selection rectangle to MainImage instead of this (as I did).
Also, in case MainImage.Source is smaller than the actual MainImage control, you should probably set the horizontal and vertical alignments of MainImage to Left and Top, respectively, less your translated rectangle end up outside the bounds of the source image. You'll need to clamp the selection rectangle to the dimensions of MainImage too.

WPF ZoomControl and Adorners

This my first post on stack overflow, I hope I get it right. I am using the ZoomControl from WPF Extensions to display an image with pan and zoom support:
<DockPanel Grid.Row="1" x:Name="canvas">
<Controls:ZoomControl x:Name="zoomControl">
<Canvas x:Name="canvas">
<Image x:Name="imageControl" Stretch="None" />
</Canvas>
</Controls:ZoomControl>
</DockPanel>
When the user selects an image with a bowse dialog, I load that image like so:
bmp = new BitmapImage(new Uri(fileName));
this.imageControul.Source = bmp;
I would like to added rectangles\adorners to specific locations (pixel coordinates) on the image the user loaded based on some image processing.
var r = new Rectangle();
r.StrokeThickness = 5;
r.Stroke = Brushes.Black;
r.Fill = Brushes.Transparent;
r.Width = width;
r.Height = height;
Canvas.SetLeft(r, y);
Canvas.SetTop(r, x);
canvas.Children.Add(r);
However, the rectangles are not placed in the expected locations? Wrong scale and location.
Thanks,
John
I expect the problem is that your Canvas is expanding to fill the space rather than being locked to the rectangle. Have a look with a tool like Snoop and see what the bounding boxes of the two are.
You might be able to fix it with Horizontal and VercticalAlignment on the canvas, set them to anything other than Stretch.
If that doesn't work restructure it like this
<ZoomBox>
<Grid>
<Image/>
<Canvas/>
</Grid>
</ZoomBox>
So the Image and the canvas are grouped by the parent Grid which is being transformed.

Items not drawing on Resize of Viewbox, Silverlight

I am currently designing a layout app in Silverlight and have a Canvas inside of a Viewbox. I add shapes to the canvas and they display properly, when I resize the viewbox to zoom in at 2x the height and width, everything still draws properly.
The problem comes when I try to zoom at a factor of 4 or greater or at 0.5 (zoomed out).
Update: The horizontal lines are still there, they are just not drawing. Interaction between the the other shapes and the disappearing ones is still present
When I do this, any horizontal lines do not redraw, but any other shapes, vertical lines of other, still redraw fine. The objects are still children of the canvas and their visibilities are all set to visible.
What is happening?
Update
Very Simple XAML:
<ScrollViewer x:Name="scrollViewer"
Padding="0"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
IsTabStop="False"
Background="Beige">
<Viewbox x:Name="viewBox" Stretch="UniformToFill">
<Canvas x:Name="designCanvas"
Background="{Binding ElementName=mainControl, Path=Background, Mode=TwoWay}">
</Canvas>
</Viewbox>
</ScrollViewer>
Here is how I add the shapes:
Rectangle horGuide = new Rectangle()
{
Tag = "horGuide",
Fill = new SolidColorBrush(Colors.Cyan),
Height = 0.5,
Width = designCanvas.canvActualWidth*16,
};
int h = designCanvas.horOffset;
int v = designCanvas.vertOffset;
double d = e.GetPosition(sideRule).Y;
designCanvas.Children.Add(horGuide);
Canvas.SetTop(horGuide, ((d+v )/ designCanvas.zoomFactor));
Canvas.SetLeft(horGuide, 0 - h);
To Zoom in:
viewBox.Width *= 2;
viewBox.Height *= 2;
Why not use the ScaleTransform class to zoom in and out.

Silveright ScrollViewer with Image and ScaleTransform

I have the following xaml.
<ScrollViewer HorizontalAlignment="Stretch" Margin="107,0,0,0" Name="scrollViewer1" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Visible">
<Image Name="image1" Stretch="None" MouseWheel="image1_MouseWheel" RenderTransformOrigin="0,0">
</Image>
</ScrollViewer>
An the following code behind.
// initialise.
private TransformGroup group = new TransformGroup();
private ScaleTransform st = new ScaleTransform();
group.Children.Add(st);
image1.RenderTransform = group
// mouse event.
TransformGroup group = (TransformGroup)image1.RenderTransform;
ScaleTransform scale = (ScaleTransform)group.Children.Last();
double zoom = e.Delta > 0 ? .2 : -.2;
scale.ScaleX += zoom;
scale.ScaleY += zoom;
How do I get the scroller to take into account that the image is now a different size.
The scroll bars remain the same size, and I cannot work out how to change them.
Thanks
You need the LayoutTransformer from the Silverlight Toolkit. Instead of setting a RenderTransform on your Image, put it inside a LayoutTransformer.
have you tried calling InvalidateScrollInfo on the scrollviewer?

Flowdocument isnt using the full width/height

I have a FlowDocument which I want to fill the entire width and height of my window. I have tried using the FlowDocumentPageViewer (no luck) and am now using a DocumentPageView. I still can't get it to dock/fill the entire space; it's just sitting in the middle, in the minimum size it can create (does it make sense?)
Here is my code:
public DocumentPageView GetPage()
{
FlowDocumentPageViewer viewer = new FlowDocumentPageViewer();
StreamReader reader = new StreamReader(location);
string data = reader.ReadToEnd();
reader.Close();
string xamlData = HtmlToXamlConverter.ConvertHtmlToXaml(data, true);
FlowDocument result = (FlowDocument)System.Windows.Markup.XamlReader.Load(new MemoryStream(System.Text.UnicodeEncoding.Default.GetBytes(xamlData)));
viewer.Document = result;
viewer.VerticalAlignment = VerticalAlignment.Center;
viewer.HorizontalAlignment = HorizontalAlignment.Center;
DocumentPageView pageView = new DocumentPageView();
pageView.VerticalAlignment = VerticalAlignment.Center;
pageView.HorizontalAlignment = HorizontalAlignment.Center;
pageView.Stretch = System.Windows.Media.Stretch.Uniform;
pageView.PageNumber = 0;
pageView.StretchDirection = StretchDirection.Both;
pageView.DocumentPaginator = ((IDocumentPaginatorSource)result).DocumentPaginator;
return pageView;
}
Please note that this code contains the combination of my two methods but only the DocumentPageView is currently used. This is the Xaml that is created from my HTML source:
<FlowDocument xml:space="preserve" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Paragraph TextAlignment="center" FontSize="22pt" FontFamily="arial">Test Paragraph</Paragraph>
<Paragraph TextAlignment="center" FontFamily="arial">Test second paragraph</Paragraph>
</FlowDocument>
If I resize the fonts the content is only resized vertically (please note that the stretch direction is set to both). Any ideas?
I had a similar problem with FlowDocumentScrollView, but this solution also seems to work with FlowDocumentPageView:
The FlowDocument is centered because it's PagePadding property is set to auto,auto,auto,auto. Setting PagePadding to 0 fixes this behavior.
<FlowDocumentScrollViewer VerticalScrollBarVisibility="Auto">
<FlowDocument PagePadding="0">
</FlowDocument>
</FlowDocumentScrollViewer>
The following lines are causing your elements to center themselves (which is not the same as stretch):
viewer.VerticalAlignment = VerticalAlignment.Center;
viewer.HorizontalAlignment = HorizontalAlignment.Center;
pageView.VerticalAlignment = VerticalAlignment.Center;
pageView.HorizontalAlignment = HorizontalAlignment.Center;
You can safely remove them, as the default alignment here is Stretch.
If you still want to center the viewer, explicitly define the page size (remember, there are 96 points in an inch, and the Margin and PageSize are set in points):
Width= 96 * 8.5
Height= 96 * 11
Could you specify where and how do you use the result of your GetPage() method? Is it xbap or desktop application?
I'm asking this, because the following document is displayed just perfectly right in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<FlowDocumentPageViewer>
<FlowDocument >
<Paragraph TextAlignment="center" FontSize="22pt" FontFamily="arial">Test Paragraph</Paragraph>
<Paragraph TextAlignment="center" FontFamily="arial">Test second paragraph</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Page>
PS: If it's a desktop application you can always find who causes problems by Snoop tool, form Pete Blois.
Update: Its a desktop application, the getpage() result is posted into a grid which docks/fills perfectly.
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="Auto" Width="Auto" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid Width="Auto" Height="Auto" Name="TransitionContainer" Background="White" Margin="0">
//here the result from GetPage() method is inserted
</Grid>
</Window>
(this comment is written from another account)
#Anvaka: What i mean by perfectly right is that the document should "dock in container" that is the fonts should resize, it should fill the container in height and width. Now that im thinking about it, that may not seem like a proper behaviour for a flowdocument.
When i put the flow document in the container it is centered in middle of parent container (so far so good). but the parent container is not filling out its parent container so when i zoom or change font size, i would like the documentPageView container to grow in width and height, but remain centered.

Resources