Silverlight客户端实现图片的截取和压缩----之上传头像

前几日在公司做sl上传头像,因为代码不能拿出来,所以自己大体写了下。功能上算是实现了。效果图:

1

点击Browse按钮打开一张图片,点击Clip会出来一个红色的方框。可以用鼠标拖动红框,在右边角有一个三角,可以改变大小。还有四周灰色的蒙版,用了四个Rectangle,如下图

2

四个Rectangle的放置,当然不一定按照我的做法,只要能实现功能即可。

xaml代码:

<controls:ChildWindow x:Class="SlTest.ClipImg"

           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

           Width="352" Height="437"

           Title="ClipImg">

    <Grid x:Name="LayoutRoot" Margin="2">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="*" />

            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

        <!--上方两个功能按钮-->

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">

            <Button Content="Browse" Width="75" Click="OnSelectPicClick"/>

            <Button Content="Clip" Width="75" Click="OnClipClick"/>

        </StackPanel>

        

        <Canvas x:Name="ImgCanvas" Grid.Row="1" Height="340" Width="310" Margin="0 5 0 0">

            <Image x:Name="SourceImg" Margin="0" MaxHeight="340" MaxWidth="310" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"

                   MouseLeftButtonDown="OnImgMouseLeftBtnDown" MouseMove="OnImgMouseMove" MouseLeftButtonUp="OnImgMosueLeftBtnUp"/>

            <!--做蒙版的四个Rectangle-->

            <Rectangle Name="topMask" Fill="#4333" Canvas.Top="0" Canvas.Left="0" />

            <Rectangle Name="bottomMask" Fill="#4333" />

            <Rectangle Name="leftMask" Fill="#4333" Canvas.Left="0"/>

            <Rectangle Name="rightMask" Fill="#4333" Canvas.Top="0" />

            <!--红色的框,还有右下角的红色三角(一个Path)-->

            <Border x:Name="ImgCropBorder" Height="140" Width="140" BorderBrush="Red" BorderThickness="1" Visibility="Collapsed"  Margin="0"

                        MouseLeftButtonDown="OnBorderMouseLeftBtnDown" MouseMove="OnBorderMouseMove" MouseLeftButtonUp="OnBorderMosueLeftBtnUp" >

                <Path Data="M400,215 L370,240 L400,240 z" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE"

                        Stretch="Fill" Stroke="Red" Width="10" Height="10" UseLayoutRounding="False" />

            </Border>

        </Canvas>

        

        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal"  Grid.Row="2">

            <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" Margin="5 0"/>

            <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" Margin="5 0"/>

        </StackPanel>

    </Grid>

</controls:ChildWindow>

cs代码:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.IO;

using System.Windows.Media.Imaging;



namespace SlTest

{

    public partial class ClipImg : ChildWindow

    {

        public ClipImg()

        {

            InitializeComponent();

        }



        private void OKButton_Click(object sender, RoutedEventArgs e)

        {

            this.DialogResult = true;

        }



        private void CancelButton_Click(object sender, RoutedEventArgs e)

        {

            this.DialogResult = false;

        }





        #region move & resize the Red Boreder



        private bool isBorder, isPath;

        private Point mousePosition;



        private void OnImgMouseLeftBtnDown(object sender, MouseButtonEventArgs e)

        {

            if (ImgCropBorder.Visibility == Visibility.Visible)

            {

                FrameworkElement element = sender as FrameworkElement;

                Point p = e.GetPosition(ImgCropBorder);

                if (p.X > 0 && p.X <= ImgCropBorder.Width

                    && p.Y > 0 && p.Y <= ImgCropBorder.Height)

                {

                    isBorder = true;

                    mousePosition = e.GetPosition(null);

                    if (element != null)

                    {

                        element.CaptureMouse();

                        element.Cursor = Cursors.Hand;

                    }

                }

            }

        }



        private void OnImgMouseMove(object sender, MouseEventArgs e)

        {

            if (isBorder)

            {

                double deltaV = e.GetPosition(null).Y - mousePosition.Y;

                double deltaH = e.GetPosition(null).X - mousePosition.X;



                double newTop = deltaV + (double)ImgCropBorder.GetValue(Canvas.TopProperty);

                double newLeft = deltaH + (double)ImgCropBorder.GetValue(Canvas.LeftProperty);



                if (newTop >= 0 && newTop <= SourceImg.Height - ImgCropBorder.Height)

                    ImgCropBorder.SetValue(Canvas.TopProperty, newTop);

                if (newLeft >= 0 && newLeft <= SourceImg.Width - ImgCropBorder.Width)

                    ImgCropBorder.SetValue(Canvas.LeftProperty, newLeft);



                mousePosition = e.GetPosition(null);

                //CropImg();

                SetMask();

            }

        }



        private void OnImgMosueLeftBtnUp(object sender, MouseButtonEventArgs e)

