Windows phone 8.1 裁剪矩形

Posted

技术标签:

【中文标题】Windows phone 8.1 裁剪矩形【英文标题】:Windows phone 8.1 crop rectangle 【发布时间】:2016-06-13 08:01:02 【问题描述】:

我正在制作具有裁剪功能的 windows phone 8.1 应用程序。问题是我不知道如何制作一个用户可以调整大小而不是裁剪图像的图形矩形。图片位于:

Image x:Name="ImagePreview" HorizontalAlignment="Left" Height="492" Margin="10,10,0,0" Stretch="UniformToFill" VerticalAlignment="Top" Width="380" >

【问题讨论】:

ImagePreview 的来源是怎么设置的? 我在第一个屏幕上发送图片,我用相机拍照或通过图库选择它。然后我在调用编辑屏幕时设置它。 protected override void OnNavigatedTo(NavigationEventArgs e) var obj = App.Current as App;原始 = obj.ImageToEdit; ImagePreview.Source = 原始; 那么ImagePreview源是BitmapImage还是WritableBitmap?因为我准备了在 Windows10 中进行裁剪的解决方案,但是在从 BitmapImage 创建流时它在 WP8.1 中崩溃了。 图片为BitmapImage类型 Aww.. 然后等一会儿。我会尝试找出崩溃的原因,然后我会发布答案。你是如何创建 obj.ImageToEdit 的?请在你的问题中发布代码 【参考方案1】:

这是裁剪图像的xaml(包括裁剪矩形)

<Grid >
        <ScrollViewer>
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>
                <Button Content="Pick a image" Click="Button_Click" />
                <Canvas Grid.Row="1" Width="380" Height="492"  Margin="10,10,0,0" VerticalAlignment="Top">
                    <Image x:Name="original" ImageOpened="original_ImageOpened" Stretch="Uniform" ManipulationCompleted="Rectangle_ManipulationCompleted" ManipulationDelta="Rectangle_ManipulationDelta" ManipulationStarted="Rectangle_ManipulationStarted" ManipulationMode="All" PointerPressed="rect_PointerPressed" Source="Assets/new_arrivals.png" HorizontalAlignment="Left" Height="492" Width="380"  >

                    </Image>
                    <Rectangle x:Name="rect"  StrokeThickness="1" Stroke="Red">
                    </Rectangle>
                </Canvas>
                <Button Grid.Row="2" Name="CropBtn" Content="CropImage"  Click="CropBtn_Click" />
                <Image Grid.Row="3" Stretch="None" Name="FinalCroppedImage"/>
            </Grid>
        </ScrollViewer>
    </Grid>

