UWP image editor (graffiti, cropping, merging) and uwp Cropping

Source: Internet
Author: User

UWP image editor (graffiti, cropping, merging) and uwp Cropping
1. Editor Introduction

Before writing this control, I always want to find an open-source one, which can be easy to use. However, I have searched all the places and cannot find them.

So, be the first person to eat crabs!

Controls have three main functions: graffiti, cropping, and merging.

Graffiti: InkToolbar and InkCanvas are used.

Cropping: This is complicated to use and the source code will be published.

Merge: scale the graffiti layer proportionally to the source image size, and then combine the two layers.

GitHub address

II. Implementation of graffiti Functions

Here, a widget written by others is used to save trouble, mainly to switch the paint brush and color conveniently. You can write controls by yourself.

It can be used as ready-to-use, with fewer lines of code.

Inktoolbar:

Https://visualstudiogallery.msdn.microsoft.com/58194dfe-df44-4c4e-893a-1eca40675269

Initialize the Ink-related controls:

                    <InkCanvas Name="ink_canvas"><ink:InkToolbar x:Name="inktoolbar"  ButtonHeight="60" ButtonWidth="60" ButtonBackground="Transparent" >
ink_canvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch | CoreInputDeviceTypes.Pen;inktoolbar.TargetInkCanvas = this.ink_canvas;


Method for obtaining graffiti:

1. Obtain from InkCanvas:

This is the screen rendered image, that is, the image is scaled.

Advantage: high speed.

Disadvantage: The image is scaled down to the control size, not the source image size. For example, if the source image is a 2880*1600 image, the size of the image obtained after the graffiti is 288*160.

CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)ink_canvas.ActualWidth, (int)ink_canvas.ActualHeight, 96);renderTarget.SetPixelBytes(new byte[(int)ink_canvas.ActualWidth * 4 * (int)ink_canvas.ActualHeight]);using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite)){    await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);}

2. layer Synthesis

First, obtain the ink layer and scale it to the source image size. Then combine the Ink layer and the source image layer. The source code of the zoom and merge algorithms will be at the end of the article.

Advantage: The image size remains unchanged, which is equivalent to graffiti on the source image.

Disadvantage: the computation is complex and time-consuming.

CanvasDevice device = CanvasDevice.GetSharedDevice();CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)ink_canvas.ActualWidth, (int)ink_canvas.ActualHeight, 96);renderTarget.SetPixelBytes(new byte[(int)ink_canvas.ActualWidth * 4 * (int)ink_canvas.ActualHeight]);using (var ds = renderTarget.CreateDrawingSession()){    IReadOnlyList<InkStroke> inklist = ink_canvas.InkPresenter.StrokeContainer.GetStrokes();    Debug.WriteLine("Ink_Strokes Count:  " + inklist.Count);   ds.DrawInk(inklist);}var inkpixel = renderTarget.GetPixelBytes();WriteableBitmap bmp = new WriteableBitmap((int)ink_canvas.ActualWidth, (int)ink_canvas.ActualHeight);Stream s = bmp.PixelBuffer.AsStream();s.Seek(0, SeekOrigin.Begin);s.Write(inkpixel, 0, (int)ink_canvas.ActualWidth * 4 * (int)ink_canvas.ActualHeight);WriteableBitmap ink_wb = await ImageProcessing.ResizeByDecoderAsync(bmp, sourceImage.PixelWidth, sourceImage.PixelHeight, true);WriteableBitmap combine_wb = await ImageProcessing.CombineAsync(sourceImage, ink_wb);

 

Iii. Implementation of Cropping

There are already many templates written by our predecessors in WPF. You do not need to make too many modifications to use them here. The code will be given at the end of the article

However, a problem occurs in UWP.

To facilitate user alignment, the cropping area is divided into nine cells.

At this time, I thought of Drawing four rectangles, but this would be choppy, and choppy.

 