        {

            isBorder = false;

            SourceImg.ReleaseMouseCapture();

            mousePosition.X = mousePosition.Y = 0;

            SourceImg.Cursor = null;

        }



        private void OnBorderMouseLeftBtnDown(object sender, MouseButtonEventArgs e)

        {

            FrameworkElement element = sender as FrameworkElement;

            mousePosition = e.GetPosition(null);

            Point p = e.GetPosition(ImgCropBorder);

            if (p.X > 0 && p.X <= ImgCropBorder.Width

                && p.Y > 0 && p.Y <= ImgCropBorder.Height)

            {

                mousePosition = e.GetPosition(null);

                isPath = true;

                if (element != null)

                {

                    element.CaptureMouse();

                    element.Cursor = Cursors.SizeNWSE;

                }

            }

        }



        private void OnBorderMouseMove(object sender, MouseEventArgs e)

        {

            if (isPath)

            {

                double deltaV = e.GetPosition(null).Y - mousePosition.Y;

                double deltaH = e.GetPosition(null).X - mousePosition.X;



                double newHeight = deltaV + ImgCropBorder.Height;

                double newWidth = deltaH + ImgCropBorder.Width;



                if (newHeight + Convert.ToDouble(ImgCropBorder.GetValue(Canvas.TopProperty)) > SourceImg.Height)

                    newHeight = SourceImg.Height - Convert.ToDouble(ImgCropBorder.GetValue(Canvas.TopProperty));

                if (newWidth + Convert.ToDouble(ImgCropBorder.GetValue(Canvas.LeftProperty)) > SourceImg.Width)

                    newWidth = SourceImg.Width - Convert.ToDouble(ImgCropBorder.GetValue(Canvas.LeftProperty));



                if (newHeight > 0 && newWidth > 0)

                {

                    ImgCropBorder.Height = newHeight;

                    ImgCropBorder.Width = newWidth;

                }

                mousePosition = e.GetPosition(null);

                //CropImg();

                SizeToMask();

            }

        }



        private void OnBorderMosueLeftBtnUp(object sender, MouseButtonEventArgs e)

        {

            isPath = false;

            FrameworkElement element = sender as FrameworkElement;

            element.ReleaseMouseCapture();

            mousePosition.X = mousePosition.Y = 0;

            element.Cursor = null;

        }



        #endregion



        private void OnSelectPicClick(object sender, RoutedEventArgs e)

        {

            try

            {

                OpenFileDialog ofd = new OpenFileDialog();

                if (true == ofd.ShowDialog())

                {

                    FileInfo fi = ofd.File;



                    BitmapImage bitmap = new BitmapImage();

                    bitmap.SetSource(fi.OpenRead());



                    if (bitmap.PixelHeight >= bitmap.PixelWidth)

                    {

                        if (bitmap.PixelHeight >= ImgCanvas.Height)

                        {

                            SourceImg.Width = ImgCanvas.Height / bitmap.PixelWidth * bitmap.PixelWidth;

                            SourceImg.Height = ImgCanvas.Height;

                        }

                        else

                        {

                            SourceImg.Width = bitmap.PixelWidth;

                            SourceImg.Height = bitmap.PixelHeight;

                        }

                    }

                    else

                    {

                        if (bitmap.PixelWidth > ImgCanvas.Width)

                        {

                            SourceImg.Height = bitmap.PixelHeight * ImgCanvas.Width / bitmap.PixelWidth;

                            SourceImg.Width = ImgCanvas.Width;

                        }

                        else

                        {

                            SourceImg.Height = bitmap.PixelHeight;

                            SourceImg.Width = bitmap.PixelWidth;

                        }

                    }

                                        

                    SourceImg.Source = bitmap;

                    ResetMask();

                }

            }

            catch (Exception ex) { MessageBox.Show(ex.ToString()); }

        }



        private void OnClipClick(object sender, RoutedEventArgs e)

        {

            if (SourceImg.Source != null)

            {

                ImgCropBorder.Width = ImgCropBorder.Height = 140;



                if (SourceImg.Height < 140)

                    ImgCropBorder.Height = SourceImg.Height / 2;

                if (SourceImg.Width < 140)

                    ImgCropBorder.Width = SourceImg.Width / 2;

                if (ImgCropBorder.Width > ImgCropBorder.Height)

                    ImgCropBorder.Width = ImgCropBorder.Height;

                else

                    ImgCropBorder.Height = ImgCropBorder.Width;



                Canvas.SetTop(ImgCropBorder, SourceImg.Height / 2 - ImgCropBorder.Width / 2);

                Canvas.SetLeft(ImgCropBorder, SourceImg.Width / 2 - ImgCropBorder.Width / 2);



                if (ImgCropBorder.Visibility == Visibility.Collapsed)

                {

                    ImgCropBorder.Visibility = System.Windows.Visibility.Visible;

                    SetMask();

                }

                else

                {

                    ImgCropBorder.Visibility = System.Windows.Visibility.Collapsed;

                    WriteableBitmap _WriteableBitmap = new WriteableBitmap((int)ImgCropBorder.Width, (int)ImgCropBorder.Width);

                    TranslateTransform t = new TranslateTransform();

                    t.Y = -1 * Convert.ToDouble(ImgCropBorder.GetValue(Canvas.TopProperty));

                    t.X = -1 * Convert.ToDouble(ImgCropBorder.GetValue(Canvas.LeftProperty));

                    _WriteableBitmap.Render(SourceImg, t);

                    _WriteableBitmap.Invalidate();

                    SourceImg.Source = _WriteableBitmap;

                    ResetMask();

                }

            }

        }



