当前位置: 首页> 最新文章列表> 使用 pack() 创建图片/音频元数据头信息

使用 pack() 创建图片/音频元数据头信息

M66 2025-05-29

在处理二进制数据时,PHP 提供了一个非常强大的函数——pack()。它可以根据指定的格式将数据打包成二进制字符串,这对于创建图片、音频等媒体文件的元数据头信息非常有用。例如,想要构造一个 WAV 音频文件的头部信息、或是为一个 BMP 图片生成文件头,pack() 都能胜任。

什么是 pack()

pack() 函数的基本语法如下:

string pack(string $format, mixed ...$values)
  • $format 是格式字符串,用于指定每个值应如何转换为二进制。

  • $values 是一个或多个要转换的值。

常见的格式字符包括:

  • C:无符号字符(8 位)

  • n:无符号短整型(16 位,大端字节序)

  • v:无符号短整型(16 位,小端字节序)

  • N:无符号长整型(32 位,大端)

  • V:无符号长整型(32 位,小端)

  • a:NUL 填充字符串

  • A:空格填充字符串

实例一:创建 WAV 音频文件的头信息

WAV 文件的文件头遵循 RIFF 格式,一般由 44 字节的头部构成。以下是一个最小的 WAV 文件头构造示例:

<?php
$sampleRate = 44100;
$bitsPerSample = 16;
$channels = 2;
$dataSize = 100000; // 音频数据大小,假设为 100000 字节
$byteRate = $sampleRate * $channels * $bitsPerSample / 8;
$blockAlign = $channels * $bitsPerSample / 8;

// 构造 WAV 文件头
$header = pack(
    'A4VVA4A4VVvvVVvvA4V',
    'RIFF',                // ChunkID
    36 + $dataSize,        // ChunkSize
    0x45564157,            // Format 'WAVE'
    'fmt ',                // Subchunk1ID
    16,                    // Subchunk1Size (PCM)
    1,                     // AudioFormat (1 = PCM)
    $channels,             // NumChannels
    $sampleRate,           // SampleRate
    $byteRate,             // ByteRate
    $blockAlign,           // BlockAlign
    $bitsPerSample,        // BitsPerSample
    'data',                // Subchunk2ID
    $dataSize              // Subchunk2Size
);

// 输出为实际文件
file_put_contents('output.wav', $header);
?>

该脚本会创建一个 output.wav 文件头,你可以随后附加实际的音频数据来生成可播放的 WAV 文件。

实例二:构建 BMP 图像的文件头

BMP 文件同样使用固定格式的头部,可以使用 pack() 构造。

<?php
$width = 100;
$height = 100;
$bitsPerPixel = 24;
$rowSize = (int)(($bitsPerPixel * $width + 31) / 32) * 4;
$imageSize = $rowSize * $height;
$fileSize = 54 + $imageSize; // 54 字节的头部 + 图像数据

$header = pack(
    'A2VvvVVVVvvVVVV',
    'BM',             // Signature
    $fileSize,        // File size
    0,                // Reserved1
    0,                // Reserved2
    54,               // Offset to image data
    40,               // Info header size
    $width,           // Width
    $height,          // Height
    1,                // Planes
    $bitsPerPixel,    // Bits per pixel
    0,                // Compression (none)
    $imageSize,       // Image size
    2835,             // X pixels per meter (72 DPI)
    2835,             // Y pixels per meter (72 DPI)
    0,                // Colors used
    0                 // Important colors
);

// 输出头部到文件
file_put_contents('output.bmp', $header);
?>

随后,你可以填充每行像素数据(注意 BMP 的每行需为 4 字节对齐)完成图像文件。

注意事项

  1. 字节序问题:多字节数字要考虑平台端序,使用 VN 来控制(小端或大端)。

  2. 对齐要求:BMP、WAV 等格式对字段对齐和结构顺序有严格要求,使用 pack() 时要确保字段对应准确。

  3. 调试输出:可以用 bin2hex()unpack() 来查看打包后的结果是否符合预期。

  4. 构造复杂文件头:可结合官方格式规范手动解析并转化为 pack() 调用。例如要生成一个 ID3v2 音频头或 PNG 的 IHDR 块,务必查阅相关文档。

结语