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

如何使用C#从.pak归档文件加载图片到WinForms的PictureBox控件

实现思路与代码示例

首先明确:.pak是一类归档格式的统称,没有统一标准,以下实现基于游戏领域最常用的id Tech系列标准PAK格式(头标识为PACK),如果你使用的是自定义结构的.pak文件,只需调整结构体定义与读取逻辑即可。

核心步骤

  • 第一步:解析PAK文件头,获取文件表的偏移量与大小
  • 第二步:遍历文件表,匹配目标图片的文件名,拿到该文件在PAK中的偏移与大小
  • 第三步:读取对应区块的二进制数据,转为Image对象后赋值给PictureBox控件

代码实现

首先定义PAK结构的映射类:

using System.Runtime.InteropServices;
using System.IO;
using System.Drawing;

// PAK文件头结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PakHeader
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string Id; // 固定为"PACK"
    public int FileTableOffset; // 文件表相对于文件开头的偏移
    public int FileTableSize; // 文件表总大小
}

// PAK文件条目结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PakFileEntry
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 56)]
    public string FileName; // 文件名,最多56字符
    public int FileOffset; // 文件在PAK中的偏移
    public int FileSize; // 文件大小
}

然后是读取PAK中图片的工具方法:

public Image LoadImageFromPak(string pakFilePath, string targetImageFileName)
{
    using var fs = new FileStream(pakFilePath, FileMode.Open, FileAccess.Read);
    using var reader = new BinaryReader(fs);

    // 读取PAK头
    var headerBytes = reader.ReadBytes(Marshal.SizeOf<PakHeader>());
    var header = BytesToStruct<PakHeader>(headerBytes);
    if (header.Id != "PACK")
    {
        throw new InvalidDataException("非标准PAK格式文件");
    }

    // 读取整个文件表
    fs.Seek(header.FileTableOffset, SeekOrigin.Begin);
    int entryCount = header.FileTableSize / Marshal.SizeOf<PakFileEntry>();
    PakFileEntry? targetEntry = null;

    for (int i = 0; i < entryCount; i++)
    {
        var entryBytes = reader.ReadBytes(Marshal.SizeOf<PakFileEntry>());
        var entry = BytesToStruct<PakFileEntry>(entryBytes);
        if (entry.FileName.Equals(targetImageFileName, StringComparison.OrdinalIgnoreCase))
        {
            targetEntry = entry;
            break;
        }
    }

    if (!targetEntry.HasValue)
    {
        throw new FileNotFoundException("PAK中未找到目标图片", targetImageFileName);
    }

    // 读取图片二进制数据
    fs.Seek(targetEntry.Value.FileOffset, SeekOrigin.Begin);
    var imageBytes = reader.ReadBytes(targetEntry.Value.FileSize);

    // 二进制转Image对象
    using var ms = new MemoryStream(imageBytes);
    return Image.FromStream(ms);
}

// 字节数组转结构体的辅助方法
private T BytesToStruct<T>(byte[] bytes) where T : struct
{
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
    }
    finally
    {
        handle.Free();
    }
}

最后调用方法赋值给PictureBox:

// 示例调用,替换为你的PAK路径和图片文件名
try
{
    var image = LoadImageFromPak(@"C:\test\resource.pak", "ui/start_bg.png");
    pictureBox1.Image = image;
    // 可选设置图片显示模式
    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
}
catch (Exception ex)
{
    MessageBox.Show($"加载失败:{ex.Message}");
}

常见适配说明

  • 如果你使用的是.NET Framework低于4.5的版本,将代码中Marshal.SizeOf<T>()替换为Marshal.SizeOf(typeof(T))即可
  • 如果你的PAK文件是压缩打包的,读取到文件二进制后需要先调用对应解压算法(比如zlib、lz4)解压后再转Image
  • 如果是自定义结构的PAK,只需修改PakHeader和PakFileEntry的结构定义匹配你的归档规则即可
  • 若读取的图片是引擎专属格式(比如dds、tga等非GDI+原生支持的格式),需要额外引入对应格式的解析库转换后再赋值

内容的提问来源于stack exchange,提问作者Technika číslo 1 s.r.o

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 19:45:09