2016-11-23 8 views
0

Windows 10 Mobile에서 실행되는 Windows 10 UWP 앱이 있습니다. 내가 가진 요구 사항은 사용자로부터 서명을 포착하는 것입니다. 지금까지 XAML에서 InkCanvas를 사용하고 코드에 연결했습니다.WCF 통화를 사용하여 InkCanvas 서명 보내기

다음 버튼을 클릭하면 InkCanvas에서 서명을 받아 WCF 호출을 통해 서버로 전송됩니다. 서버 및 WCF 서비스가 이미 있습니다. 서명 이미지를 base64 serialize 된 문자열로 사용합니다.

일단 이미지 나 바이트 배열이 있으면 base64를 얻는 방법을 알고 있습니다. 그러나 많은 시간을 읽으면서 기사/예제가 WPF 또는 Windows 8.1 용으로 작성되었으며 Windows 10 UWP에서 작동하지 않는다는 사실을 발견했습니다. 또한 작동하는 것으로 밝혀진 예제 중 GIF로 파일에 서명을 저장하는 것이 유일한 방법 인 것 같습니다.

은 내가 나에게 InkStroke의 읽기 전용 목록을 반환하는이

var strokeCollection = cvsSignature.InkPresenter.StrokeContainer.GetStrokes(); 

같은 GetStrokes()를 호출 할 수있는 것을 알 수있다. 그 목록을 반복하고 바이트 배열을 만들 수있을 것 같아요? 내가 어떻게 그럴 수 있니? 이것이 효율적이지 않은 것 같습니까?

그렇지 않으면 스트림을 파일 스트림에서 메모리 스트림으로 변경할 수 있다고 생각했지만 가능하지 않거나 뭔가 빠졌습니다. 나는 시도하고이

using (var inkMemStream = new MemoryStream()) 
{ 
    await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(inkMemStream); 
} 

그러나 나는

감사를 Windows.Storage.Streams.IOutputStream하는 System.IO.MemoryStream에서 변환 할 수없는 예외가 접근 이러한 유형의 !

답변

1

InkCanvas를 파일이나 GIF로 저장하지 않고 메모리에서 조작하고 싶지 않은 경우를 발견했습니다. 사실 아래 세 가지 옵션이 있습니다. 이 중 일부의 경우 정확한 이름을 검색하여 NuGet에서 찾을 수있는 Win2D.uwp에 대한 참조를 추가해야합니다. Microsoft에서 제공합니다.

  1. 바이트 배열에 InkCanvas 변환 :

    private byte[] ConvertInkCanvasToByteArray() 
    { 
        //First, we need to get all of the strokes in the canvas 
        var canvasStrokes = myCanvas.InkPresenter.StrokeContainer.GetStrokes(); 
    
        //Just as a check, make sure to only do work if there are actually strokes (ie not empty) 
        if (canvasStrokes.Count > 0) 
        { 
         var width = (int)myCanvas.ActualWidth; 
         var height = (int)myCanvas.ActualHeight; 
         var device = CanvasDevice.GetSharedDevice(); 
         //Create a new renderTarget with the same width and height as myCanvas at 96dpi 
         var renderTarget = new CanvasRenderTarget(device, width, 
          height, 96); 
    
         using (var ds = renderTarget.CreateDrawingSession()) 
         { 
          //This will clear the renderTarget with a clean slate of a white background. 
          ds.Clear(Windows.UI.Colors.White); 
          //Here is where we actually take the strokes from the canvas and draw them on the render target. 
          ds.DrawInk(myCanvas.InkPresenter.StrokeContainer.GetStrokes()); 
         } 
         //Finally, this will return the render target as a byte array. 
         return renderTarget.GetPixelBytes(); 
        } 
        else 
        { 
         return null; 
        } 
    } 
    
  2. 을 당신이 필요로하는 모든 픽셀의 바이트 배열 인 경우, 작업이 완료된다. 그러나 이미지를 생성하려면 WriteableBitmap을 사용합니다. 이를 위해 호출 할 수있는 동기화 및 비동기 메소드가 있습니다.

    private WriteableBitmap GetSignatureBitmapFull() 
    { 
        var bytes = ConvertInkCanvasToByteArray(); 
    
        if (bytes != null) 
        { 
         var width = (int)cvsSignature.ActualWidth; 
         var height = (int)cvsSignature.ActualHeight; 
    
         var bmp = new WriteableBitmap(width, height); 
         using (var stream = bmp.PixelBuffer.AsStream()) 
         { 
          stream.Write(bytes, 0, bytes.Length); 
          return bmp; 
         } 
        } 
        else 
         return null; 
    } 
    
    private async Task<WriteableBitmap> GetSignatureBitmapFullAsync() 
    { 
        var bytes = ConvertInkCanvasToByteArray(); 
    
        if (bytes != null) 
        { 
         var width = (int)cvsSignature.ActualWidth; 
         var height = (int)cvsSignature.ActualHeight; 
    
         var bmp = new WriteableBitmap(width, height); 
         using (var stream = bmp.PixelBuffer.AsStream()) 
         { 
          await stream.WriteAsync(bytes, 0, bytes.Length); 
          return bmp; 
         } 
        } 
        else 
         return null; 
    } 
    
  3. 마지막으로, 여기에 당신이 그렇게 할 경우 나는 비트 맵에 수확을 할 수 있도록 사용하고 비동기 방식이다. 이 방법의 핵심은이 방법을 사용하면 픽셀 바이트를 배열로 먼저 가져올 필요가 없다는 점입니다. 당신은 캔버스에서 스트로크를 얻을 다음은 메모리 스트림은 Windows 10 유니버설에서 InkCanvas를 사용할 때 몇 가지 대안을 제공 할 수 있습니다

    private async Task<WriteableBitmap> GetSignatureBitmapCropped() 
    { 
        try 
        { 
         var canvasStrokes = cvsSignature.InkPresenter.StrokeContainer.GetStrokes(); 
    
         if (canvasStrokes.Count > 0) 
         { 
          var bounds = cvsSignature.InkPresenter.StrokeContainer.BoundingRect; 
          var xOffset = (uint)Math.Round(bounds.X); 
          var yOffset = (uint)Math.Round(bounds.Y); 
          var pixelWidth = (int)Math.Round(bounds.Width); 
          var pixelHeight = (int)Math.Round(bounds.Height); 
    
          using (var memStream = new InMemoryRandomAccessStream()) 
          { 
           await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(memStream); 
    
           var decoder = await BitmapDecoder.CreateAsync(memStream); 
    
           var transform = new BitmapTransform(); 
           var newBounds = new BitmapBounds(); 
           newBounds.X = 0; 
           newBounds.Y = 0; 
           newBounds.Width = (uint)pixelWidth; 
           newBounds.Height = (uint)pixelHeight; 
           transform.Bounds = newBounds; 
    
           var pdp = await decoder.GetPixelDataAsync(
            BitmapPixelFormat.Bgra8, 
            BitmapAlphaMode.Straight, 
            transform, 
            ExifOrientationMode.IgnoreExifOrientation, 
            ColorManagementMode.DoNotColorManage); 
    
           var pixels = pdp.DetachPixelData(); 
    
           var cropBmp = new WriteableBitmap(pixelWidth, pixelHeight); 
    
           using (var stream = cropBmp.PixelBuffer.AsStream()) 
           { 
            await stream.WriteAsync(pixels, 0, pixels.Length); 
           } 
           return cropBmp; 
          } 
         } 
         else 
         { 
          return null; 
         } 
        } 
        catch (Exception ex) 
        { 
         return null; 
        } 
    } 
    