        private void SetMask()

        {

            double left = Canvas.GetLeft(ImgCropBorder);

            double top = Canvas.GetTop(ImgCropBorder);



            topMask.Height = top;



            leftMask.Height = SourceImg.Height - top;

            leftMask.Width = left;

            Canvas.SetTop(leftMask, top);



            SizeToMask();

        }





        private void SizeToMask()

        {

            double left = Canvas.GetLeft(ImgCropBorder);

            double top = Canvas.GetTop(ImgCropBorder);



            topMask.Width = left + ImgCropBorder.Width;



            rightMask.Height = top + ImgCropBorder.Height;

            rightMask.Width = SourceImg.Width - left - ImgCropBorder.Width;

            Canvas.SetLeft(rightMask, left + ImgCropBorder.Width);



            bottomMask.Width = SourceImg.Width - left;

            bottomMask.Height = SourceImg.Height - top - ImgCropBorder.Height;

            Canvas.SetLeft(bottomMask, left);

            Canvas.SetTop(bottomMask, top + ImgCropBorder.Height);

        }



        private void ResetMask()

        {



            leftMask.Width = 0;

            rightMask.Width = 0;

            topMask.Width = 0;

            bottomMask.Width = 0;

        }

    }

}



移动红色框的事件是写在Image上的,因为红色的框是透明的。改变大小的事件写在Border上不是Path上。代码比较简单基本上都能够看懂
我就不浪费口舌了。。。
图片的截取和压缩主要通过WriteableBitmap 这个类实现的,对它进行相应的变换就可以实现截取和压缩。
由WriteableBitmap转换成byte我调用了FluxJpeg这个三方的。博客园上有很多说明,在博客园上搜索“FluxJpeg”就可以找的到,
也有很详细说明。
还有一个我用到的类:
 
    public class ImgByte

    {

        public static byte[] BitMapToByte(System.Windows.Media.Imaging.WriteableBitmap bitmap)

        {

            if (bitmap == null) return null;

            int width = bitmap.PixelWidth;

            int height = bitmap.PixelHeight;

            int bands = 3;

            byte[][,] raster = new byte[bands][,];



            for (int i = 0; i < bands; i++)

            {

                raster[i] = new byte[width, height];

            }



            for (int row = 0; row < height; row++)

            {

                for (int column = 0; column < width; column++)

                {

                    int pixel = bitmap.Pixels[width * row + column];

                    byte a = ((byte)(pixel >> 24));



                    byte r = (byte)(pixel >> 16);//4 R

                    byte g = (byte)(pixel >> 8);//2 G

                    byte b = (byte)pixel;//0 B



                    if (a < 2)

                    {

                        raster[0][column, row] = (byte)(255 - r);

                        raster[1][column, row] = (byte)(255 - g);

                        raster[2][column, row] = (byte)(255 - b);

                    }

                    else

                    {

                        raster[0][column, row] = (byte)(r * 255.0 / a);

                        raster[1][column, row] = (byte)(g * 255.0 / a);

                        raster[2][column, row] = (byte)(b * 255.0 / a);

                    }

                }

            }



            FluxJpeg.Core.ColorModel model = new FluxJpeg.Core.ColorModel { colorspace = FluxJpeg.Core.ColorSpace.RGB };

            FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);





            //Encode the Image as a JPEG

            System.IO.MemoryStream stream = new System.IO.MemoryStream();

            FluxJpeg.Core.Encoder.JpegEncoder encoder = new FluxJpeg.Core.Encoder.JpegEncoder(img, 100, stream);

            encoder.Encode();



            //Back to the start

            stream.Seek(0, System.IO.SeekOrigin.Begin);



            //Get teh Bytes and write them to the stream

            byte[] binaryData = new byte[stream.Length];

            long bytesRead = stream.Read(binaryData, 0, (int)stream.Length);

            return binaryData;

        }

    }
使用的这个类转化成Image的,对于透明的图片,我做了点修正,透明图片会用白色填充。

你可能感兴趣的:(silverlight)