gpt4 book ai didi

c# - 使用 Transforms 裁剪低分辨率图像并将其分配给我的用户控件

转载 作者:太空狗 更新时间:2023-10-29 19:46:53 25 4
gpt4 key购买 nike

我一直在开发 Windows 8.1 RT 应用程序,其中用户使用 Stretch=Uniform 加载图像。图像可以尽可能小,也可以尽可能大。剪辑发生在我的用户控件中,当我点击/按住屏幕/图像时,我的用户控件出现。当我点击并按住并在背景中的图像周围移动手指/鼠标时,就会发生剪裁。

我面临的问题是

  1. 每当在 Emulator 上首次加载应用程序时,以及第一次执行点击/单击并按住时,用户控件会出现在屏幕的左上角,然后出现在上方我的点击/保持区​​域。我需要的是它应该始终出现在我点击并按住的任何地方以及我点击并按住的任何时候。松开手指/鼠标时,它应该会折叠。

  2. 我正在使用中心 转换。我希望我的鼠标当前所在的区域(像素)准确显示在用户控件的中心,如果我正在加载一个小分辨率图像 480*800 甚至更小,该区域我的鼠标没有进入中心。为了更清楚,想象一下我正在点击并按住人眼的角膜。角膜应该显示在用户控件的中心,上方和下方的区域应该覆盖其余部分.

    1. 我不希望我的控件超出我的图像边界,如果我的鼠标位于图像的最后一个像素,则应该显示图像的某些部分和背景的某些部分。
  3. 我需要旋转控件,如 video 所示在下面找到完整的代码。

MainPage.XAML

<Page
x:Class="App78.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App78"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid
x:Name="LayoutGrid"
Margin="0,0"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Holding="LayoutGrid_Holding"
PointerMoved="LayoutGrid_OnPointerMoved"
PointerWheelChanged="LayoutGrid_OnPointerWheelChanged"
PointerPressed="LayoutGrid_OnPointerPressed"
PointerReleased="LayoutGrid_OnPointerReleased">
<Image
x:Name="BigImage"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Source="http://blog.al.com/space-news/2009/04/iss015e22574.jpg" />

<local:Magnifier VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="MagnifierTip" Visibility="Collapsed" />
</Grid>
</Page>

MAINPAGE.XAML.CS

using System;
using System.Diagnostics;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace App78
{
public sealed partial class MainPage : Page
{
private double zoomScale = 2;
private double pointerX = 0;
private double pointerY = 0;
private const double MinZoomScale = .25;
private const double MaxZoomScale = 32;


public MainPage()
{
this.InitializeComponent();

var bi = (BitmapImage)BigImage.Source;
bi.ImageOpened += bi_ImageOpened;
this.SizeChanged += MainPage_SizeChanged;
}

void MainPage_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
this.UpdateImageLayout();
}

void bi_ImageOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
this.UpdateImageLayout();
}

private void UpdateImageLayout()
{
var bi = (BitmapImage)BigImage.Source;
if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
bi.PixelHeight < this.LayoutGrid.ActualHeight)
{
this.BigImage.Stretch = Stretch.None;
}
else
{
this.BigImage.Stretch = Stretch.Uniform;
}

this.UpdateMagnifier();
}

private void LayoutGrid_OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
//DV: If pointer is not in contact we can ignore it
if (!e.Pointer.IsInContact) { return; }

var point = e.GetCurrentPoint(this.LayoutGrid);
this.pointerX = point.Position.X;
this.pointerY = point.Position.Y;
this.UpdateMagnifier();
}

private void UpdateMagnifier()
{
var bi = (BitmapImage)BigImage.Source;

double offsetX = 0;
double offsetY = 0;
double imageScale = 1;

var imageRatio = (double)bi.PixelWidth / bi.PixelHeight;
var gridRatio = this.LayoutGrid.ActualWidth / this.LayoutGrid.ActualHeight;

if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
bi.PixelHeight < this.LayoutGrid.ActualHeight)
{
offsetX = 0.5 * (this.LayoutGrid.ActualWidth - bi.PixelWidth);
offsetY = 0.5 * (this.LayoutGrid.ActualHeight - bi.PixelHeight);
//imageScale = 1; - remains
}
else if (imageRatio < gridRatio)
{
offsetX = 0.5 * (this.LayoutGrid.ActualWidth - imageRatio * this.LayoutGrid.ActualHeight);
offsetY = 0;
imageScale = BigImage.ActualHeight / bi.PixelHeight;
}
else
{
offsetX = 0;
offsetY = 0.5 * (this.LayoutGrid.ActualHeight - this.LayoutGrid.ActualWidth / imageRatio);
imageScale = BigImage.ActualWidth / bi.PixelWidth;
}

