C++从字符串加载Magick::Image报错:无对应解码委托
问题详情
ImageMagick版本
7.0.8-62
操作系统及版本
Debian GNU/Linux 8.11
问题描述
某图片通过URL下载后,直接通过文件名加载Magick::Image可正常运行:
Magick::Image image(file_name.c_str()); cout << "magick is " << image.magick() << endl; cout << "baseColumns is " << image.baseColumns() << endl; cout << "baseRows is " << image.baseRows() << endl;
但将文件内容读取到std::string后,通过Magick::Blob转换为Image对象时出现错误:
std::string get_file_contents(const char *filename) { std::FILE *fp = std::fopen(filename, "rb"); if (fp) { std::string contents; std::fseek(fp, 0, SEEK_END); contents.resize(std::ftell(fp)); std::rewind(fp); std::fread(&contents[0], 1, contents.size(), fp); std::fclose(fp); return(contents); } throw(errno); } std::string content = get_file_contents(file_name.c_str()); const size_t len = content.size(); Magick::Blob blob(static_cast<const void *>(content.c_str()), len); Magick::Image image(blob);
错误信息:Magick: NoDecodeDelegateForThisImageFormat '' @ error/blob.c/BlobToImage/458
尝试更换图片后发现,多数图片可正常加载,但部分浏览器能正常打开的图片出现该问题。请问这类图片有何特殊性?如何正确从字符串加载Image?
原因及解决方案
这类图片的特殊性
出现问题的图片通常有以下特点:
- 缺失格式识别的魔术字节:部分图片因损坏、特殊编码或格式变种,没有ImageMagick依赖的头部特征字节。直接读文件时,ImageMagick可以通过文件名后缀推断格式,但Blob模式无文件名信息,只能靠内容识别,因此失败。
- 属于容错性要求高的格式变种:比如小众的WebP/HEIC变种、带冗余元数据的图片,浏览器的格式识别容错性远高于ImageMagick,能忽略异常数据正常解析,但ImageMagick无法自动识别。
- 文件含非图片冗余数据:图片头部/尾部附带了注释、额外元数据,浏览器会自动过滤,但ImageMagick的Blob识别逻辑对这类情况容错性差。
正确从字符串加载Image的方法
方法1:显式指定图片格式
如果知道图片格式,创建Image对象时直接指定格式,跳过自动识别步骤:
// 替换为实际格式,比如"PNG"、"WEBP" Magick::Image image(blob, "JPG");
若不确定格式,可从文件名后缀提取格式后传入:
std::string format = file_name.substr(file_name.find_last_of('.') + 1); std::transform(format.begin(), format.end(), format.begin(), ::toupper); Magick::Image image(blob, format);
方法2:优化二进制内容存储逻辑
std::string虽支持二进制存储,但用std::vector<unsigned char>存储二进制数据更稳妥,避免潜在的字符编码干扰:
std::vector<unsigned char> get_file_contents(const char *filename) { std::FILE *fp = std::fopen(filename, "rb"); if (fp) { std::fseek(fp, 0, SEEK_END); size_t size = std::ftell(fp); std::rewind(fp); std::vector<unsigned char> contents(size); std::fread(contents.data(), 1, size, fp); std::fclose(fp); return contents; } throw(errno); } // 使用vector创建Blob auto content = get_file_contents(file_name.c_str()); Magick::Blob blob(content.data(), content.size()); Magick::Image image(blob);
方法3:先探测格式再读取
用ping方法先探测图片格式信息,再以此格式读取内容:
Magick::Image image; image.ping(blob); // 仅探测图片元数据,不加载完整内容 std::string format = image.magick(); image.read(blob, format); // 用探测到的格式读取完整图片
内容的提问来源于stack exchange,提问作者James Stephen
相关产品推荐
相关产品推荐

