zoukankan      html  css  js  c++  java
  • 05、Windows Store app 的图片裁切(更新)

    在 Win Phone Silverlight api 中,有一个 PhotoChooserTask 选择器,指定宽、高属性,在选择图片的时候,

    可以进行裁切,代码:

    PhotoChooserTask photoChooserTask = new PhotoChooserTask();
    photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
    
    // 设置 宽、高
    photoChooserTask.PixelHeight = 130;
    photoChooserTask.PixelWidth = 130;
    photoChooserTask.ShowCamera = true;
    photoChooserTask.Show();


    在图片选择完成后,可以进行裁切:

    这里模仿这个交互,在 Store app 实现类似的交互。

    1、XAML 页面

    1)首先放置两个 Image 控件,一个显示用户缩放、平移的手势操作,另一个显示截图完成后的结果:

    <Image  x:Name="img" Stretch="UniformToFill" ManipulationMode="All"  ManipulationDelta="Image_ManipulationDelta"  RenderTransformOrigin="0.5,0.5">
        <Image.RenderTransform>
            <CompositeTransform x:Name="img_transform" CenterX="0" CenterY="0"/>
        </Image.RenderTransform>
    </Image>
    
    <Image x:Name="imgResult" Width="100" Height="100"/>

    2)放置一个 Border 元素,他的边框为黑色透明,中间的宽、高固定为 200px,里面放一个 白色的 Border,作为取景框:

    <!--屏幕遮罩 -->
    <Border IsHitTestVisible="False" x:Name="borderMask" BorderThickness="135,268.3" Background="Transparent" BorderBrush="#55000000" >
        <Border BorderThickness="1"  BorderBrush="White"/>
    </Border>

    2、在 C# 页面

    1)注册当前 Page 对象的 SizeChanged 事件,以当 Windows 的宽、高发生改变时,调整遮罩 和 图片的位置:

     // 当页面布局发生改变时,动态调整遮罩的位置
     this.SizeChanged += PhotoChooserPage_SizeChanged;
           void PhotoChooserPage_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                 InitMask();
            }
    
            // 取景框的 宽、高,img 图片控件初始的最小宽、高要大于它
            public double Img_w = 200;
    
            // 取景框大小 - 作为标准
            Rect measureRect;
    
            void InitMask()
            {
                double w = Window.Current.Bounds.Width;
    
                double h = Window.Current.Bounds.Height;
                
                if (w > Img_w && h > Img_w)
                {
                    // 左边距
                    double left = (w - Img_w) / 2;
    
                    // 上边距
                    double top = (h - Img_w) / 2;
    
                    // 取景框作为截图的标准
                    measureRect = new Rect(left, top, Img_w, Img_w);
    
                    // 把 Border 的边框设置为黑色半透明,背景为 null,则实现取景框效果
                    borderMask.BorderThickness = new Thickness(left, top, left, top);
                    
                    borderMask.Width = w;
                    borderMask.Height = h;
                                    
                    Canvas.SetLeft(img, left);
                    Canvas.SetTop(img, top);
    
                    Canvas.SetLeft(imgResult, (w - imgResult.ActualWidth) / 2);
                }
            }

    2)在 Image 控件的 Image_ManipulationDelta 事件中,调整当前 Image 的 拉伸、缩放:

     // 缩放累加
     double scale = 1.0;
    
     // 平移累加
     double translate_x = 0;
     double translate_y = 0;
    
     object o = 1;
     private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
     {
         e.Handled = true;
    
         lock (o)
         {
             // 非惯性下
             if (!e.IsInertial)
             {
                 //  x-y 屏幕坐标的更改
                 translate_x += e.Delta.Translation.X;
                 translate_y += e.Delta.Translation.Y;
    
                 // 两指缩放更改
                 scale *= e.Delta.Scale;
    
                 // 更改图片 CompositeTransform 对象
                 img_transform.TranslateX = translate_x;
                 img_transform.TranslateY = translate_y;
    
                 img_transform.ScaleX = img_transform.ScaleY = scale;
    
                 // 如果超出取景框,则撤销上面的修改
                 if (!IsValide())
                 {
    
                     translate_x -= e.Delta.Translation.X;
                     translate_y -= e.Delta.Translation.Y;
    
                     scale /= e.Delta.Scale;
    
                     img_transform.TranslateX = translate_x;
                     img_transform.TranslateY = translate_y;
    
                     img_transform.ScaleX = img_transform.ScaleY = scale;
                 }
             }
    
         }
     }

    3)计算当前的图片范围,并限制图片的大小、边框不能在取景框里面:

      // 判断图片在遮罩的中间位置
      bool IsValide()
      {
          Rect Temp = GetBounds(img, LayoutRoot);
    
          // 查找当前 Windows.Foundation.Rect 所表示的矩形和指定 Windows.Foundation.Rect 所表示的矩形的交集,并将结果存储为当前 
          // Windows.Foundation.Rect
          Temp.Intersect(measureRect);
    
          if (Temp == measureRect)
          {
              return true;
          }
    
          return false;
      }
    
      // 获取 UIElement 在页面中的坐标和尺寸
      public Rect GetBounds(FrameworkElement childElement, FrameworkElement parentElement)
      {
          // https://msdn.microsoft.com/en-us/library/system.windows.media.visual.transformtovisual%28v=vs.110%29.aspx
          // https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.uielement.transformtovisual.aspx
          GeneralTransform transform = childElement.TransformToVisual(parentElement);
    
          return transform.TransformBounds(new Rect(0, 0, childElement.ActualWidth, childElement.ActualHeight));
      }


    4)当用户点击 ”裁切“ 按钮时, 使用 BitmapEncoder 对图像进行裁切:

            private async void AppBarButton_Crop_Click(object sender, RoutedEventArgs e)
            {
                appBar.IsEnabled = false;
    
                try
                {
                    StorageFile sourceFile = PickedFile;// await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("Images\test\test.jpg");
    
                    if (PickedFile == null) return;
    
                    using (var readStream = await sourceFile.OpenReadAsync())
                    {
                        var decoder = await BitmapDecoder.CreateAsync(readStream);
    
                        //using (InMemoryRandomAccessStream writeStream = new InMemoryRandomAccessStream())
                        //{
    
                        if (WriteStream != null)
                        {
                            WriteStream.Dispose();
                        }
    
                        WriteStream = new InMemoryRandomAccessStream();
    
                        BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(WriteStream, decoder);
    
                        Rect temp = GetBounds(img, LayoutRoot);
    
                        double scale_x = decoder.PixelWidth / temp.Width;
    
                        encoder.BitmapTransform.Bounds = new BitmapBounds
                        {
                            X = (uint)Math.Round((measureRect.X - temp.X) * scale_x, 0),
                            Y = (uint)Math.Round((measureRect.Y - temp.Y) * scale_x, 0),
                            Width = (uint)Math.Round(measureRect.Width * scale_x, 0),
                            Height = (uint)Math.Round(measureRect.Height * scale_x, 0)
                        };
    
                        await encoder.FlushAsync();
    
                        BitmapImage bi = new BitmapImage();
                        bi.SetSource(WriteStream);
                        imgResult.Source = bi;
    
                        // 如果需要设置图片的固定宽、高,可以使用 WriteableBitmap 对象
                        //WriteableBitmap wb = new WriteableBitmap(120, 120);
                        //wb.SetSource(writeStream);
                        //imgResult.Source = wb;
    
    
                        double size = WriteStream.Size / (1024 * 1024.0);
                        if (size > 5)
                            await (new MessageDialog(string.Format("图片大于 5MB(当前{0:0.0}MB),请重新选择"))).ShowAsync();
    
                        //}
                    }
                }
                catch (Exception ex)
                {
                    (new MessageDialog("截图区域超出边界了:" + ex.Message)).ShowAsync();
                }
    
    
                appBar.IsEnabled = true;
            }


    在 Windows 上的显示效果:

    在手机上的显示效果:

      

    Demo 的下载链接(win8.1+ wp8.1)

    2015/9/1 更新

       增加 PC 上的鼠标的滚轮事件,进行图片缩放。

       在 xaml 页面,给 Canvas 增加一个 事件: PointerWheelChanged="LayoutRoot_PointerWheelChanged" 

            // 鼠标滚轮的缩、放
            private void LayoutRoot_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
            {
                // Detect scroll is completed with PointerWheelChanged : http://stackoverflow.com/questions/13816352/detect-scroll-is-completed-with-pointerwheelchanged
    
                //var m = e.KeyModifiers;
    
                e.Handled = true;
    
                lock (o)
                {
                    if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
                    {
                        PointerPoint mousePosition = e.GetCurrentPoint(sender as Canvas);
                        var delta = mousePosition.Properties.MouseWheelDelta;
    
                        scale *= (delta > 0 ? 1.1 : 0.9);
    
                        img_transform.ScaleX = img_transform.ScaleY = scale;
    
                        // 如果超出取景框,则撤销上面的修改
                        if (!IsValide())
                        {
                            scale /= (delta > 0 ? 1.1 : 0.9);
    
                            img_transform.ScaleX = img_transform.ScaleY = scale;
                        }
    
                        Debug.WriteLine(delta);
                    }
                }
            }


    win10 uwp 工程代码下载

  • 相关阅读:
    VS2008 环境中完美搭建 Qt 4.7.4 静态编译的调试与发布 Inchroy's Blog 博客频道 CSDN.NET
    编写可丢弃的代码
    c++ using namespace std; 海明威 博客园
    解决MySQL server has gone away
    nginx upstream 调度策略
    (2006, 'MySQL server has gone away') 错误解决 dba007的空间 51CTO技术博客
    Linux IO模型漫谈(2) 轩脉刃 博客园
    redis源码笔记 initServer 刘浩de技术博客 博客园
    MySQLdb批量插入数据
    词库的扩充百度百科的抓取你知道这些热词吗? rabbit9898 ITeye技术网站
  • 原文地址:https://www.cnblogs.com/hebeiDGL/p/4363643.html
Copyright © 2011-2022 走看看