在Xamarin.Forms中获取Image或ImageSource的bytes []/stream?

Jos*_*phA 7 c# android ios xamarin

我一直在挖掘Xamarin.Forms.Labs,以了解有关如何访问和操作图像的更多信息.将图像保存到Android/iOS照片库工作正常,至少通过用户交互从任一图像中检索图像也是如此.

问题是我希望能够在内部将一些文件保存到程序中.实际上保存文件本身似乎不是问题 - 我已经为此编写了一个接口/ DependencyService解决方案.

我似乎无法做的是使用Xamarin.Forms Image或ImageSource访问图像数据本身的bytes []或流.使用静态方法将流读入ImageSource相对简单,那么如何将这些字节输出以便将文件保存在程序本身中?

为了构建这个:我正在开发一个应用程序,用户在表单中包含/选择图片,并最终将表单发布到网站.因此能够实际保存图片或访问数据本身以便传输它是非常关键的.

Nik*_*hev 0

一种非常巧妙的方法是为您的图像编写一个自定义渲染器。byte[]/Stream然后渲染器将从本机控件获取。这是一个非常粗略的实现,没有任何错误处理来帮助您入门:

public class MyImage : Image
{
    public Func<byte[]> GetBytes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是iOS渲染器:

public class MyImageRenderer : ImageRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);

        var newImage = e.NewElement as MyImage;
        if (newImage != null)
        {
            newImage.GetBytes = () =>
            {
                return this.Control.Image.AsPNG().ToArray();
            };
        }

        var oldImage = e.OldElement as MyImage;
        if (oldImage != null)
        {
            oldImage.GetBytes = null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Android涉及更多一些:

public class MyImageRenderer : ImageRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);

        var newImage = e.NewElement as MyImage;
        if (newImage != null)
        {
            newImage.GetBytes = () =>
            {
                var drawable = this.Control.Drawable;
                var bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888);
                drawable.Draw(new Canvas(bitmap));
                using (var ms = new MemoryStream())
                {
                    bitmap.Compress(Bitmap.CompressFormat.Png, 100, ms);
                    return ms.ToArray();
                }
            };
        }

        var oldImage = e.OldElement as MyImage;
        if (oldImage != null)
        {
            oldImage.GetBytes = null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,用法是显而易见的:

var bytes = myImage.GetBytes?.Invoke();
Run Code Online (Sandbox Code Playgroud)

将这个想法扩展到支持流应该非常简单。明显的警告是,表单控件 ( MyImage) 通过 保留对其渲染器的引用GetBytes(),但这似乎是不可避免的。