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

.NET 7无PackageStore类,如何获取内存中Bitmap的URI?

.NET 7 中生成内存Bitmap的URI替代方案

在.NET 7中,PackageStore类被移除后,我们可以通过自定义内存包缓存+注册URI请求处理程序的方式,实现不创建临时文件的内存Bitmap URI生成逻辑。

核心思路

  1. 用静态类替代PackageStore,维护内存中的Package实例缓存
  2. 注册自定义的WebRequest处理程序,让系统能解析pack://格式的URI并读取内存中的流

实现步骤

1. 安装依赖

首先确保已安装System.IO.Packaging NuGet包:

Install-Package System.IO.Packaging

2. 实现内存包缓存类

用于存储和管理内存中的Package实例,替代原PackageStore的功能:

using System.Collections.Generic;
using System.IO.Packaging;
using System;
using System.Threading;

public static class MemoryPackageCache
{
    private static readonly Dictionary<Uri, Package> _packageCache = new Dictionary<Uri, Package>();
    private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

    public static void AddPackage(Uri packUri, Package package)
    {
        _lock.EnterWriteLock();
        try
        {
            if (_packageCache.ContainsKey(packUri))
                throw new InvalidOperationException("该URI对应的包已存在");
            _packageCache.Add(packUri, package);
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }

    public static bool TryGetPackage(Uri packUri, out Package? package)
    {
        _lock.EnterReadLock();
        try
        {
            return _packageCache.TryGetValue(packUri, out package);
        }
        finally
        {
            _lock.ExitReadLock();
        }
    }

    public static void RemovePackage(Uri packUri)
    {
        _lock.EnterWriteLock();
        try
        {
            if (_packageCache.TryGetValue(packUri, out var package))
            {
                package.Dispose();
                _packageCache.Remove(packUri);
            }
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
}

3. 实现自定义WebRequest处理程序

让系统能够解析pack:// URI并返回内存中的流:

using System.IO.Packaging;
using System.Net;
using System;

public class MemoryPackWebRequest : WebRequest
{
    private readonly PackagePart? _targetPart;

    private MemoryPackWebRequest(Uri uri)
    {
        // 解析pack URI,拆分出包URI和部件URI
        var packUri = PackUriHelper.GetPackageUri(uri);
        if (MemoryPackageCache.TryGetPackage(packUri, out var package))
        {
            var partUri = PackUriHelper.GetPartUri(uri);
            _targetPart = package.GetPart(partUri);
        }
    }

    public override Stream GetResponseStream()
    {
        return _targetPart?.GetStream() ?? throw new WebException("未找到内存中的包部件");
    }

    public override WebResponse GetResponse()
    {
        return new MemoryPackWebResponse(this);
    }

    // 自定义WebResponse实现
    public class MemoryPackWebResponse : WebResponse
    {
        private readonly MemoryPackWebRequest _request;

        public MemoryPackWebResponse(MemoryPackWebRequest request)
        {
            _request = request;
        }

        public override Stream GetResponseStream()
        {
            return _request.GetResponseStream();
        }
    }

    // WebRequest创建器
    public class MemoryPackWebRequestCreator : IWebRequestCreate
    {
        public WebRequest Create(Uri uri)
        {
            return new MemoryPackWebRequest(uri);
        }
    }
}

4. 注册处理程序并生成URI

在应用启动时注册pack://前缀的处理程序,然后修改原方法生成内存Bitmap的URI:

注册处理程序(例如在App.xaml.cs的OnStartup方法中)

WebRequest.RegisterPrefix("pack://", new MemoryPackWebRequest.MemoryPackWebRequestCreator());

生成内存Bitmap URI的方法

using System.IO.Packaging;
using System;
using System.IO;

Uri GetMemoryBitmapUri()
{
    // 创建内存包
    MemoryStream packStream = new MemoryStream();
    Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite);
    
    // 定义包的基础URI并添加到缓存
    Uri packBaseUri = new Uri("pack://memory_bitmap/");
    MemoryPackageCache.AddPackage(packBaseUri, pack);

    // 创建包中的图片部件
    Uri partUri = new Uri("/bitmap.jpg", UriKind.Relative);
    PackagePart imagePart = pack.CreatePart(partUri, System.Net.Mime.MediaTypeNames.Image.Jpeg);
    
    // 写入Bitmap字节数据
    byte[] bitmapBytes = GetInMemoryBitmapData(); // 替换为你的Bitmap字节获取逻辑
    using (Stream partStream = imagePart.GetStream())
    {
        partStream.Write(bitmapBytes, 0, bitmapBytes.Length);
    }

    // 生成最终的pack URI
    return PackUriHelper.Create(packBaseUri, partUri);
}

// 示例:模拟获取Bitmap字节数据的方法
byte[] GetInMemoryBitmapData()
{
    // 这里替换为实际的Bitmap转字节逻辑
    using (var ms = new MemoryStream())
    {
        // 假设你有一个Bitmap对象:bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        return ms.ToArray();
    }
}

注意事项

  • 内存管理:当不再需要该URI时,务必调用MemoryPackageCache.RemovePackage(packBaseUri)释放资源,避免内存泄漏。
  • URI唯一性:确保每个内存包的基础URI(如pack://memory_bitmap/)是唯一的,避免缓存冲突。
  • 兼容性:该方案适用于大多数接受URI并通过WebRequest读取流的类,若目标类有特殊的URI解析逻辑,可能需要调整自定义处理程序的实现。

内容的提问来源于stack exchange,提问作者undermind

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:21