Search code examples
embedded-resourceuno-platform

Uno platform: load embedded resource file


How do I load an embedded resource for the Android head ? My code, below works for UWP:

  Assembly assembly = GetType ().GetTypeInfo ().Assembly;
  string[] names = assembly.GetManifestResourceNames ();
  Console.WriteLine ("Resource Names");
  foreach (var name in names)
    Console.WriteLine ("  " + name);
  using (var stream = assembly.GetManifestResourceStream (Source))
  {
    bmpSrc = SKBitmap.Decode (stream);
  }

And, the XAML is

  <controls:ExpandableImage 
    ...
    Source="UnoTest.Assets.icons.folder_tab.png"
  />

The file resides in UnoTest.Shared/Assets/ and is marked as "embedded resource".

The debug output shows that one of the "names" is

"UnoTest.Droid.Assets.icons.folder_tab.png"

indicating that my URI should be referring to the Android head.

EDIT

Ultimately, in this experiment, I am intending to paint the left part of the bitmap in the left of the target area, the right in the right, and fill the middle with an expansion of a vertical stripe from the bitmap's mid section. Then, draw some text over it.

private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
  ...
  // identify left, right halves and a 10px wide swath of the middle of the source bitmap
  SKRect rectSrcLeft = new SKRect(0, 0, bmpSrc.Width / 2, bmpSrc.Height);
  SKRect rectSrcRight = new SKRect(bmpSrc.Width / 2, 0, bmpSrc.Width, bmpSrc.Height);
  SKRect rectSrcMid = new SKRect(bmpSrc.Width / 2 - 5, 0, bmpSrc.Width / 2 + 5, bmpSrc.Height);

  // create a new bitmap containing a 10 pixel wide swatch from middle of bmpSrc
  SKBitmap bmpSrcMid = new SKBitmap(10, bmpSrc.Height);
  using (SKCanvas tempCanvas = new SKCanvas(bmpSrcMid))
  {
    SKRect rectDest = new SKRect(0, 0, rectSrcMid.Width, rectSrcRight.Height);
    tempCanvas.DrawBitmap(bmpSrc, rectSrcMid, rectDest);
  }

  var canvas = e.Surface.Canvas;

  using (SKPaint paint = new SKPaint())
  {
    canvas.Save();
    float hDest = canvas.DeviceClipBounds.Height;
    float scale = hDest / (float)bmpSrc.Height;
    canvas.Scale(scale);

    paint.IsAntialias = true;

    // determine dest rect for middle section
    float rightDest = (float)textBounds.Width / scale; // rightmost point of whole target area
    SKRect rectDestMid = new SKRect(rectSrcLeft.Width, 0, rightDest - rectSrcRight.Width, rectSrcRight.Height);

    // left part of tab
    canvas.DrawBitmap(bmpSrc, rectSrcLeft, rectSrcLeft, paint);

    // right part of tab
    {
      SKRect rectDest = new SKRect(rectDestMid.Right, 0, rightDest, rectSrcRight.Height);
      canvas.DrawBitmap(bmpSrc, rectSrcRight, rectDest, paint);
    }

    // mid part of tab
    paint.Shader = SKShader.CreateBitmap(bmpSrcMid,
                                         SKShaderTileMode.Repeat,
                                         SKShaderTileMode.Repeat);
    canvas.DrawRect(rectDestMid, paint);

    canvas.Restore(); // back to orig scale
  }

  using (SKPaint paint = new SKPaint { Color = SKColors.Black })
  {
    float leftText = 20; // matches padding in ListPage.xaml
    float bottomText = canvas.DeviceClipBounds.Height / 2 + textCoreHeight / 2;
    canvas.DrawText(Label, new SKPoint(leftText, bottomText), paint);
  }
}

The XAML for the control is:

<UserControl
  x:Class="UnoTest.Shared.Controls.ExpandableImage"
  ...
  <skia:SKXamlCanvas x:Name="EICanvas" PaintSurface="OnPaintSurface" />
</UserControl>

Do I need to write some code to modify the "generic" URI for the Android case ?


Solution

  • Here's what I ended up doing. It is not 100% robust but pretty close. And it's really simple.

      if (Source == null)
        return;
    
      string sourceWithNameSpace = null;
      Assembly assembly = GetType ().GetTypeInfo ().Assembly;
      string[] names = assembly.GetManifestResourceNames ();
      foreach (var name in names)
      {
        if (name.EndsWith (Source))
        {
          sourceWithNameSpace = name;
          break;
        }
      }
      if (sourceWithNameSpace == null)
        return;
    
      using (var stream = assembly.GetManifestResourceStream (sourceWithNameSpace))
      {
        bmpSrc = SKBitmap.Decode (stream);
      }
    

    And, in the XML file, leave off the project head from the Source path, e.g.:

        Source="Assets.icons.folder_tab.png"