//DV: This is probably not need anymore
//MagnifierTip.MagnifierTransform.X = this.pointerX;
//MagnifierTip.MagnifierTransform.Y = this.pointerY;
MagnifierTip.PositionTransform.X = (-this.pointerX + offsetX) / imageScale;
MagnifierTip.PositionTransform.Y = (-this.pointerY + offsetY) / imageScale;

//DV: I haven't tested the Scaling/Zoom
MagnifierTip.ZoomTransform.ScaleX = imageScale * zoomScale;
MagnifierTip.ZoomTransform.ScaleY = imageScale * zoomScale;

MagnifierTip.CenterTransform.X = MagnifierTip.MagnifierEllipse.ActualWidth / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;
MagnifierTip.CenterTransform.Y = MagnifierTip.MagnifierEllipse.ActualHeight / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;

//DV: I added a GlobalGrid Transform which translates every children
MagnifierTip.MagnifierTransformGrid.X = this.pointerX - (MagnifierTip.ActualWidth / 2);
MagnifierTip.MagnifierTransformGrid.Y = this.pointerY - (MagnifierTip.ActualHeight); ;

}

private void LayoutGrid_OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
if (e.GetCurrentPoint(this.LayoutGrid).Properties.MouseWheelDelta > 0)
{
zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale * 1.2));
}
else
{
zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale / 1.2));
}

this.UpdateMagnifier();
}


//DV: Holding usually only works with touch https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.uielement.holding.aspx?f=255&MSPPError=-2147217396
private void LayoutGrid_Holding(object sender, HoldingRoutedEventArgs e)
{
//
}

//DV: pointer pressed supports both mouse and touch but fires immeadiatley. You'll have to figure out a delay strategy or using holding for touch and right click for mouse
private void LayoutGrid_OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Visible;
}

//DV: pointer released supports both mouse and touch.
private void LayoutGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
}

放大镜.XAML

<UserControl
x:Class="App78.Magnifier"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App78"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Height="230"
Width="170">


<Grid Height="230" Width="170">

<!-- DV: This is the global transform I added -->
<Grid.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="MagnifierTransformGrid" x:FieldModifier="public"/>
</TransformGroup>
</Grid.RenderTransform>
<Ellipse Opacity="1" Visibility="Visible" Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Center" VerticalAlignment="Top" IsHitTestVisible="False" Width="135" Height="128" StrokeThickness="3" Margin="0,17,0,0" />
<Ellipse x:Name="MagnifierEllipse" x:FieldModifier="public" Opacity="1" Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" IsHitTestVisible="False" Width="150" Height="150" Stroke="White" StrokeThickness="3" Margin="11,8,0,0" >
<Ellipse.Fill>
<ImageBrush
ImageSource="http://blog.al.com/space-news/2009/04/iss015e22574.jpg"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top">
<ImageBrush.Transform>
<TransformGroup>
<TranslateTransform x:FieldModifier="public"
x:Name="CenterTransform"/>
<TranslateTransform x:FieldModifier="public"
x:Name="PositionTransform"/>
<ScaleTransform x:FieldModifier="public"
x:Name="ZoomTransform"/>
</TransformGroup>
</ImageBrush.Transform>
</ImageBrush>
</Ellipse.Fill>
</Ellipse>
<Path Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z"
Fill="#FFF4F4F5"
Stretch="Fill"
Stroke="Black"
UseLayoutRounding="False"
Height="227"
Width="171" ></Path>
</Grid>
</UserControl>

为方便起见,可以从here 下载该项目。 .为了更好地理解,我希望您看到这个 video .这正是我需要实现的。

最佳答案

我通过一些变化和三角函数得到了它 here .

MainPage.xaml

<Page
x:Class="MagnifierApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MagnifierApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid
x:Name="LayoutGrid"
Margin="0,0"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
PointerMoved="LayoutGrid_OnPointerMoved"
PointerWheelChanged="LayoutGrid_OnPointerWheelChanged"
PointerPressed="LayoutGrid_OnPointerPressed"
PointerReleased="LayoutGrid_OnPointerReleased">
<Image
x:Name="BigImage"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Source="http://blog.al.com/space-news/2009/04/iss015e22574.jpg" />
<local:Magnifier
x:Name="MagnifierTip"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Visibility="Collapsed" />
</Grid>
</Page>

MainPage.xaml.cs

