Jugando Con imágenes en WPF – Parte 2 – Zoom, Rotación y Traslación


En el Post anterior, vimos como Aplicar a una imagen el efecto de Reflexión y sombra, en este vamos a manipular la imagen haciendo un efecto de Zoom, rotándola y trasladándola.

Empezamos con un proyecto de WPF en Visual Studio, pueden usar la versión Express para este ejemplo.

–          Insertamos una imagen a nuestro proyecto.

–          En el Formulario, insertamos un control Image, con la propiedad Strecth a Uniform, y en Source el nombre de la imagen que acabamos de agregar a nuestro proyecto

–          Justo debajo del control Imagen, agregamos un control Slider, que servirá para acomodar el Zoom a nuestra imagen, con la propiedad de Maximum=5, para limitar el zoom.

–          Creamos un RenderTransform a la Imagen para escalar a la imagen, los valores de ScaleX y ScaleY van a depender del Valor de Slider, lo que hacemos es un Binding (Enlazar) a las propiedades ScaleX y ScaleY

El código debe ir así:

<Grid>

<Image Margin="16,2,100,113" Name="image1" Stretch="Uniform" Source="Drizzt.jpg" />

<Slider Height="23" Margin="38,0,112,53" Name="slider1" VerticalAlignment="Bottom" Value="1" Maximum="5" />

</Grid>

Ahora hacemos el Binding de la imagen con el Slider:

<Image Margin="16,2,100,113" Name="image1" Stretch="Uniform" Source="Drizzt.jpg" >

<Image.RenderTransform>

<ScaleTransform ScaleX="{Binding Path=Value, ElementName=slider1}" ScaleY="{Binding Path=Value, ElementName=slider1}"></ScaleTransform>

</Image.RenderTransform>

</Image>

 Como vemos, en la propiedad ScaleX y ScaleY, hacemos un binding, donde el elemento es el slider1, y el Value es la propiedad que vamos a enlazar, así cuando el valor del Slider cambia, se crea una transformación a la imagen, cambiándola de tamaño:

 ZoomSlider

 Ahora agregamos dos botones al lado derecho de la imagen, los botones serán para rotar la imagen hacia la derecha o hacia la izquierda. Las rotaciones las vamos a hacer desde el código:

 <Button Height="46" HorizontalAlignment="Right" Margin="0,5,20,0" Name="button1" VerticalAlignment="Top" Width="59" Content="&lt;-" Click="button1_Click"></Button>

    <Button Height="46" HorizontalAlignment="Right" Margin="0,69,20,0" Name="button2" VerticalAlignment="Top" Width="59">-&gt;</Button>

 Los símbolos &gt; y &lt; equivalen a > y < respectivamente.

En el botón que dice <-, agregamos el siguiente código:

private void button1_Click(object sender, RoutedEventArgs e)

{

image1.LayoutTransform = new RotateTransform(-90);

}

Lo que hicimos es a la imagen adicionarle una transformación de rotación de -90 grados, si ejecutamos el código veremos que al presionar el botón, la imagen se rota 90 grados hacia la izquierda:

 rotarizquierda

Para hacerlo más dinámico, declaramos una variable llamada ángulo, para que cada vez que presionemos el botón, dicha variable aumente o disminuya su valor:

private double angulo = 0;

private void button1_Click(object sender, RoutedEventArgs e)

{

angulo -= 90;

image1.LayoutTransform = new RotateTransform(angulo);

}

Al botón ->, lo que hacemos es que en vez de restar, le sumamos 90 grados:

private void button2_Click(object sender, RoutedEventArgs e)

{

angulo += 90;

image1.LayoutTransform = new RotateTransform(angulo);

}

rotarderecha

 

Ahora vamos a hacer un Panning, el panning en términos informáticos, se refiere a intentar mover un objeto oprimiendo el botón del mouse y manteniéndolo oprimido mover el mouse, arrastrando la imagen a la posición del mouse.

Para hacerlo hacemos uso del TranslateTransform, que traslada el objeto a una posición dada, creamos un tipo TranslateTransform:

