这个文件是一种HDR格式。最近玩OpenGL想要做基于图像的光照,但是——我得弄个HDR图片。最终,我选择了Radiance RGBE格式(下面称作rgbe格式)。因为能在这里白嫖到一些。在不想用库的情况下,于是便参考std_image与RGBE的官方解释,编写了这篇文章。
不同于PNG格式那样分块,rgbe格式只包括两个部分。一个很小的文件头,和一段通常很大的文件数据。文件数据是RLE压缩的:
文件头很简单,它是一段ASCII字符串。文件头里面的字符串是一行一行的,可以有空行,以#打头的是注释,可以出现在任何位置,应该被忽略。同时,最开始的几个字符是"#?RADIANCE"。紧接着是XXX=XXX这样的文件信息。我们随便找一个rgbe文件格式,可以看到它的文件头:
#?RADIANCE
# Made with 100% pure HDR Shop
FORMAT=32-bit_rle_rgbe
EXPOSURE= 1.0000000000000
-Y 128 +X 256
其中,各个数据含义如下:
FORMAT | 文件数据格式, 32-bit_rle_rgbe表示RLE编码的数据 |
EXPOSURE | 曝光度,一般是1,不管它了吧~ |
-Y | 指定图像高度 |
+X | 指定图像宽度 |
现在,开始干正事——解析rgbe文件,把它转换为[float32 : R], [float32 : G], [float32 : B]的数据。因为float是4字节的,所以输出结果也是对齐的。不需要有步长处理。这样就可以直接送入OpenGL了。
检查文件头
现在来梳理一下我们的程序——首先,需要一个函数来检查文件头。假定fs是我的文件读取流(下同)的话,数一数,文件头是是一个字符('#', '?', 'R', 'A', 'D', 'I', 'A', 'N', 'C', 'E', '\n'),因此:
bool HDRImg::isRadianceFile(BuffISteam &fs) noexcept
{
bool r;
char tmp[12];
r = fs.Read(tmp, 11); // 尝试读取文件头
tmp[11] = '\0'; // 封闭字符串
if (r == false || strcmp("#?RADIANCE\n