背景:
上一篇博文DICOM:DICOM万能编辑工具之Sante DICOM Editor介绍了DICOM万能编辑工具,在日常使用过程中发现,“只要Sante DICOM Editor打不开的数据,基本可以判定此DICOM文件格式错误(准确率达99.9999%^_^)”。在感叹Sante DICOM Editor神器牛掰的同时,想了解一下其底层是如何实现的。通过日常使用以及阅读软件帮助手册推断其底层依赖库很可能是dcmtk,就如同本人使用dcmtk、fo-dicom、dcm4che3等诸多DICOM开源库遇到的兼容性问题类似,——dcmtk兼容性最强,fo-dicom次之,dcm4che3最差。
问题:
本篇通过对比dcmtk3.6与dcm4che3.x解析同一特殊dicom文件(包含非标准VR的元素)分析dcmtk、dcm4che以及fo-dicom数据加载的兼容性问题。
特殊的dicom文件内容如下:
28 00 20 01 20 20 02 00 30 F8,具体描述如下:
使用dcmtk与fo-dicom加载数据时都未出现错误,例如dcmtk加载数据时的提示如下:
由此可以看出dcmtk已经顺利识别出了非标准VR的元素(0028,0120),并成功加载。
虽然使用fo-dicom加载数据没有出现错误,但是对于上述非标准VR的元素(0028,0120)后的元素未顺利加载,如下图所示:
而dcm4che3加载过程中直接弹出了错误,如下所示:
问题分析:
出现该问题的原因是dcm4che3和fo-dicom在解析0028,0120元素时,对于20 20的非标准VR无法识别。下文中将通过分析dcm4che3与dcmtk的源码来定位问题的具体位置并给出解决方案(此处暂时只对比分析了dcm4che3.3.8最新版与dmctk3.6的源码,对于fo-dicom的源码分析待后续整理完成后再补充)。
1. dcmtk3.6源码:
使用dcmtk编写本次数据加载测试工程,简单的示例代码如下:
int main()
{
OFLog::configure(OFLogger::TRACE_LOG_LEVEL);
char* ifname = "c:\\1.dcm";
E_FileReadMode readMode = /*ERM_fileOnly*/ERM_autoDetect;
E_TransferSyntax xfer = EXS_Unknown;
Uint32 maxReadLength = DCM_MaxReadLength;
bool loadIntoMemory = true;
DcmFileFormat dfile;
DcmObject *dset = &dfile;
if (readMode == ERM_dataset) dset = dfile.getDataset();
OFCondition cond = dfile.loadFile(ifname, xfer, EGL_noChange, maxReadLength, readMode);
if (cond.bad())
{
return 1;
}
return 0;
}
单步调试,可以知道dcmtk加载dicom文件的流程如下: