在Xamarin.Forms中获取图像或ImageSource的字节[]/流

本文关键字:字节 ImageSource Forms Xamarin 获取 图像 | 更新日期: 2023-09-27 18:22:35

我一直在深入研究Xamarin.Forms.Labs,以了解有关如何访问和操作图像的更多信息。将图像保存到Android/iOS照片库中效果很好,从两者中检索图像也很好,至少在用户交互时是这样。

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

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

为此:我现在正在开发一个应用程序,用户可以在该应用程序中拍摄/选择要包含在表单中的图片,表单最终会发布到网站上。因此,能够真正保存图片,或者访问数据本身以传输数据,是非常关键的。

在Xamarin.Forms中获取图像或ImageSource的字节[]/流

一种非常巧妙的方法是为您的图像编写自定义渲染器。然后,渲染器将从本机控件获取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;
        }
    }
}

安卓的版本更为复杂:

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()保留了对其呈现器的引用,但这似乎是不可避免的。