后面的代码

 public sealed partial class MainPage : Page
    
        bool pointerpressed = false;
        WriteableBitmap WB_CapturedImage;//for original image
        WriteableBitmap WB_CroppedImage;//for cropped image
        Point Point1, Point2;
        public MainPage()
        
            this.InitializeComponent();
           // view = CoreApplication.GetCurrentView();
            this.NavigationCacheMode = NavigationCacheMode.Required;
            CompositionTarget.Rendering += CompositionTarget_Rendering;
        

        void CompositionTarget_Rendering(object sender, object e)
        
            rect.SetValue(Canvas.LeftProperty, (Point1.X < Point2.X) ? Point1.X : Point2.X);
            rect.SetValue(Canvas.TopProperty, (Point1.Y < Point2.Y) ? Point1.Y : Point2.Y);
            rect.Width = (int)Math.Abs(Point2.X - Point1.X);
            rect.Height = (int)Math.Abs(Point2.Y - Point1.Y);
        
    //To generate croping rectangle
    private void Rectangle_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
            
                Point1 = e.Position;//Set first touchable cordinates as point1
                Point2 = Point1;
            

            private void Rectangle_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
            
                var point = Point2;
                if (e.Position.X <= original.ActualWidth && e.Position.X >= 0)
                    point.X = e.Position.X;
                if (e.Position.Y <= original.ActualHeight && e.Position.Y >= 0)
                    point.Y = e.Position.Y;
                Point2 = point;
            

            private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
            
                var point = Point2;
               // Debug.WriteLine(e.Position.X + "&&&" + original.ActualWidth);
                if (e.Position.X <= original.ActualWidth && e.Position.X>=0)
                    point.X = e.Position.X;
                if (e.Position.Y <= original.ActualHeight && e.Position.Y >= 0)
                    point.Y = e.Position.Y;
                Point2 = point;
            

            private void rect_PointerPressed(object sender, PointerRoutedEventArgs e)
            
                pointerpressed = true;
                Point1 = e.GetCurrentPoint(original).Position;//Set first touchable cordinates as point1
                Point2 = Point1;
            
 private async void CropBtn_Click(object sender, RoutedEventArgs e)
        
            BitmapDecoder decoder = null;
            BitmapImage bImage = original.Source as BitmapImage;

            if (storageFile == null && bImage.UriSource!=null)
            
                storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx://"+bImage.UriSource.AbsolutePath));
            

            using (IRandomAccessStream streamWithContent = await storageFile.OpenAsync(FileAccessMode.Read))
                    
                decoder = await BitmapDecoder.CreateAsync(streamWithContent);
                BitmapFrame bitmapFrame = await decoder.GetFrameAsync(0);
                WB_CapturedImage = new WriteableBitmap((int)bitmapFrame.PixelWidth,
                                                             (int)bitmapFrame.PixelHeight);
                Size cropsize = new Size(Math.Abs(Point2.X - Point1.X), Math.Abs(Point2.Y - Point1.Y));
                double originalImageWidth = WB_CapturedImage.PixelWidth;
                double originalImageHeight = WB_CapturedImage.PixelHeight;

                // Get the size of the image when it is displayed on the phone
                double displayedWidth = original.ActualWidth;
                double displayedHeight = original.ActualHeight;

                // Calculate the ratio of the original image to the displayed image
                double widthRatio = originalImageWidth / displayedWidth;
                double heightRatio = originalImageHeight / displayedHeight;
                WB_CroppedImage = await GetCroppedBitmapAsync(streamWithContent, Point1, cropsize, widthRatio, heightRatio);

                FinalCroppedImage.Source = WB_CroppedImage;
            
        
 public static async Task<WriteableBitmap> GetCroppedBitmapAsync(IRandomAccessStream originalImage,
       Point startPoint, Size cropSize, double scaleWidth, double scaleheight)
    
        if (double.IsNaN(scaleWidth) || double.IsInfinity(scaleWidth))
        
            scaleWidth = 1;
        
        if (double.IsNaN(scaleheight) || double.IsInfinity(scaleheight))
        
            scaleheight = 1;
        
        // Convert start point and size to integer.
        var startPointX = (uint)Math.Floor(startPoint.X * scaleWidth);
        var startPointY = (uint)Math.Floor(startPoint.Y * scaleheight);
        var height = (uint)Math.Floor(cropSize.Height * scaleheight);
        var width = (uint)Math.Floor(cropSize.Width * scaleWidth);

        // Create a decoder from the stream. With the decoder, we can get 
        // the properties of the image.
        var decoder = await BitmapDecoder.CreateAsync(originalImage);

        // The scaledSize of original image.
        var scaledWidth = (uint)(decoder.PixelWidth);
        var scaledHeight = (uint)(decoder.PixelHeight);

        // Refine the start point and the size. 
        if (startPointX + width > scaledWidth)
        
            startPointX = scaledWidth - width;
        

        if (startPointY + height > scaledHeight)
        
            startPointY = scaledHeight - height;
        

        // Get the cropped pixels.
        var pixels = await GetPixelData(decoder, startPointX, startPointY, width, height,
            scaledWidth, scaledHeight);

        // Stream the bytes into a WriteableBitmap
        var cropBmp = new WriteableBitmap((int)width, (int)height);
        var pixStream = cropBmp.PixelBuffer.AsStream();
        pixStream.Write(pixels, 0, (int)(width * height * 4));

        return cropBmp;
    

 private static async Task<byte[]> GetPixelData(BitmapDecoder decoder, uint startPointX, uint startPointY,
          uint width, uint height, uint scaledWidth, uint scaledHeight)
        
            var transform = new BitmapTransform();
            var bounds = new BitmapBounds();
            bounds.X = startPointX;
            bounds.Y = startPointY;
            bounds.Height = height;
            bounds.Width = width;
            transform.Bounds = bounds;

            transform.ScaledWidth = scaledWidth;
            transform.ScaledHeight = scaledHeight;

            // Get the cropped pixels within the bounds of transform.
            var pix = await decoder.GetPixelDataAsync(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Premultiplied,
                transform,
                ExifOrientationMode.IgnoreExifOrientation,
                ColorManagementMode.ColorManageToSRgb);
            var pixels = pix.DetachPixelData();
            return pixels;
        

【讨论】:

【参考方案2】:

Microsoft 发布了一个示例 Windows 10 应用程序,该应用程序提供图像裁剪功能。大部分代码都可以在 Windows Phone 8.1 中重用。

控件在这里:https://github.com/Microsoft/Appsample-Photosharing/blob/master/PhotoSharingApp/PhotoSharingApp.Universal/Controls/CropControl.cs

并在以下页面中使用:https://github.com/Microsoft/Appsample-Photosharing/blob/master/PhotoSharingApp/PhotoSharingApp.Universal/Views/CropPage.xaml

您还必须检查在(搜索控件:CropControl)中声明的模板:https://github.com/Microsoft/Appsample-Photosharing/blob/master/PhotoSharingApp/PhotoSharingApp.Universal/Styles/Styles.xaml

【讨论】:

以上是关于Windows phone 8.1 裁剪矩形的主要内容,如果未能解决你的问题,请参考以下文章

Windows Phone 8.1 中的裁剪图像问题

Windows Phone - 裁剪 BitmapImage [关闭]

Windows Phone 裁剪视图

可以运行 2 个后台任务 - Windows Phone 8.1 通用应用程序?

适用于 Windows Phone 8.1(无 XAML)的最小应用程序:与桌面应用程序的差异

xml 适用于Windows 8.1和Windows Phone 8.1应用程序的扩展器控件演示。