System.Drawing.Bitmap から SoftwareBitmap を取得する方法 ＆ C#/WinRT で OCR やってみた - クリップボードから取得版


# 1. System.Drawing.Bitmap から SoftwareBitmap を取得する方法

2-1. ソースコード の MakeSoftwareBitmap メソッドの処理で実現可能。

## 1-1. SoftwareBitmap をプログラムから生成する方法（参考サイト）

[ビットマップ画像の作成、編集、保存 - UWP applications | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/uwp/audio-video-camera/imaging#create-or-edit-a-softwarebitmap-programmatically)

# 2. C#/WinRT で OCR やってみた - クリップボードから取得版

## 2-1. ソースコード

以下、[C#/WinRT で OCR やってみた - Qiita](https://qiita.com/kob58im/items/cdc0dbb93cf7f00e5144)からの派生

※SoftwareBitmap側 の RGB の順序が合っているかは裏どりしていない。

```csharp

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.Foundation;


class OcrTest
{
    [System.STAThread]
    static void Main(string[] args)
    {
        System.Drawing.Image img = System.Windows.Forms.Clipboard.GetImage();
        if (img != null)
        {
            var bmp = (System.Drawing.Bitmap)img; // 例外が発生する可能性あり
            SoftwareBitmap softBmp = MakeSoftwareBitmap(bmp);
            Task<string> ret = LoadImageAndOcr(softBmp);
            Console.WriteLine(ret.Result);
        }
    }

    [ComImport]
    [Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    unsafe interface IMemoryBufferByteAccess
    {
        void GetBuffer(out byte* buffer, out uint capacity);
    }

    static SoftwareBitmap MakeSoftwareBitmap(System.Drawing.Bitmap bmp)
    {
        unsafe {
            var softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, bmp.Width, bmp.Height, BitmapAlphaMode.Premultiplied);


            System.Drawing.Imaging.BitmapData bd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            byte* pSrc = (byte*)bd.Scan0;

            using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Write))
            {
                using (var reference = buffer.CreateReference())
                {
                    byte* pDest;
                    uint capacity;
                    ((IMemoryBufferByteAccess)reference).GetBuffer(out pDest, out capacity);

                    // Fill-in the BGRA plane
                    BitmapPlaneDescription bl = buffer.GetPlaneDescription(0);
                    for (int y = 0; y < bl.Height; y++) {
                        int blOffset = bl.StartIndex + y*bl.Stride;
                        int yb = y*bd.Stride;
                        for (int x = 0; x < bl.Width; x++) {
                            pDest[blOffset + 4*x    ] = pSrc[yb + 4*x    ]; // blue
                            pDest[blOffset + 4*x + 1] = pSrc[yb + 4*x + 1]; // green
                            pDest[blOffset + 4*x + 2] = pSrc[yb + 4*x + 2]; // red
                            pDest[blOffset + 4*x + 3] = (byte)255; // alpha
                        }
                    }
                }
            }
            
            bmp.UnlockBits(bd);

            return softwareBitmap;
        }
    }

    static async Task<OcrResult> detect(SoftwareBitmap bitmap)
    {
        var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
        var ocrResult = await MyWaitUtil<OcrResult>.GetResultWithWaiting( ocrEngine.RecognizeAsync(bitmap) );
        // https://docs.microsoft.com/ja-jp/uwp/api/windows.media.ocr.ocrresult.lines?view=winrt-19041
        return ocrResult;
    }
    
    static async Task<string> LoadImageAndOcr(SoftwareBitmap softwareBitmap)
    {
        OcrResult t = await detect(softwareBitmap);
        return t.Text;
    }
}

public static class MyWaitUtil<T>
{
    public static async Task<T> GetResultWithWaiting(IAsyncOperation<T> task)
    {
        while ( task.Status != AsyncStatus.Completed ) {
            if ( task.Status == AsyncStatus.Error || task.Status == AsyncStatus.Canceled ) {
                Console.WriteLine("Error or Canceled");
                return default(T);
            }
            await Task.Delay(1);
        };
        return task.GetResults();
    }
}

```