private TranslateTransform trasladar;

Creamos los eventos de MouseDown, MouseUp ,MouseMove e inicializamos el objeto trasladar, y luego le asignamos el objeto trasladar al RenderTransform de la imagen:

this.trasladar = new TranslateTransform();

image1.RenderTransform = this.transformGroup;

image1.MouseDown += new MouseButtonEventHandler(image1_MouseDown);

image1.MouseMove += new MouseEventHandler(image1_MouseMove);

image1.MouseUp += new MouseButtonEventHandler(image1_MouseUp);

En el evento MouseDown hacemos uso del método CaptureMouse, para establecer la captura del mouse en el control Image:

image1.CaptureMouse();

Y en el evento MouseMove, validamos que se esté haciendo clic en la imagen, con el método IsMouseCaptured, creamos una variable del tipo Point, donde se va a guardar la posición del mouse, luego le aplicamos a la imagen la transformación de Traslación:

void image1_MouseMove(object sender, MouseEventArgs e)

{

if (image1.IsMouseCaptured)

  {

   Point clic = e.GetPosition(this);

   this.trasladar.X = clic.X;

   this.trasladar.Y = clic.Y;              

}

}

Al ejecutarlo vemos que al presionar el Mouse sobre la imagen y mover el mouse, la imagen se traslada lejos del puntero del Mouse, esto lo podemos corregir, haciendo uso de unas operaciones, para ello declaramos dos variables tipo Punto, una que guarde el punto donde hicimos clic por primera vez, y otro que guarde la posición inicial del objeto trasladar:

private Point Centro = new Point(0, 0);

private Point Inicio;

 

Luego modificamos el evento MouseDown:

void image1_MouseDown(object sender, MouseButtonEventArgs e)

{

image1.CaptureMouse();

this.Centro = e.GetPosition(this);

this.Inicio = new Point(this.trasladar.X, this.trasladar.Y);

this.Cursor = Cursors.ScrollAll;

}

Ahora modificamos el evento MouseMove:

void image1_MouseMove(object sender, MouseEventArgs e)

{

if (image1.IsMouseCaptured)

  {

   Point clic = e.GetPosition(this);

   this.trasladar.X = clic.X - this.Centro.X + this.Inicio.X;

   this.trasladar.Y = clic.Y - this.Centro.Y + this.Inicio.Y;

  }

}

 La explicación de esta operación se las debo 😦

Ahora en el evento MouseUp soltamos la captura del Mouse con el método ReleaseMouseCapture(), y volvemos a dejar el cursor normal:

void image1_MouseUp(object sender, MouseButtonEventArgs e)

{

image1.ReleaseMouseCapture();

this.Cursor = Cursors.Arrow;

}

Al probar, vemos que todo va bien, al dar clic sobre la imagen, luego mantener presionado el botón del Mouse y moverlo, la imagen se mueve hacia dónde va el Mouse, pero que sucede con nuestro Slider?, pues ya no funciona, porque en el código ya le estamos asignando a la propiedad RenderTransform de la imagen un objeto TraslateTransform, por lo tanto el que asignamos en el código XAML ya no es válido, para corregir esto, vamos a hacer todo desde el código c#.

Para poder asignar a un control varias transformaciones (Rotación, escalamiento, traslación), se crea un objeto TransformGroup, y después se le asignan como hijos las demás transformaciones.

Creamos un objeto ScaleTransform, y otro TransfromGroup, después le asignamos al TransformGroup, los objetos ScaleTransform y TraslateTransform, el código debe ir así:

private double angulo = 0;

private TranslateTransform trasladar;

private ScaleTransform escalar;

private TransformGroup transformGroup;

private Point Centro = new Point(0, 0);

private Point Inicio;

 

