You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Forms中如何从图库图片扫描识别QR Code二维码

Xamarin 基于ZXing实现本地图片QR码扫描的修复方案

你的代码存在几个容易导致ZXing识别失败的问题,按以下步骤调整即可解决返回null的问题:

1. 首先修复基础语法错误

你现有代码中DependencyService调用缺少闭合尖括号,修正为:

var binaryBitmap = Xamarin.Forms.DependencyService.Get<IImageHelper>().GetBinaryBitmap(file.GetStream());

2. 配置ZXing解码提示参数

未配置解码优化参数是识别失败的高频原因,添加DecodeHints开启识别优化、指定QR码格式:

var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync();
if (file == null) return;
var reader = new QRCodeReader();
// 新增解码提示配置
var hints = new Dictionary<DecodeHintType, object>
{
    { DecodeHintType.TRY_HARDER, true }, // 开启高精度识别模式
    { DecodeHintType.POSSIBLE_FORMATS, new List<BarcodeFormat> { BarcodeFormat.QR_CODE } }, // 仅识别QR码减少性能消耗
    { DecodeHintType.CHARACTER_SET, "UTF-8" } // 指定字符编码避免中文乱码
};
var binaryBitmap = Xamarin.Forms.DependencyService.Get<IImageHelper>().GetBinaryBitmap(file.GetStream());
var result = reader.decode(binaryBitmap, hints); // 解码时传入hints

3. 优化像素读取逻辑,避免逐像素取值性能问题

你当前的GetRgbBytes方法逐像素调用GetPixel性能极低,大尺寸图片会触发识别超时,替换为批量读取像素的实现:

private byte[] GetRgbBytes(Bitmap image)
{
    int width = image.Width;
    int height = image.Height;
    int[] pixels = new int[width * height];
    // 批量读取所有像素到数组
    image.GetPixels(pixels, 0, width, 0, 0, width, height);
    byte[] rgbBytes = new byte[width * height * 3];
    for (int i = 0; i < pixels.Length; i++)
    {
        int pixel = pixels[i];
        rgbBytes[i * 3] = (byte)((pixel >> 16) & 0xff); // 红通道
        rgbBytes[i * 3 + 1] = (byte)((pixel >> 8) & 0xff); // 绿通道
        rgbBytes[i * 3 + 2] = (byte)(pixel & 0xff); // 蓝通道
    }
    return rgbBytes;
}

4. 增加Exif旋转修正

手机拍摄的照片通常自带Exif旋转标记,未修正旋转的歪斜二维码会导致ZXing识别失败,在GetBinaryBitmap中新增旋转处理逻辑:

public BinaryBitmap GetBinaryBitmap(Stream image)
{
    // 先将流转为字节数组,同时用于解码和Exif读取
    byte[] imageBytes;
    using (var ms = new MemoryStream())
    {
        image.CopyTo(ms);
        imageBytes = ms.ToArray();
    }
    
    // 解码Bitmap,可根据图片尺寸调整InSampleSize做降采样,提升识别效率
    BitmapFactory.Options options = new BitmapFactory.Options
    {
        InSampleSize = 2 // 宽高缩小为原尺寸的1/2,可根据实际场景调整
    };
    Bitmap bitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length, options);
    
    // 读取Exif旋转角度
    var exif = new ExifInterface(new MemoryStream(imageBytes));
    var orientation = exif.GetAttributeInt(ExifInterface.TagOrientation, (int)Orientation.Normal);
    float rotation = orientation switch
    {
        (int)Orientation.Rotate90 => 90,
        (int)Orientation.Rotate180 => 180,
        (int)Orientation.Rotate270 => 270,
        _ => 0
    };
    
    // 修正Bitmap旋转
    if (rotation != 0)
    {
        Matrix matrix = new Matrix();
        matrix.PostRotate(rotation);
        bitmap = Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
    }

    // 生成BinaryBitmap返回
    byte[] rgbBytes = GetRgbBytes(bitmap);
    var luminanceSource = new RGBLuminanceSource(rgbBytes, bitmap.Width, bitmap.Height);
    var binarizer = new HybridBinarizer(luminanceSource);
    return new BinaryBitmap(binarizer);
}

更简单的替代方案

无需手动封装BinaryBitmap,直接使用ZXing.Net.Mobile自带的BarcodeReader类的重载方法,直接传入处理后的Bitmap即可,ZXing内部会自动完成像素转换、二值化等逻辑:

// IImageHelper接口新增方法实现
public string ScanQrFromImage(Stream imageStream)
{
    byte[] imageBytes;
    using (var ms = new MemoryStream())
    {
        imageStream.CopyTo(ms);
        imageBytes = ms.ToArray();
    }
    
    // 解码并修正旋转(逻辑同上)
    var bitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
    // 修正旋转逻辑省略,和上面一致
    
    var reader = new BarcodeReader
    {
        AutoRotate = true,
        Options = new DecodingOptions
        {
            TryHarder = true,
            PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }
        }
    };
    var result = reader.Decode(bitmap);
    return result?.Text;
}

内容的提问来源于stack exchange,提问作者Tahir Mahmood Hashmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 02:09:02