2
votes

I'm trying to do some ocr with windows phone 8.1 using this: https://blogs.windows.com/buildingapps/2014/09/18/microsoft-ocr-library-for-windows-runtime/

private async void camera_PhotoConfirmationCaptured(MediaCapture sender, PhotoConfirmationCapturedEventArgs e)
{
    try
    {
        WriteableBitmap bitmap = new WriteableBitmap((int)e.Frame.Width, (int)e.Frame.Height); //crash here
        await bitmap.SetSourceAsync(e.Frame);

        OcrResult result = await ocr.RecognizeAsync(e.Frame.Height, e.Frame.Width, bitmap.PixelBuffer.ToArray());

        foreach (var line in result.Lines)
        {

        }
    }

    catch(Exception ex)
    {

    }
}

private async void takePictureButton_Click(object sender, RoutedEventArgs e)
{
    await camera.CapturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.CreatePng(), imageStream);
}

I keep getting a crash on the WriteableBitmap constructor and I don't know what to do to fix it. RecognizeAsync must take a writeable bitmap. Here's the exception:

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

EDIT1:

I tried this code and got an exception on this line:

        WriteableBitmap bitmap = null;

        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
        {
            bitmap = new WriteableBitmap((int)e.Frame.Width, (int)e.Frame.Height); //crash here again
            await bitmap.SetSourceAsync(e.Frame);

            OcrResult result = await ocr.RecognizeAsync(e.Frame.Height, e.Frame.Width, bitmap.PixelBuffer.ToArray());

            foreach (var line in result.Lines)
            {

            }
        });

"Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))"

What do you think is causing this?

1
Don't create the Bitmap on one thread then access it on another.whoisj

1 Answers

3
votes

You have a couple of problems here. The first error (RPC_E_WRONG THREAD) is because UI objects need to be called from the dispatcher (aka UI) thread, not from a worker thread. You can call Dispatcher.RunAsync to have a delegate called on the dispatcher thread to call WriteableBitmap, something like"

await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        // Do stuff on dispatcher thread
    });

The second error you are getting once you updated the code to run on the dispatcher thread is probably on the SetSourceAsync call rather than the WriteableBitmap constructor. The Frame passed in the PhotoConfirmationCaptured event is the raw bits, not an encoded file, so SetSourceAsync doesn't know what to do with it. Instead you need to pass the bits directly into the WriteableBitmap's PixelBuffer. This is called out in the Remarks for the PhotoConfirmationCaptured event and its Frame property. Definitely read and understand the latter:

   void PhotoConfirmationCaptured(MediaCapture sender, PhotoConfirmationCapturedEventArgs args)
   {
   using (ManualResetEventSlim evt = new ManualResetEventSlim(false))
   {
       Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
       {
           try
           {
               WriteableBitmap bmp = new WriteableBitmap(unchecked((int)args.Frame.Width), unchecked((int)args.Frame.Height));
               using (var istream = args.Frame.AsStream())
               using (var ostream = bmp.PixelBuffer.AsStream())
               {
                   await istream.CopyStreamToAsync(ostream);
               }
           }
           finally
           {
               evt.Set();
           }

       });

       evt.Wait();
   }

}