<Rectangle x:Name="horizontalLine" Canvas.Left="{Binding SelectedRect.Left}" Canvas.Top="{Binding HorizontalLineCanvasTop}" Height="1" Width="{Binding SelectedRect.Width}" Fill="{ThemeResource ApplicationForegroundThemeBrush}"/><Rectangle x:Name="verticalLine" Canvas.Left="{Binding VerticalLineCanvasLeft}" Canvas.Top="{Binding SelectedRect.Top}" Width="1" Height="{Binding SelectedRect.Height}" Fill="{ThemeResource ApplicationForegroundThemeBrush}"/><Rectangle x:Name="horizontalLine1" Canvas.Left="{Binding SelectedRect.Left}" Canvas.Top="{Binding HorizontalLine1CanvasTop}" Height="1" Width="{Binding SelectedRect.Width}" Fill="{ThemeResource ApplicationForegroundThemeBrush}"/><Rectangle x:Name="verticalLine1" Canvas.Left="{Binding VerticalLine1CanvasLeft}" Canvas.Top="{Binding SelectedRect.Top}" Width="1" Height="{Binding SelectedRect.Height}" Fill="{ThemeResource ApplicationForegroundThemeBrush}"/>

The solution is to draw the Path. Because of the drawing mechanism, there will be no freezing, giving users the feeling of lubrication.

<Path x:Name="horizontalLine" Fill="{ThemeResource ApplicationForegroundThemeBrush}" Stroke="{ThemeResource ApplicationForegroundThemeBrush}" StrokeThickness="0.5">  <Path.Data>      <RectangleGeometry Rect="{Binding HorizontalLine1}"/>  </Path.Data></Path><Path x:Name="horizontalLine1" Fill="{ThemeResource ApplicationForegroundThemeBrush}" Stroke="{ThemeResource ApplicationForegroundThemeBrush}" StrokeThickness="0.5">  <Path.Data>    <RectangleGeometry Rect="{Binding HorizontalLine2}"/>  </Path.Data></Path><Path x:Name="verticalLine" Fill="{ThemeResource ApplicationForegroundThemeBrush}" Stroke="{ThemeResource ApplicationForegroundThemeBrush}" StrokeThickness="0.5">  <Path.Data>    <RectangleGeometry Rect="{Binding VerticalLine1}"/>  </Path.Data></Path><Path x:Name="verticalLine1" Fill="{ThemeResource ApplicationForegroundThemeBrush}" Stroke="{ThemeResource ApplicationForegroundThemeBrush}" StrokeThickness="0.5">  <Path.Data>    <RectangleGeometry Rect="{Binding VerticalLine2}"/>  </Path.Data></Path>

 

Iv. Image Synthesis

First, scale the graffiti layer. Here, you can use algorithms such as Fant and double cubic spline interpolation. Then the layers are merged Based on the transparency of the graffiti layer and the source image layer.

The method of layer merging is not necessarily correct. It feels like this: if the upper layer is transparent, it is 0.7. Then, the merged pixel is the upper pixel value x 0.7 + lower pixel value x (1-0.7 ). If there are multiple layers, merge them from top to bottom.

      public static byte[] Combine(byte[] basesrc, byte[] floatsrc,int width, int height)        {            byte[] retsrc = new byte[height * 4 * width];            for (int x = 0; x < width; ++x)            {                for (int y = 0; y < height; ++y)                {                    int[] color_float = getBGR(floatsrc, x, y, width);                    int alpha_float = GAP(floatsrc, x, y, width);                    int[] color_base = getBGR(basesrc, x, y, width);                    int alpha_base = GAP(basesrc, x, y, width);                    int R=0, G=0, B=0, A=0;                    if (alpha_base != 255)                    {                        color_base[0] = color_base[1] = color_base[2] = alpha_base = 255;                        color_base[0] = (255 * (255 - alpha_float) + color_float[0] * alpha_base) / 255;                        color_base[1] = (255 * (255 - alpha_float) + color_float[1] * alpha_base) / 255;                        color_base[2] = (255 * (255 - alpha_float) + color_float[2] * alpha_base) / 255;                        alpha_base = 255;                    }                    if (color_float[0] == 0 && color_float[1] == 0 && color_float[2] == 0 && alpha_float == 0)                    {                        B = color_base[0];                        G = color_base[1];                        R = color_base[2];                        A = alpha_base;                    }                    else                    {                        B = (color_base[0] * (255 - alpha_float) + color_float[0] * alpha_float) / 255;                        G = (color_base[1] * (255 - alpha_float) + color_float[1] * alpha_float) / 255;                        R = (color_base[2] * (255 - alpha_float) + color_float[2] * alpha_float) / 255;                        A = alpha_float+(255-alpha_float)*(alpha_base/255);                        A = A > 255 ? 255 : A;                    }                                        putpixel(retsrc, x, y, width, R, G, B, A);                }            }            return retsrc;        }

 

GtiHub address: https://github.com/LeoLeeCN/UWP_Toolkit

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.