희망에 직접 저장됩니다.

0

내 유일한 옵션은 GIF 파일로 서명을 저장하는 것입니다.

GIF이 유일한 선택은 아닙니다. official sampleGIF으로 표시되지만 InkStokes 컬렉션은 JPGPNG으로 저장할 수도 있습니다. 코드는 다음과 같이 보시다시피

var savePicker = new Windows.Storage.Pickers.FileSavePicker(); 
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary; 
savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg" ,".gif",".png"}); 
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync(); 

그러나 접근 이러한 유형의

내가 얻을 내가 System.IO.MemoryStream에서 변환 할 수 없습니다 예외가

을 Windows.Storage.Streams.IOutputStream하기 System.IO.MemoryStream에서 Windows.Storage.Streams.IOutputStream으로 직접 변환 할 수 없습니다. ImageSource으로 저장 한 이미지 파일을 읽어야합니다. 일단 이미지 또는 바이트 배열이 있으면 base64를 얻는 방법을 알았습니다. 그래서 우리가 필요로하는 것은 이미지 파일에서 이미지 나 바이트 배열을 얻는 것입니다.

using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read) 
{ 
    var bitmap = new BitmapImage(); 
    bitmap.SetSource(streamforread); 
} 
:

if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0) 
{ 
    var savePicker = new Windows.Storage.Pickers.FileSavePicker(); 
    savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary; 
    savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg", ".gif", ".png" }); 
    Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync(); 
    if (null != file) 
    { 
     using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite)) 
     { 
      await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream); 
     } 
     using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read)) 
     { 
      WriteableBitmap inkimagesource = new WriteableBitmap(50, 50); 
      inkimagesource.SetSource(streamforread); 
      byte[] imageBuffer = inkimagesource.PixelBuffer.ToArray(); 
      MemoryStream ms = new MemoryStream(imageBuffer); 
     } 
    } 
} 

을 다음과 같이

단지 다음과 같이 코드를 읽고 파일을 변경해야 할 이미지 소스로 파일을 읽기 바이트 배열로 이미지 파일 다음 메모리 스트림을 읽기

그 목록을 반복하고 바이트 배열을 만들 수있을 것 같아요? 내가 어떻게 그럴 수 있니? 이것이 효율적이지 않은 것 같습니까?

현재 API는 InkStroke 컬렉션을 바이트 배열로 직접 빌드 할 수있는 것은 아닙니다. SaveAsync() 메서드는 이미 InkStroke 컬렉션을 스트림에 저장하는 데 도움이됩니다. 위의 코드를 사용하여 스트림을 사용할 수 있습니다.

+0

자세한 사례를 가져 주셔서 감사합니다. 나는 이것을 더 깊이 조사 할 것이다. 그러나 주석 으로서는 파일에 저장 한 다음 파일에서 읽고 내가하고 싶은 것을하기 위해 머리를 감쌀 수 없습니다. 이는 처음에는 파일에 저장할 필요가없는 응용 프로그램의 경우 예상치 못한 가난하고 값 비싼 방식입니다. InkCanvas 클래스가 메모리에 직접 저장하는 기능을 사용하지 않는다는 사실에 놀랐습니다. –