Mercurial > hg > orthanc
comparison Core/DicomParsing/FromDcmtkBridge.cpp @ 3920:82e88ff003d7 c-get
merge default -> c-get
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Tue, 12 May 2020 14:58:24 +0200 |
parents | 210af28c4087 |
children | 74eeadf5d51d |
comparison
equal
deleted
inserted
replaced
3918:dba48c162b7b | 3920:82e88ff003d7 |
---|---|
119 # include <dcmtk/dcmjpls/djencode.h> | 119 # include <dcmtk/dcmjpls/djencode.h> |
120 # endif | 120 # endif |
121 #endif | 121 #endif |
122 | 122 |
123 | 123 |
124 #include <dcmtk/dcmdata/dcrledrg.h> | |
125 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 | |
126 # include <dcmtk/dcmdata/dcrleerg.h> | |
127 # include <dcmtk/dcmimage/diregist.h> // include to support color images | |
128 #endif | |
129 | |
130 | |
124 namespace Orthanc | 131 namespace Orthanc |
125 { | 132 { |
126 static bool IsBinaryTag(const DcmTag& key) | 133 static bool IsBinaryTag(const DcmTag& key) |
127 { | 134 { |
128 return (key.isUnknownVR() || | 135 return (key.isUnknownVR() || |
1196 default: | 1203 default: |
1197 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1204 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1198 } | 1205 } |
1199 } | 1206 } |
1200 | 1207 |
1208 | |
1209 | |
1210 static bool SaveToMemoryBufferInternal(std::string& buffer, | |
1211 DcmFileFormat& dicom, | |
1212 E_TransferSyntax xfer) | |
1213 { | |
1214 E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; | |
1215 | |
1216 // Create a memory buffer with the proper size | |
1217 { | |
1218 const uint32_t estimatedSize = dicom.calcElementLength(xfer, encodingType); // (*) | |
1219 buffer.resize(estimatedSize); | |
1220 } | |
1221 | |
1222 DcmOutputBufferStream ob(&buffer[0], buffer.size()); | |
1223 | |
1224 // Fill the memory buffer with the meta-header and the dataset | |
1225 dicom.transferInit(); | |
1226 OFCondition c = dicom.write(ob, xfer, encodingType, NULL, | |
1227 /*opt_groupLength*/ EGL_recalcGL, | |
1228 /*opt_paddingType*/ EPD_noChange, | |
1229 /*padlen*/ 0, /*subPadlen*/ 0, /*instanceLength*/ 0, | |
1230 EWM_updateMeta /* creates new SOP instance UID on lossy */); | |
1231 dicom.transferEnd(); | |
1232 | |
1233 if (c.good()) | |
1234 { | |
1235 // The DICOM file is successfully written, truncate the target | |
1236 // buffer if its size was overestimated by (*) | |
1237 ob.flush(); | |
1238 | |
1239 size_t effectiveSize = static_cast<size_t>(ob.tell()); | |
1240 if (effectiveSize < buffer.size()) | |
1241 { | |
1242 buffer.resize(effectiveSize); | |
1243 } | |
1244 | |
1245 return true; | |
1246 } | |
1247 else | |
1248 { | |
1249 // Error | |
1250 buffer.clear(); | |
1251 return false; | |
1252 } | |
1253 } | |
1254 | |
1255 | |
1201 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, | 1256 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, |
1202 DcmDataset& dataSet) | 1257 DcmDataset& dataSet) |
1203 { | 1258 { |
1204 // Determine the transfer syntax which shall be used to write the | 1259 // Determine the transfer syntax which shall be used to write the |
1205 // information to the file. We always switch to the Little Endian | 1260 // information to the file. If not possible, switch to the Little |
1206 // syntax, with explicit length. | 1261 // Endian syntax, with explicit length. |
1207 | 1262 |
1208 // http://support.dcmtk.org/docs/dcxfer_8h-source.html | 1263 // http://support.dcmtk.org/docs/dcxfer_8h-source.html |
1209 | 1264 |
1210 | 1265 |
1211 /** | 1266 /** |
1212 * Note that up to Orthanc 0.7.1 (inclusive), the | 1267 * Note that up to Orthanc 0.7.1 (inclusive), the |
1213 * "EXS_LittleEndianExplicit" was always used to save the DICOM | 1268 * "EXS_LittleEndianExplicit" was always used to save the DICOM |
1214 * dataset into memory. We now keep the original transfer syntax | 1269 * dataset into memory. We now keep the original transfer syntax |
1215 * (if available). | 1270 * (if available). |
1216 **/ | 1271 **/ |
1217 E_TransferSyntax xfer = dataSet.getOriginalXfer(); | 1272 E_TransferSyntax xfer = dataSet.getCurrentXfer(); |
1218 if (xfer == EXS_Unknown) | 1273 if (xfer == EXS_Unknown) |
1219 { | 1274 { |
1220 // No information about the original transfer syntax: This is | 1275 // No information about the original transfer syntax: This is |
1221 // most probably a DICOM dataset that was read from memory. | 1276 // most probably a DICOM dataset that was read from memory. |
1222 xfer = EXS_LittleEndianExplicit; | 1277 xfer = EXS_LittleEndianExplicit; |
1223 } | 1278 } |
1224 | |
1225 E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; | |
1226 | 1279 |
1227 // Create the meta-header information | 1280 // Create the meta-header information |
1228 DcmFileFormat ff(&dataSet); | 1281 DcmFileFormat ff(&dataSet); |
1229 ff.validateMetaInfo(xfer); | 1282 ff.validateMetaInfo(xfer); |
1230 ff.removeInvalidGroups(); | 1283 ff.removeInvalidGroups(); |
1231 | 1284 |
1232 // Create a memory buffer with the proper size | 1285 return SaveToMemoryBufferInternal(buffer, ff, xfer); |
1233 { | 1286 } |
1234 const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType); // (*) | 1287 |
1235 buffer.resize(estimatedSize); | 1288 |
1236 } | 1289 bool FromDcmtkBridge::Transcode(DcmFileFormat& dicom, |
1237 | 1290 DicomTransferSyntax syntax, |
1238 DcmOutputBufferStream ob(&buffer[0], buffer.size()); | 1291 const DcmRepresentationParameter* representation) |
1239 | 1292 { |
1240 // Fill the memory buffer with the meta-header and the dataset | 1293 E_TransferSyntax xfer; |
1241 ff.transferInit(); | 1294 if (!LookupDcmtkTransferSyntax(xfer, syntax)) |
1242 OFCondition c = ff.write(ob, xfer, encodingType, NULL, | 1295 { |
1243 /*opt_groupLength*/ EGL_recalcGL, | 1296 throw OrthancException(ErrorCode_InternalError); |
1244 /*opt_paddingType*/ EPD_withoutPadding); | |
1245 ff.transferEnd(); | |
1246 | |
1247 if (c.good()) | |
1248 { | |
1249 // The DICOM file is successfully written, truncate the target | |
1250 // buffer if its size was overestimated by (*) | |
1251 ob.flush(); | |
1252 | |
1253 size_t effectiveSize = static_cast<size_t>(ob.tell()); | |
1254 if (effectiveSize < buffer.size()) | |
1255 { | |
1256 buffer.resize(effectiveSize); | |
1257 } | |
1258 | |
1259 return true; | |
1260 } | 1297 } |
1261 else | 1298 else |
1262 { | 1299 { |
1263 // Error | 1300 DicomTransferSyntax sourceSyntax; |
1264 buffer.clear(); | 1301 bool known = LookupOrthancTransferSyntax(sourceSyntax, dicom); |
1265 return false; | 1302 |
1303 if (!dicom.getDataset()->chooseRepresentation(xfer, representation).good() || | |
1304 !dicom.getDataset()->canWriteXfer(xfer) || | |
1305 !dicom.validateMetaInfo(xfer, EWM_updateMeta).good()) | |
1306 { | |
1307 return false; | |
1308 } | |
1309 else | |
1310 { | |
1311 dicom.removeInvalidGroups(); | |
1312 | |
1313 if (known) | |
1314 { | |
1315 LOG(INFO) << "Transcoded an image from transfer syntax " | |
1316 << GetTransferSyntaxUid(sourceSyntax) << " to " | |
1317 << GetTransferSyntaxUid(syntax); | |
1318 } | |
1319 else | |
1320 { | |
1321 LOG(INFO) << "Transcoded an image from unknown transfer syntax to " | |
1322 << GetTransferSyntaxUid(syntax); | |
1323 } | |
1324 | |
1325 return true; | |
1326 } | |
1266 } | 1327 } |
1267 } | 1328 } |
1268 | 1329 |
1269 | 1330 |
1270 ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag) | 1331 ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag) |
1657 case Json::arrayValue: | 1718 case Json::arrayValue: |
1658 { | 1719 { |
1659 DcmTag key(tag.GetGroup(), tag.GetElement()); | 1720 DcmTag key(tag.GetGroup(), tag.GetElement()); |
1660 if (key.getEVR() != EVR_SQ) | 1721 if (key.getEVR() != EVR_SQ) |
1661 { | 1722 { |
1662 throw OrthancException(ErrorCode_BadParameterType); | 1723 throw OrthancException(ErrorCode_BadParameterType, "Bad Parameter type for tag " + tag.Format()); |
1663 } | 1724 } |
1664 | 1725 |
1665 DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key); | 1726 DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key); |
1666 element.reset(sequence); | 1727 element.reset(sequence); |
1667 | 1728 |
1701 | 1762 |
1702 break; | 1763 break; |
1703 } | 1764 } |
1704 | 1765 |
1705 default: | 1766 default: |
1706 throw OrthancException(ErrorCode_BadParameterType); | 1767 throw OrthancException(ErrorCode_BadParameterType, "Bad Parameter type for tag " + tag.Format()); |
1707 } | 1768 } |
1708 | 1769 |
1709 return element.release(); | 1770 return element.release(); |
1710 } | 1771 } |
1711 | 1772 |
1719 } | 1780 } |
1720 | 1781 |
1721 DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element); | 1782 DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element); |
1722 DcmPixelSequence* pixelSequence = NULL; | 1783 DcmPixelSequence* pixelSequence = NULL; |
1723 if (!pixelData.getEncapsulatedRepresentation | 1784 if (!pixelData.getEncapsulatedRepresentation |
1724 (dataset.getOriginalXfer(), NULL, pixelSequence).good()) | 1785 (dataset.getCurrentXfer(), NULL, pixelSequence).good()) |
1725 { | 1786 { |
1726 return NULL; | 1787 return NULL; |
1727 } | 1788 } |
1728 else | 1789 else |
1729 { | 1790 { |
1972 } | 2033 } |
1973 } | 2034 } |
1974 } | 2035 } |
1975 | 2036 |
1976 | 2037 |
1977 bool FromDcmtkBridge::LookupTransferSyntax(std::string& result, | |
1978 DcmFileFormat& dicom) | |
1979 { | |
1980 const char* value = NULL; | |
1981 | |
1982 if (dicom.getMetaInfo() != NULL && | |
1983 dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() && | |
1984 value != NULL) | |
1985 { | |
1986 result.assign(value); | |
1987 return true; | |
1988 } | |
1989 else | |
1990 { | |
1991 return false; | |
1992 } | |
1993 } | |
1994 | |
1995 | |
1996 #if ORTHANC_ENABLE_LUA == 1 | 2038 #if ORTHANC_ENABLE_LUA == 1 |
1997 void FromDcmtkBridge::ExecuteToDicom(DicomMap& target, | 2039 void FromDcmtkBridge::ExecuteToDicom(DicomMap& target, |
1998 LuaFunctionCall& call) | 2040 LuaFunctionCall& call) |
1999 { | 2041 { |
2000 Json::Value output; | 2042 Json::Value output; |
2071 DJDecoderRegistration::registerCodecs(); | 2113 DJDecoderRegistration::registerCodecs(); |
2072 # if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 | 2114 # if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 |
2073 DJEncoderRegistration::registerCodecs(); | 2115 DJEncoderRegistration::registerCodecs(); |
2074 # endif | 2116 # endif |
2075 #endif | 2117 #endif |
2118 | |
2119 LOG(INFO) << "Registering RLE codecs in DCMTK"; | |
2120 DcmRLEDecoderRegistration::registerCodecs(); | |
2121 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 | |
2122 DcmRLEEncoderRegistration::registerCodecs(); | |
2123 #endif | |
2076 } | 2124 } |
2077 | 2125 |
2078 | 2126 |
2079 void FromDcmtkBridge::FinalizeCodecs() | 2127 void FromDcmtkBridge::FinalizeCodecs() |
2080 { | 2128 { |
2090 // Unregister JPEG codecs | 2138 // Unregister JPEG codecs |
2091 DJDecoderRegistration::cleanup(); | 2139 DJDecoderRegistration::cleanup(); |
2092 # if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 | 2140 # if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 |
2093 DJEncoderRegistration::cleanup(); | 2141 DJEncoderRegistration::cleanup(); |
2094 # endif | 2142 # endif |
2143 #endif | |
2144 | |
2145 DcmRLEDecoderRegistration::cleanup(); | |
2146 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 | |
2147 DcmRLEEncoderRegistration::cleanup(); | |
2095 #endif | 2148 #endif |
2096 } | 2149 } |
2097 | 2150 |
2098 | 2151 |
2099 | 2152 |
2576 std::vector<size_t> parentIndexes; | 2629 std::vector<size_t> parentIndexes; |
2577 bool hasCodeExtensions; | 2630 bool hasCodeExtensions; |
2578 Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); | 2631 Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); |
2579 ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions); | 2632 ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions); |
2580 } | 2633 } |
2634 | |
2635 | |
2636 | |
2637 bool FromDcmtkBridge::LookupOrthancTransferSyntax(DicomTransferSyntax& target, | |
2638 DcmFileFormat& dicom) | |
2639 { | |
2640 if (dicom.getDataset() == NULL) | |
2641 { | |
2642 throw OrthancException(ErrorCode_InternalError); | |
2643 } | |
2644 | |
2645 DcmDataset& dataset = *dicom.getDataset(); | |
2646 | |
2647 E_TransferSyntax xfer = dataset.getCurrentXfer(); | |
2648 if (xfer == EXS_Unknown) | |
2649 { | |
2650 dataset.updateOriginalXfer(); | |
2651 xfer = dataset.getOriginalXfer(); | |
2652 if (xfer == EXS_Unknown) | |
2653 { | |
2654 throw OrthancException(ErrorCode_BadFileFormat, | |
2655 "Cannot determine the transfer syntax of the DICOM instance"); | |
2656 } | |
2657 } | |
2658 | |
2659 return FromDcmtkBridge::LookupOrthancTransferSyntax(target, xfer); | |
2660 } | |
2581 } | 2661 } |
2582 | 2662 |
2583 | 2663 |
2584 #include "./FromDcmtkBridge_TransferSyntaxes.impl.h" | 2664 #include "./FromDcmtkBridge_TransferSyntaxes.impl.h" |