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的,对于透明的图片,我做了点修正,透明图片会用白色填充。
posted @ 2010-12-26 20:33  Honker Snow  阅读(2302)  评论(9编辑  收藏  举报