SFML中通过Map数组调用loadFromMemory加载纹理失败求助
核心原因
问题出在map存储的PNG二进制数据不完整或长度传递错误,导致loadFromMemory无法读取到完整的PNG文件内容,从而提示"Corrupt PNG"。
具体场景分析
字符串类型存储导致数据截断
如果你的myMap是std::map<std::string, std::string>类型,PNG二进制数据中必然包含空字符\0。而std::string会将\0视为字符串结束符,在赋值或构造时只会保留第一个\0之前的内容,导致存储到map中的数据是截断后的不完整PNG。
直接用常量balle调用时,你大概率是同时传递了正确的完整数据长度(比如texture.loadFromMemory(balle, balle_size)),所以能正常加载。数据长度未正确传递
SFML的Texture::loadFromMemory有两个关键重载:bool loadFromMemory(const void* data, std::size_t size):需要明确传入数据的字节长度bool loadFromMemory(const std::string& data):默认用data.size()作为长度,但如果字符串包含\0,size()会被错误计算为第一个\0的位置
如果你调用map中的数据时,只传了指针(比如
myMap["balle"].c_str())却没传长度,SFML会无法确定数据的真实长度,要么误判结束位置,要么读取到非法内存,导致加载失败。map初始化时数据复制错误
往map中存储数据时,如果用了错误的复制方式(比如myMap["balle"] = std::string(balle),其中balle是const unsigned char*类型的二进制数据),会因为\0的存在导致数据不完整。
解决方法
方法1:用std::vector<unsigned char>存储二进制数据
改用std::map<std::string, std::vector<unsigned char>>来存储PNG二进制内容,vector可以完整保存所有字节(包括\0):
// 存储时 std::vector<unsigned char> balle_data(balle, balle + balle_size); myMap["balle"] = balle_data; // 加载时 texture.loadFromMemory(myMap["balle"].data(), myMap["balle"].size());
方法2:正确构造std::string存储完整数据
如果坚持用std::string,需要用包含长度的构造函数来确保完整存储:
// 存储时,明确传入数据长度 myMap["balle"] = std::string(reinterpret_cast<const char*>(balle), balle_size); // 加载时,要么直接传string,要么同时传指针和长度 texture.loadFromMemory(myMap["balle"]); // 或者更稳妥的方式 texture.loadFromMemory(myMap["balle"].data(), myMap["balle"].size());
方法3:检查数据长度一致性
在存储和加载前后,分别打印原始balle的长度和map中存储的数据长度,如果两者不一致,说明数据在存储过程中被截断,需要修正存储逻辑。
内容的提问来源于stack exchange,提问作者Christophe Martin