using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace MagnifierApp
{
public sealed partial class MainPage : Page
{
private double zoomScale = 2;
private double pointerX = 0;
private double pointerY = 0;
private const double MinZoomScale = .25;
private const double MaxZoomScale = 32;
private bool isFirst = true;

public MainPage()
{
this.InitializeComponent();

var bi = (BitmapImage)BigImage.Source;
bi.ImageOpened += bi_ImageOpened;
this.SizeChanged += MainPage_SizeChanged;
}

void MainPage_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
this.UpdateImageLayout();
}

void bi_ImageOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
this.UpdateImageLayout();
}

private void UpdateImageLayout()
{
var bi = (BitmapImage)BigImage.Source;

if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
bi.PixelHeight < this.LayoutGrid.ActualHeight)
{
this.BigImage.Stretch = Stretch.None;
}
else
{
this.BigImage.Stretch = Stretch.Uniform;
}

this.UpdateMagnifier();
}

private void LayoutGrid_OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (!e.Pointer.IsInContact)
{
return;
}

var point = e.GetCurrentPoint(this.LayoutGrid);
this.pointerX = point.Position.X;
this.pointerY = point.Position.Y;
this.UpdateMagnifier();
}

private void LayoutGrid_OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
if (e.GetCurrentPoint(this.LayoutGrid).Properties.MouseWheelDelta > 0)
{
zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale * 1.2));
}
else
{
zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale / 1.2));
}

this.UpdateMagnifier();
}

private void LayoutGrid_OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
if (!e.Pointer.IsInContact) { return; }

var point = e.GetCurrentPoint(this.LayoutGrid);

this.pointerX = point.Position.X;
this.pointerY = point.Position.Y;
this.UpdateMagnifier();
MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Visible;
}

private void LayoutGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}

private void UpdateMagnifier()
{
var bi = (BitmapImage)BigImage.Source;

double offsetX;
double offsetY;
double imageScale;
CalculateImageScaleAndOffsets(bi, out offsetX, out offsetY, out imageScale);

MagnifierTip.PositionTransform.X = (-this.pointerX + offsetX) / imageScale;
MagnifierTip.PositionTransform.Y = (-this.pointerY + offsetY) / imageScale;
MagnifierTip.ZoomTransform.ScaleX = imageScale * zoomScale;
MagnifierTip.ZoomTransform.ScaleY = imageScale * zoomScale;

MagnifierTip.CenterTransform.X = MagnifierTip.MagnifierEllipse.ActualWidth / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;
MagnifierTip.CenterTransform.Y = MagnifierTip.MagnifierEllipse.ActualHeight / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;

MagnifierTip.MagnifierTranslateTransform.X = this.pointerX - (MagnifierTip.ActualWidth / 2);
MagnifierTip.MagnifierTranslateTransform.Y = this.pointerY - (MagnifierTip.ActualHeight);

bool tooHigh = MagnifierTip.MagnifierTranslateTransform.Y < 0;
bool tooLeft = MagnifierTip.MagnifierTranslateTransform.X < 0;
bool tooRight = MagnifierTip.MagnifierTranslateTransform.X + MagnifierTip.ActualWidth > this.LayoutGrid.ActualWidth;

if (tooHigh || tooLeft || tooRight)
{
double angle = 0.0;

if (tooLeft && !tooHigh)
{
var dx = -MagnifierTip.MagnifierTranslateTransform.X;
var r = MagnifierTip.ActualHeight - MagnifierTip.ActualWidth / 2;
var arad = Math.Asin(dx / r);
angle = arad * 180 / Math.PI;
}
else if (tooLeft && tooHigh)
{
var dx = -MagnifierTip.MagnifierTranslateTransform.X;
var dy = -MagnifierTip.MagnifierTranslateTransform.Y;
var r = MagnifierTip.ActualHeight - MagnifierTip.ActualWidth / 2;
var arad1 = Math.Asin(dx / r);
var arad2 = Math.Acos((r - dy) / r);
var arad = Math.Max(arad1, arad2);
angle = arad * 180 / Math.PI;
}
else if (tooHigh && !tooRight)
{
var dy = -MagnifierTip.MagnifierTranslateTransform.Y;
var r = MagnifierTip.ActualHeight - MagnifierTip.ActualWidth / 2;
var arad = Math.Acos((r - dy) / r);

if (MagnifierTip.MagnifierTranslateTransform.X + Math.Sin(arad) * r + MagnifierTip.ActualWidth > this.LayoutGrid.ActualWidth)
{
arad = -arad;
}

angle = arad * 180 / Math.PI;
}
else if (tooHigh)
{
var dy = -MagnifierTip.MagnifierTranslateTransform.Y;
var dx = MagnifierTip.MagnifierTranslateTransform.X + MagnifierTip.ActualWidth - this.LayoutGrid.ActualWidth;
var r = MagnifierTip.ActualHeight - MagnifierTip.ActualWidth / 2;
var arad1 = -Math.Acos((r - dy) / r);
var arad2 = -Math.Asin(dx / r);
var arad = Math.Min(arad1, arad2);
angle = arad * 180 / Math.PI;
}
else //if (tooRight)
{
var dx = MagnifierTip.MagnifierTranslateTransform.X + MagnifierTip.ActualWidth - this.LayoutGrid.ActualWidth;
var r = MagnifierTip.ActualHeight - MagnifierTip.ActualWidth / 2;
var arad = -Math.Asin(dx / r);
angle = arad * 180 / Math.PI;
}

MagnifierTip.RotateTransform.Angle = angle;
MagnifierTip.LensRotateTransform.Angle = -angle;
}
else
{
MagnifierTip.RotateTransform.Angle = 0;
MagnifierTip.LensRotateTransform.Angle = 0;
}
}