public Imagenes2()

      {

      InitializeComponent();

      this.trasladar = new TranslateTransform();

      this.escalar = new ScaleTransform();

      this.transformGroup = new TransformGroup();

      this.transformGroup.Children.Add(this.trasladar);

      this.transformGroup.Children.Add(this.escalar);

      image1.RenderTransform = this.transformGroup;

      image1.MouseDown += new MouseButtonEventHandler(image1_MouseDown);

      image1.MouseMove += new MouseEventHandler(image1_MouseMove);

      image1.MouseUp += new MouseButtonEventHandler(image1_MouseUp);

      }

 

Ahora desde la vista de diseño hacemos doble clic sobre el Slider, para que se cree el evento Slider_ValueChanged, en ese evento escribimos lo siguiente:

if (this.escalar != null)

{

this.escalar.ScaleX = e.NewValue;

this.escalar.ScaleY = e.NewValue;

}

Antes de hacer algo validamos que el objeto escalar no sea nulo, pues apenas inicia la aplicación, se ejecuta el evento Slider_ValueChanged y el objeto se encuentra nulo.

Asignamos a las propiedades ScaleX y ScaleY el nuevo valor del Slider con e.NewValue.

Si probamos todo:

Escalando (Zooming):

 escalar

Trasladando (Panning) :

 panning

Rotando:

 

rotar

Código Fuente:

Aquí.

Referencias:

http://stackoverflow.com/questions/741956/wpf-pan-zoom-image

http://mel-green.com/2009/09/wpf-simple-vista-image-viewer/

9 pensamientos en “Jugando Con imágenes en WPF – Parte 2 – Zoom, Rotación y Traslación

  1. hola estoy tratando de hacer una aplicacion para hacer una imagen donde el usuario escogas los valores y tenga la rotacion
    si me puedes ayudar con ello te lo agradeceria mucho

  2. holaaaa! he estado probando tu ejemplo y va genial, pero sabes si hay alguna forma que al aplicarle por ejemplo el cambio de rotar, la imagen original se guarde girada???

    • Hola, para guardar los cambios, hay que modificar la rotación, de tal forma que la rotación se le haga al source de la imagen, luego al guardar la imagen, los cambios son reflejados, por ejemplo, si yo modifico el método de rotación:
      private void button2_Click(object sender, RoutedEventArgs e)
      {
      angulo += 90;

      TransformedBitmap TempImage = new TransformedBitmap();
      TempImage.BeginInit();
      TempImage.Source = (BitmapSource)image1.Source;
      RotateTransform transform = new RotateTransform(angulo);
      TempImage.Transform = transform;
      TempImage.EndInit();
      image1.Source = TempImage;
      }
      Luego, creo el método para guardar la imagen:

      private void button6_Click(object sender, RoutedEventArgs e)
      {
      String filePath = @”C:\img\nombreimagen.png”;
      var encoder = new PngBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create((BitmapSource)image1.Source));
      using (System.IO.FileStream stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
      {
      encoder.Save(stream);
      }
      }

      Solo debes cambiar la ruta y el nombre que va a quedar la imagen, al guardarla, la imagen tendrá los cambios de la rotación :).

  3. hola. Tengo una imagen en un grid y quiero moverla, el escalado si me funciona pero no me funciona el panning.
    Cuando pincho en la imagen me cambia el icono del raton pero no me hace nada.
    por favor puedes ayudarme. necesito que la imagen se mueva y cuando suelte el ratón vualva a su sitio.

    Gracias

  4. Hola, agradecería demasiado me ayudaras un poco. Tengo una App donde debo pasar un Text Marquee para avisos, como el de los noticieros, donde ponen las noticias recientes (barra de la parte inferior). Conseguí hacerlo en Windows Form, mi código es este:
    private void timer1_Tick(object sender, EventArgs e)
    {
    this.Refresh();
    myLabel2.Left += 15;
    if (myLabel2.Left >= this.Width)
    {
    myLabel2.Left = myLabel2.Width * -1;
    }
    }
    Consigo que el label se mueva de izquierda a derecha infinitamente sin importar el tamaño del label o la ventana. ¿Crees poderme ayudar para hacerlo en WPF? En serio que he buscado mucho y soy nuevo acá en WPF :c Gracias hermano!

Deseas comentar o sugerir algo?

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s