Сложность объединения ScaleTransform (WPF) с Transalate Transform во время рендеринга изображения
WPF.
(Я заранее извиняюсь за кажущуюся стенку кода, но проблема мне кажется сложной, и я хотел быть настолько полным, насколько это необходимо).
У меня есть изображение, которое сбрасывается на InkCanvas:
Перед изменением размера показывает:
Изменение контура траектории во время DragDelts показывает:
После DragCompleted. Примечание: Я ХОЧУ, ЧТОБЫ ЛУЧШИЙ УГЛОВОЙ УГОЛ был В ПОЛОЖЕНИИ "Х", ГДЕ КУРСОР НА ВРЕМЯ ДРАГКОМПЛЕТА:
Вот код, который я использую для получения изображений выше. По сути, проблема сводится к вычислению правильного преобразования преобразования после изменения размера изображения. Я перепробовал все, что могу придумать, но безуспешно. Что действительно вызывает недоумение, так это то, что смещение от курсора в некоторой степени зависит от положения, в которое изображение помещается в InkCanvas. То есть, если изображение сброшено ближе к левой границе, смещение будет более выраженным, чем если бы оно было опущено в центре. Очень запутанно.
private void IC_Drop(object sender, DragEventArgs e)
{
InkCanvas ic = sender as InkCanvas;
ic.EditingMode = InkCanvasEditingMode.None;
ImageInfo image_Info = e.Data.GetData(typeof(ImageInfo)) as ImageInfo;
if (image_Info != null)
{
Image image = new Image();
image.Width = image_Info.Width * 4;
image.Stretch = Stretch.Fill;
image.Source = new BitmapImage(image_Info.Uri);
Point position = e.GetPosition(ic);
TranslateTransform mov = new TranslateTransform(position.X, position.Y);
image.RenderTransform = mov;
ic.Children.Add(image);
ImageResizing imgResize = ImageResizing.Create(image);
}
}
ImageResizing.Create () теперь добавляет rendertransforms и thumb thumbner к изображению для изменения размера, перемещения и поворота:
private ImageResizing(Image image)
{
if (image == null)
throw new ArgumentNullException("image");
_image = image;
ScaleTransform scale = new ScaleTransform();
RotateTransform rot = new RotateTransform();
TranslateTransform mov = new TranslateTransform();
TransformGroup tg = new TransformGroup();
tg.Children.Add(image.RenderTransform);
tg.Children.Add(scale);
tg.Children.Add(rot);
tg.Children.Add(mov);
image.RenderTransform = tg;
image.RenderTransformOrigin = new Point(0.5,0.5);
// Create the adorner.
_adorner = new MyImageAdorner(image);
// Get the Adorner Layer and add the Adorner.
InstallAdorner();
}
Украшение TopLeft Thumb определяется с помощью:
Thumb topLeft;
Path outline;
public MyImageAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
// Initialize the Resizing (i.e., corner) thumbs with specialized cursors.
BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
topLeft.DragDelta += new DragDeltaEventHandler(TopLeft_DragDelta);
topLeft.DragCompleted += TopLeft_DragCompleted;
}
// Helper method to instantiate the corner Thumbs, set the Cursor property,
// set some appearance properties, and add the elements to the visual tree.
void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
{
if (cornerThumb != null) return;
cornerThumb = new Thumb();
// Set some arbitrary visual characteristics.
cornerThumb.Cursor = customizedCursor;
cornerThumb.Height = cornerThumb.Width = 15;
cornerThumb.Opacity = 0.40;
cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue);
visualChildren.Add(cornerThumb);
}
Я использую DragDelta для позиционирования элемента контура контура до желаемого конечного размера, например, так:
// Top Left Corner is being dragged. Anchor is Bottom Right.
void TopLeft_DragDelta(object sender, DragDeltaEventArgs e)
{
ScaleTransform sT = new ScaleTransform(1 - e.HorizontalChange / outline.ActualWidth, 1 - e.VerticalChange / outline.ActualHeight,
outline.ActualWidth, outline.ActualHeight);
outline.RenderTransform = sT;
}
Обратите внимание, что я собираюсь изменить размер изображения в верхнем правом углу в нижнем правом углу. Следовательно, по мере перетаскивания угла TopLeft все точки изображения должны удаляться от нижнего правого угла.
Наконец, я использую событие DragCompleted для фактического выполнения нового рендеринга на изображении:
private void TopLeft_DragCompleted(object sender, DragCompletedEventArgs e)
{
// Get new scaling from the Outline.
ScaleTransform sT = outline.RenderTransform as ScaleTransform;
double anchorX = sT.CenterX;
double anchorY = sT.CenterY;
// Get the previous scaling
TransformGroup gT = AdornedElement.RenderTransform as TransformGroup;
ScaleTransform sT0 = gT.Children[1] as ScaleTransform;
double oldscaleX = sT0.ScaleX;
double oldscaleY = sT0.ScaleY;
double oldCenterX = anchorX - (outline.ActualWidth ) * oldscaleX;
double oldCenterY = anchorY - (outline.ActualHeight) * oldscaleY;
// Get the previous translation
TranslateTransform tT = gT.Children[3] as TranslateTransform;
sT0.CenterX = anchorX;
sT0.CenterY = anchorY;
sT0.ScaleX *= sT.ScaleX;
sT0.ScaleY *= sT.ScaleY;
double newCenterX = anchorX -(outline.ActualWidth) * sT0.ScaleX;
double newCenterY = anchorY -(outline.ActualHeight) * sT0.ScaleY;
tT.X += newCenterX - oldCenterX;
tT.Y += newCenterY - oldCenterY;
// Put transforms back.
gT.Children[1] = sT0;
gT.Children[3] = tT;
AdornedElement.RenderTransform = gT;
outline.RenderTransform = Transform.Identity;
}
А для полноты, рекламодатель позиционируется как:
protected override Size ArrangeOverride(Size finalSize)
{
double eW = AdornedElement.RenderSize.Width;
double eH = AdornedElement.RenderSize.Height;
FrameworkElement ele = AdornedElement as FrameworkElement;
EnforceSize(ele);
eH = ele.Height;
eW = ele.Width;
Size aS = new Size(eW, eH);
// calculate the center of the image.
var center = new Point(eW / 2, eH / 2);
topLeft.Arrange(new Rect(new Point(-center.X, -center.Y), aS));
topRight.Arrange(new Rect(new Point(center.X, -center.Y), aS));
bottomLeft.Arrange(new Rect(new Point(-center.X, center.Y), aS));
bottomRight.Arrange(new Rect(new Point(center.X, center.Y), aS));
// The RotateHandle is placed slightly above the Top of the Image center.
// The MoveHandle is placed at the center of the Image.
rotateHandle.Arrange(new Rect(new Point(0, -(center.Y + HANDLEMARGIN)), aS));
moveHandle.Arrange(new Rect(new Point(0, 0), aS));
// Place a blue outline arround the image.
outline.Data = new RectangleGeometry(new Rect(aS));
outline.Arrange(new Rect(aS));
// Return the final size.
return aS;
}
Я был бы признателен за любую помощь или предложения. Что я делаю неправильно?
ТИА
Примечание. На этот вопрос дан ответ. Масштабирование, вызывающее перекос