private void CalculateImageScaleAndOffsets(BitmapImage bi, out double offsetX, out double offsetY, out double imageScale)
{
var imageRatio = (double)bi.PixelWidth / bi.PixelHeight;
var gridRatio = this.LayoutGrid.ActualWidth / this.LayoutGrid.ActualHeight;

if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
bi.PixelHeight < this.LayoutGrid.ActualHeight)
{
offsetX = 0.5 * (this.LayoutGrid.ActualWidth - bi.PixelWidth);
offsetY = 0.5 * (this.LayoutGrid.ActualHeight - bi.PixelHeight);
imageScale = 1;
}
else if (imageRatio < gridRatio)
{
offsetX = 0.5 * (this.LayoutGrid.ActualWidth - imageRatio * this.LayoutGrid.ActualHeight);
offsetY = 0;
imageScale = BigImage.ActualHeight / bi.PixelHeight;
}
else
{
offsetX = 0;
offsetY = 0.5 * (this.LayoutGrid.ActualHeight - this.LayoutGrid.ActualWidth / imageRatio);
imageScale = BigImage.ActualWidth / bi.PixelWidth;
}
}
}
}

放大镜.xaml

<UserControl
x:Class="MagnifierApp.Magnifier"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MagnifierApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Height="227"
Width="170">
<Grid
Height="227"
Width="170"
RenderTransformOrigin="0.5,1">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform
x:FieldModifier="public"
x:Name="RotateTransform"
Angle="0" />
<TranslateTransform
x:Name="MagnifierTranslateTransform"
x:FieldModifier="public" />
</TransformGroup>
</Grid.RenderTransform>
<Ellipse
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsHitTestVisible="False"
Width="152"
Height="152"
Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Margin="9,10,0,0"
RenderTransformOrigin="0.5,0.5"
StrokeThickness="0">
</Ellipse>
<Ellipse
x:Name="MagnifierEllipse"
x:FieldModifier="public"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsHitTestVisible="False"
Width="152"
Height="152"
Stroke="White"
Margin="9,10,0,0"
RenderTransformOrigin="0.5,0.5"
StrokeThickness="0">
<Ellipse.RenderTransform>
<RotateTransform
x:FieldModifier="public"
x:Name="LensRotateTransform"
Angle="0" />
</Ellipse.RenderTransform>
<Ellipse.Fill>
<ImageBrush
ImageSource="http://blog.al.com/space-news/2009/04/iss015e22574.jpg"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top">
<ImageBrush.Transform>
<TransformGroup>
<TranslateTransform
x:FieldModifier="public"
x:Name="PositionTransform" />
<ScaleTransform
x:FieldModifier="public"
x:Name="ZoomTransform" />
<TranslateTransform
x:FieldModifier="public"
x:Name="CenterTransform" />
</TransformGroup>
</ImageBrush.Transform>
</ImageBrush>
</Ellipse.Fill>
</Ellipse>
<Path
Data="M85,11 C43.8548,11 10.5,44.3548 10.5,85.5 C10.5,126.645 43.8548,160 85,160 C126.145,160 159.5,126.645 159.5,85.5 C159.5,44.3548 126.145,11 85,11 z M85,0.5 C131.668,0.5 169.5,38.3319 169.5,85 C169.5,103.959 163.256,121.459 152.713,135.558 L151.895,136.625 L152,136.625 L84.2999,226 L18,136.625 L18.1054,136.625 L17.2872,135.558 C6.74375,121.459 0.5,103.959 0.5,85 C0.5,38.3319 38.3319,0.5 85,0.5 z"
Margin="0,0.5,0,0"
Stretch="Fill"
Stroke="Black"
UseLayoutRounding="False"
StrokeThickness="0"
Fill="White" />
</Grid>
</UserControl>

关于c# - 使用 Transforms 裁剪低分辨率图像并将其分配给我的用户控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29703191/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com