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

时间:2014-09-19 16:23:49

标签: c# android ios xamarin

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

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

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

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

1 个答案:

答案 0 :(得分:1)

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

public class MyImage : Image
{
    public Func<byte[]> GetBytes { get; set; }
}

以下是 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;
        }
    }
}

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;
        }
    }
}

最后,用法很明显:

var bytes = myImage.GetBytes?.Invoke();

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